- 桌面应用
【免费下载链接】CopyQ
Clipboard manager with advanced features
CopyQ 是一款功能强大的剪贴板管理器,会将复制过的内容持久化保存在本地磁盘的标签页中。为了保障这些存储数据的安全,CopyQ 自 14.0.0 版本起内置了基于用户密码的整库加密能力,不再依赖任何外部软件;同时保留了基于 GnuPG 的遗留加密插件,用于按需加密单个条目或兼容旧版本。本文将围绕 docs/password-protection.rst 的完整内容,结合仓库源码(src/common/encryption.cpp、src/gui/encryptionpassword.cpp、plugins/itemencrypted/itemencrypted.cpp)深入讲解两种方案的启用步骤、配置参数、底层密码学原理与实操注意事项,读完即可为你的剪贴板数据加上一道可靠的密码锁。
一、两种加密方案概览
CopyQ 提供两条加密路径,适用场景截然不同:
| 特性 | 内置加密(Built-in Encryption) | 遗留加密插件(Encryption Plugin) |
|---|---|---|
| 引入版本 | 14.0.0 起 | 老版本长期存在,14.0.0 起标记为 deprecated |
| 外部依赖 | 无(依赖 Qt 加密库 QCA 及其 OpenSSL 后端) | 必须安装 GnuPG(gpg2/gpg) |
| 加密范围 | 应用加载的全部标签页,自动覆盖 | 配置中指定的标签页;也可按需加密单个条目 |
| 密码输入频率 | 启动时、修改密码时、定时过期时 | 每隔几分钟需重新输入 |
| 密钥管理 | DEK/KEK 信封加密,支持外部密钥库 | GnuPG 公私钥体系,密钥文件位于配置目录 |
官方建议是:新版本一律使用内置加密;仅在需要"逐条目加密"或运行 CopyQ 14.0.0 之前旧版本时,才考虑遗留插件。
二、内置加密:启用与配置
2.1 启用步骤
打开Preferences(首选项)对话框,勾选Encrypt Tabs选项(对应界面文件 src/ui/configtabgeneral.ui 中的checkBoxEncryptTabs,配置项定义见 src/common/appconfig.h 的encrypt_tabs,默认值为false)。勾选后 CopyQ 会弹出密码设置对话框:
- 输入新密码并二次确认(两次不一致会提示重试,最多尝试 3 次,见 src/gui/encryptionpassword.cpp);
- 密码不允许为空;
- 设置成功后,CopyQ 会对全部现有标签页数据执行一次性加密(
reencryptTabs,调用位置见 src/gui/mainwindow.cpp)。
启用后,所有由应用加载的标签页数据都会被加密——不存在按标签页或按条目逐一勾选的配置,这是与遗留插件最本质的区别。
2.2 何时需要输入密码
根据官方文档与源码,密码在以下场景被要求输入:
- CopyQ 启动时:读取加密标签页数据前,需要解锁;
- 修改加密密码时:必须提供当前密码;
- 定时要求:若在 "History(历史记录)" 配置页中启用Require password after an interval(间隔一段时间后要求输入密码),则到期后应用会周期性请求密码。对应配置项为
expire_encrypted_tab_seconds(取值被钳制在 0~999999 秒,见 src/common/appconfig.h)。
此外,禁用加密(取消勾选 Encrypt Tabs)时同样需要输入密码验证身份(见测试用例 src/tests/tests_encryption.cpp)。
2.3 使用外部密钥库(Use external key store)
为避免每次启动都手动输入密码,可勾选Use external key store(使用外部密钥库)。该选项将密码托管给系统级安全存储,对应配置项use_key_store(默认值为true,见 src/common/appconfig.h)。各平台后端如下:
- Windows— Credential Store(凭据管理器)
- macOS— Keychain(钥匙串)
- Linux— GNOME Keyring 或 KWallet
从源码看,密码通过KeychainAccess::writePassword/readPassword读写,服务名为com.github.hluk.copyq;当 CopyQ 以会话(session)方式运行时,键名还会带上会话后缀(PasswordForSession-<session>),避免多会话互相干扰(见 src/gui/encryptionpassword.cpp)。
需要特别提醒:启用外部密钥库并不会绕过定时密码过期——当 "Require password after an interval" 开启时,周期性提示依然生效。
2.4 内置加密与导出数据的边界
官方文档明确了一个容易踩坑的注意点:
- 内置加密保护的是磁盘上的静态数据(data at rest);
exportTab与exportData脚本命令始终写出未加密文件,不受加密设置影响;- 从 GUI 执行File(文件)— Export(导出)时,CopyQ 会弹出可选导出密码对话框——若填写密码,导出文件中的标签页数据将以该密码加密;不填则明文导出。
详细的备份/导出说明见 docs/backup.rst(其中也强调:GUI 导出可选密码加密,而exportData脚本命令不支持该特性,始终导出未加密数据;若标签页与磁盘目录同步,则文件本身不会被导出)。
三、内置加密的底层原理(源码级)
3.1 DEK/KEK 信封加密架构
内置加密采用标准"信封加密(Envelope Encryption)"设计,核心类为Encryption::EncryptionKey(定义见 src/common/encryption.h):
- DEK(Data Encryption Key):随机生成的 256 位数据加密密钥,真正用于加密全部标签页数据(
generateRandomDEK()); - KEK(Key Encryption Key):由用户密码经PBKDF2派生而来,用于加密(包裹)DEK;
- 磁盘上只保存"被 KEK 包裹后的 DEK"(
wrapped_dek.dat)与 KEK 派生的随机盐(kek_salt.dat),文件路径由configurationFilePath("wrapped_dek.dat")/configurationFilePath("kek_salt.dat")决定(见 src/common/encryption.cpp)。
这套架构带来两个关键收益(源码注释原话):
- 改密码开销极小:修改密码只需用新 KEK 重新包裹 DEK,无需重新加密全部数据(
saveKey()只重写两个小文件,见 src/common/encryption.cpp); - 安全性更高:DEK 是密码学随机密钥,强度远高于任何口令派生密钥;且每个用户拥有独立随机盐。
3.2 具体密码学参数
从 src/common/encryption.cpp 的常量定义可以确认完整算法组合:
- 对称加密:AES-256-CBC,PKCS7 填充(QCA 名称
aes256-cbc-pkcs7); - 密钥派生:PBKDF2-SHA1,迭代次数100,000,输出 32 字节(256 位);
- 每条消息随机盐:16 字节,每条消息通过HKDF-SHA256(RFC 5869)从主密钥派生独立的消息密钥(
derivePerMessageKey); - 完整性校验:对密文负载计算HMAC-SHA256(32 字节标签),解密时用常数时间比较(
constantTimeEquals)验证,可有效防篡改(见 src/common/encryption.cpp); - 文件格式魔数:
CPQ1,用于标识新版格式并拒绝旧版遗留格式(decryptAuthenticated会拒绝不以CPQ1开头的负载)。
3.3 数据落盘的健壮性设计
- 写入采用
QSaveFile原子提交,避免写一半损坏; - Unix 系平台上,密钥文件权限被收紧为仅属主可读写(
ReadOwner | WriteOwner,见 src/common/encryption.cpp); saveKey()在改写前会先备份wrapped_dek.dat/kek_salt.dat(.backup后缀),写完后用新密码反向解包校验 DEK 一致,任何一步失败都会自动回滚备份(见 src/common/encryption.cpp)。
3.4 密码输入途径与测试验证
源码支持多种密码来源(PasswordSource):
- 交互式密码对话框(
QInputDialog,密码模式输入); - 环境变量
COPYQ_PASSWORD(适合自动化/无头场景,见 src/gui/encryptionpassword.cpp); - 系统密钥库(上文所述)。
仓库测试 src/tests/tests_encryption.cpp 与 src/tests/tests_encryption_expire.cpp 覆盖了:启用加密、写入/重载/重启后解密读取、禁用加密时要求密码、密码过期周期等场景。命令行层面可用copyq config encrypt_tabs true/false直接开关该配置(测试代码RUN("config" << "encrypt_tabs" << "true", ...)即此用法)。
四、遗留加密插件(Legacy Encryption Plugin)
自 14.0.0 起该插件已被官方标记为deprecated(已弃用)。仅推荐两类用户使用:需要逐条目加密,或运行 CopyQ14.0.0 之前旧版本。
官方同时给出两条明确警告:
- 插件依赖GnuPG(
gpg2),引入外部密钥管理复杂性与版本兼容问题; - 密码必须每隔几分钟重新输入一次,使用体验较差。
4.1 安装插件与 GnuPG
在Configuration 对话框的 "Items" 配置页中启用Encryptionitem 插件(仓库实现见 plugins/itemencrypted/itemencrypted.cpp,插件 ID 为itemencrypted,名称 "Encryption")。
若系统未安装 GnuPG,插件配置页会提示先安装:
Windows:可用 Chocolatey 安装 Gpg4win:
choco install gpg4winLinux:安装
gpg命令行工具,一般由gnupg软件包提供(个别发行版包名不同)。
从源码看,插件会依次探测gpg2、gpg可执行文件,并要求主版本号 ≥ 2(GpgExecutable构造与findGpgExecutable(),见 plugins/itemencrypted/itemencrypted.cpp);若检测不到 GnuPG,插件状态为GpgNotInstalled,加密标签页将无法加载(loadItems中会提示 "GnuPG must be installed to view encrypted tabs.")。
4.2 生成密钥与设置密码
加密标签页与条目前,必须先生成 GnuPG 公私钥文件。在插件配置页点击"Generate New Keys..."按钮并等待——源码中该操作通过gpg --batch --gen-key生成RSA 4096 位、仅用于加密(Key-Usage: encrypt)的密钥,真实姓名固定为copyq(见startGenerateKeysProcess,plugins/itemencrypted/itemencrypted.cpp),密钥环文件存放在 CopyQ 配置目录下。
密钥生成后,若尚未设置密码,点击"Change Password..."按钮完成设置:
最后一步在插件配置中填入要加密的标签页名列表(每行一个,与标签页名精确匹配;支持&助记键与/路径写法,匹配逻辑见canSaveItems(),plugins/itemencrypted/itemencrypted.cpp)。若只想逐条目加密,可跳过此步。
点击"OK"确认关闭 Configuration 对话框即可生效。
4.3 保护整个标签页
- 按Ctrl+T新建标签页;
- 标签页名称必须与插件配置中填写的名称之一完全一致;
- 该标签页的数据在保存时会经
gpg --encrypt加密(文件头为CopyQ_encrypted_tab v2,见ItemEncryptedSaver::saveItems(),plugins/itemencrypted/itemencrypted.cpp)。
此后打开该标签页会提示输入密码(无需每次都输,间隔一段时间才要求一次)。若输错密码或取消了密码提示,可点击标签页上的"Reload(重新加载)"按钮再次输入密码:
4.4 保护单个条目
在不加密的标签页中,可添加带快捷键的菜单/工具栏动作实现单条目加密:
- 打开Command 对话框(F6);
- 点击"Add(添加)",从列表中选择Encryption类命令,用"OK"确认关闭对话框。
插件向命令系统注册了 4 个内置命令(见commands(),plugins/itemencrypted/itemencrypted.cpp):
| 命令 | 菜单路径 | 快捷键 | 底层脚本 |
|---|---|---|---|
| Encrypt(需要 GnuPG) | Items — Encryption — Encrypt | Ctrl+L | plugins.itemencrypted.encryptItems() |
| Decrypt | Items — Encryption — Decrypt | Ctrl+L | plugins.itemencrypted.decryptItems() |
| Decrypt and Copy | Items — Encryption — Decrypt and Copy | Ctrl+Shift+L | plugins.itemencrypted.copyEncryptedItems() |
| Decrypt and Paste | Items — Encryption — Decrypt and Paste | Enter | plugins.itemencrypted.pasteEncryptedItems() |
加密时,选中条目中所有非 CopyQ 内部格式(不以application/x-copyq-前缀开头)的数据被pack序列化后经 GnuPG 加密,以application/x-copyq-encrypted格式(源码常量mimeEncryptedData)存储;解密时反向unpack还原(见encryptItem/decryptItem/encryptItems/decryptItems,plugins/itemencrypted/itemencrypted.cpp)。加密条目在界面上以挂锁图标标识(ItemEncrypted控件显示IconLock)。
4.5 密钥文件与跨机器共享
插件配置页会提示:若要在其他电脑或会话中共享加密条目,需要保留密钥环文件(存放于 CopyQ 配置目录)。gpg 2.1 以下版本需要同时保存公钥环与私钥环(.pub/.sec);gpg 2.1 及以上仅需公钥环文件。源码通过--export-secret-key导出私钥并以属主可读写权限落盘(见exportGpgKey(),plugins/itemencrypted/itemencrypted.cpp)。请务必妥善保管这些文件。
五、常见问题与最佳实践
- 新旧方案如何选?运行 14.0.0 及以上版本、加密目标是"全部剪贴板历史"时,一律使用内置加密;只有需要"单条目选择性加密"才考虑遗留插件。
- 密码忘记了怎么办?内置加密的密钥文件(
wrapped_dek.dat/kek_salt.dat)被 KEK 包裹,丢失密码即丢失 DEK,加密数据无法恢复——请务必保管好密码,或依赖外部密钥库(use_key_store)。 - 导出的数据默认是明文:脚本
exportTab/exportData永远输出未加密文件;GUI 导出可自愿设置导出密码,请根据数据敏感度自行决定。 - 自动化场景:可通过环境变量
COPYQ_PASSWORD在无人值守环境下提供密码(内置加密),或用命令行copyq config encrypt_tabs true/false管理开关。 - 备份加密数据:直接复制数据/配置目录即可完成备份,但备份与恢复前务必完全退出 CopyQ(见 docs/backup.rst)。
六、参考资源
- 官方文档原文:docs/password-protection.rst
- 备份与导出说明:docs/backup.rst
- 内置加密核心实现:src/common/encryption.cpp、src/common/encryption.h
- 密码提示与密钥库逻辑:src/gui/encryptionpassword.cpp、src/common/keychainaccess.cpp
- 配置项定义:src/common/appconfig.h
- 遗留加密插件:plugins/itemencrypted/itemencrypted.cpp、plugins/itemencrypted/itemencrypted.h
- 加密相关测试:src/tests/tests_encryption.cpp、src/tests/tests_encryption_expire.cpp
- 桌面应用
【免费下载链接】CopyQ
Clipboard manager with advanced features
相关推荐
YOLOv5 2025革新:轻量化突破与全场景落地加速
YOLOv5 2025革新:轻量化突破与全场景落地加速 导语 2025年YOLOv5通过动态损失函数与多尺度特征融合技术实现精度与效率双重突破,在边缘计算与行业
CLI开发工具Ditto数据库和加密功能:保障你的剪贴板数据安全终极指南
Ditto剪贴板管理工具不仅帮你记录所有的复制粘贴历史,更重要的是通过强大的数据库存储和加密机制来保护你的隐私数据。这款Windows剪贴板扩展工具采用SQLi
桌面应用剪贴板数据永不丢失:CopyQ备份与恢复完全指南
剪贴板数据永不丢失:CopyQ备份与恢复完全指南 你是否曾因系统崩溃、软件升级或误操作丢失过重要的剪贴板历史记录?作为程序员、内容创作者或日常办公用户,我们每天
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考