rclone crypt 加密后端深度指南:客户端加密原理、交互式配置与文件格式解析
【免费下载链接】rclone"rsync for cloud storage" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Azure Blob, Azure Files, Yandex Files项目地址: https://gitcode.com/GitHub_Trending/rc/rclone
导读
本文围绕 rclone 的crypt覆盖层(overlay)后端展开,系统讲解它在项目中的定位、客户端加解密工作方式、从rclone config交互式建连到标准/高级参数的全部配置项,并结合仓库源码剖析数据文件、文件名与密钥派生的底层格式。读完本文,你将能够为任意存储后端(S3、Google Drive、本地磁盘等)叠加一层透明加密,理解.bin后缀、base32文件名与 64 KiB 分块等细节,并掌握改密、备份与完整性校验的正确姿势。
Crypt 是什么:包装在其它后端之上的加密层
crypt类型的 remote 本身不直接访问任何存储系统,而是包装(wrap)另一个 remote,由后者去真正读写云端数据。这与项目中的 alias、union、chunker 等覆盖层后端的定位一致,见 backend/crypt/crypt.go 中fs.Register(&fs.RegInfo{ Name: "crypt", Description: "Encrypt/Decrypt a remote", ... })的注册逻辑。由于是"层层包装",你可以把加密层加在任何后端之上,甚至叠加多层,且 rclone 的全部既有能力(拷贝、同步、mount 挂载等)都能照常作用于 crypt remote。
通过 crypt remote 访问存储系统实现的是客户端加密(client-side encryption):
- 上传前,rclone 在本地系统上自动加密;
- 下载后,rclone 在本地系统上自动解密;
- 数据在底层 remote 中始终以密文形式静止存储(encrypted at rest)。
因此,把数据放在你并不完全信任的位置也是安全的。反向理解很重要:若绕过 crypt 层——例如直接用其它应用访问存储系统,或用 rclone 直接访问被包装的底层 remote——则不会发生任何加解密:读出来的内容就是打乱后的密文,写进去的内容也不会被加密。这也是为什么官方建议为加密内容专门划分一个目录并只通过 crypt remote 访问它。
从源码调用链看,rclone 在上传/下载路径上分别挂接"加密流"与"解密流":数据加密用 NaCl SecretBox(见下文"文件加密"),文件名加解密由Cipher.encryptFileName/decryptFileName(backend/crypt/cipher.go 附近)逐段处理,从而对上层表现为一个普通 remote。
加密算法与技术组成
crypt 采用对称密钥加密(secret-key / symmetric encryption):用一个密码口令(password / pass phrase)派生真正的加密密钥。密码可由用户输入,也可让rclone config随机生成,并以轻度混淆形式保存在配置文件里。若你的运行环境无法保证配置文件安全,应当叠加**配置文件加密(configuration encryption)**防护。
几个密码学关键点(均有源码佐证):
- Salt(盐):加密使用密码学 salt 搅乱密钥,使同一明文可产生不同密文。配置 crypt remote 时可选输入 salt,或让 rclone 生成唯一 salt;省略时 rclone 使用内置固定字符串。源码中的内置 salt 定义在 backend/crypt/cipher.go:
defaultSalt = []byte{0xA8, 0x0D, 0xF4, ...}(16 字节)。与常规密码学做法不同,rclone不在 remote 上存储任何附加信息,因此自定义 salt 实际上相当于"必须记住的第二个密码"。 - 文件内容加密:使用 NaCl SecretBox)。
- 文件名加密:默认开启,但鉴于其副作用(名称长度受限等)可关闭。
Rclone 不加密的内容(明文保留):
- 文件长度(可精确到 16 字节范围内推算);
- 修改时间(用于同步判定)。
交互式配置:创建secretremote
先照常为底层存储配置 remote 并确认可用。本例底层 remote 名为remote,加密内容放在其path子路径下——remote:path内部的一切都会被加密,外部不受影响。下面用rclone config创建一个名为secret的 crypt remote(完整对话实录):
No remotes found, make a new one? n) New remote s) Set configuration password q) Quit config n/s/q> n name> secret Type of storage to configure. Enter a string value. Press Enter for the default (""). Choose a number from below, or type in your own value [snip] XX / Encrypt/Decrypt a remote \ "crypt" [snip] Storage> crypt ** See help for crypt backend at: https://rclone.org/crypt/ ** Remote to encrypt/decrypt. Normally should contain a ':' and a path, eg "myremote:path/to/dir", "myremote:bucket" or maybe "myremote:" (not recommended). Enter a string value. Press Enter for the default (""). remote> remote:path How to encrypt the filenames. Enter a string value. Press Enter for the default ("standard"). Choose a number from below, or type in your own value. / Encrypt the filenames. 1 | See the docs for the details. \ "standard" 2 / Very simple filename obfuscation. \ "obfuscate" / Don't encrypt the file names. 3 | Adds a ".bin" extension only. \ "off" filename_encryption> Option to either encrypt directory names or leave them intact. NB If filename_encryption is "off" then this option will do nothing. Enter a boolean value (true or false). Press Enter for the default ("true"). Choose a number from below, or type in your own value 1 / Encrypt directory names. \ "true" 2 / Don't encrypt directory names, leave them intact. \ "false" directory_name_encryption> Password or pass phrase for encryption. y) Yes type in my own password g) Generate random password y/g> y Enter the password: password: Confirm the password: password: Password or pass phrase for salt. Optional but recommended. Should be different to the previous password. y) Yes type in my own password g) Generate random password n) No leave this optional password blank (default) y/g/n> g Password strength in bits. 64 is just about memorable 128 is secure 1024 is the maximum Bits> 128 Your password is: JAsJvRcgR-_veXNfy_sGmQ Use this password? Please note that an obscured version of this password (and not the password itself) will be stored under your configuration file, so keep this generated password in a safe place. y) Yes (default) n) No y/n> Edit advanced config? (y/n) y) Yes n) No (default) y/n> Remote config -------------------- [secret] type = crypt remote = remote:path password = *** ENCRYPTED *** password2 = *** ENCRYPTED *** -------------------- y) Yes this is OK (default) e) Edit this remote d) Delete this remote y/e/d>配置完成后,secret的使用方式与任何其它 remote 无异,例如rclone copy D:\docs secret:\docs——rclone 会在传输过程中按需自动加解密。若直接访问底层remote:path则会绕过加密。
关于密码存储:obscured ≠ 安全
写入rclone.conf的 crypt 密码只是轻度混淆(lightly obscured),仅能防住不经意的窥视;除非对rclone.conf启用配置文件加密,否则不能视为安全。混淆实现为使用静态密钥的 AES-CTR:IV(nonce)原样存放在混淆结果开头,且该静态密钥在所有 rclone 版本间共享(这也解释了为何换机器以相同口令重建后兼容但混淆串不同——salt 不同所致)。建议使用长口令,或交由rclone config生成随机口令。
指定 remote 的灵活性
配置待加密 remote 时,可以填写任何 rclone 能作为源/目标的字符串:
- 主要用法:指向已配置 remote 内的路径,例如
remote:path/to/dir、remote:bucket,让远端不可信位置的数据以密文存放; - 纯本地加密:也可指向本地文件系统路径(Linux 如
/path/to/dir,Windows 如C:\path\to\dir),从而把 rclone 用作纯本地文件加密工具,例如在可移动 U 盘上保存加密文件; - 注意:不含
:的字符串会被当作本地文件系统的相对路径(如remote会被当作当前目录下名为 remote 的子目录); - 指定路径可以不存在,rclone 会在需要时自动创建。
若同时用包装后的 remote 存放明文、又经 crypt 存放密文,务必让 crypt 指向其中的独立子目录。对于基于 bucket 的存储(Swift、S3、Google Cloud Storage、B2 等),建议将 crypt 包装在具体 bucket上(如s3:bucket);若包装整个根(如s3:)并开启文件名加密,rclone 会连 bucket 名一起加密。
若指定remote:path/to/dir,则加密文件存放在远端path/to/dir下;启用文件名加密时,写入secret:subdir/subfile的文件实际落在未加密路径path/to/dir下,而subdir/subpath这段会被加密。
更换密码(Changing password)
由于密钥由客户端持有的口令直接派生,无法对已加密内容单独改密——直接修改已有 crypt remote 的密码,会让你再也无法解密旧内容。唯一办法是用新密码整体重传。根据数据量、带宽与配额,可选两条路线:
- 从本地等替代位置重传:删除全部旧密文 → 修改密码(或删除并重建 crypt 配置)→ 从替代位置重新上传全部数据;
- 存储端就地迁移:在同一个后端上新建指向独立目录的新 crypt remote(新密码),用 rclone 将数据从旧 crypt remote 拷到新 remote——旧密码解密、新密码加密全程在本地流式完成;完成后删除旧目录与旧配置。注意该过程数据需从存储系统下载再上传,流量翻倍,若存储有上下行配额会双重计费。
安全提醒:rclone 随机密码生成器曾在 1.49.0(2019-08-26 发布)至 1.53.2(2020-10-26 发布)之间生成的密码被认为不安全(该缺陷于 1.53.3,即 2020-11-19 发布版本修复),受影响用户应更换密码;自行拟定密码、或使用早于 1.49.0 / 晚于 1.53.2 的版本生成密码则不受影响。
实战示例:standard 文件名加密的目录树
假设本地存在如下明文结构,文件名加密模式为standard:
plaintext/ ├── file0.txt ├── file1.txt └── subdir ├── file2.txt ├── file3.txt └── subsubdir └── file4.txt上传并在 crypt remote 中查看(明文视图与大小):
$ rclone -q copy plaintext secret: $ rclone -q ls secret: 7 file1.txt 6 file0.txt 8 subdir/file2.txt 10 subdir/subsubdir/file4.txt 9 subdir/file3.txt直接查看底层remote:path,看到的是无规律的密文名字,文件大小略大于明文(头部 + 分块开销):
$ rclone -q ls remote:path 55 hagjclgavj2mbiqm6u6cnjjqcg 54 v05749mltvv1tf4onltun46gls 57 86vhrsv86mpbtd3a0akjuqslj8/dlj7fkq4kdq72emafg7a7s41uo 58 86vhrsv86mpbtd3a0akjuqslj8/7uu829995du6o42n32otfhjqp4/b9pausrfansjth5ob3jkdqd4lc 56 86vhrsv86mpbtd3a0akjuqslj8/8njh1sk437gttmep3p70g81aps目录结构得到保留(加密目录只是换了名字):
$ rclone -q ls secret:subdir 8 file2.txt 9 file3.txt 10 subsubdir/file4.txt若关闭文件名加密(off模式),底层名称只追加.bin后缀,防止云服务商尝试解析文件内容:
$ rclone -q ls remote:path 54 file0.txt.bin 57 subdir/file3.txt.bin 56 subdir/file2.txt.bin 58 subdir/subsubdir/file4.txt.bin 55 file1.txt.bin文件名加密模式(Filename encryption modes)
crypt 支持三种filename_encryption取值,源码中对应 backend/crypt/cipher.go 的NameEncryptionOff / NameEncryptionStandard / NameEncryptionObfuscated枚举:
Off(关闭)
- 不隐藏文件名与目录结构;
- 支持更长文件名(约 246 字符);
- 可使用子路径、拷贝单文件。
Standard(标准)
- 文件名被加密;
- 文件名长度受限(约 143 字符);
- 可使用子路径、拷贝单文件;
- 目录结构可见;
- 相同文件名加密后名称相同(确定性加密,这是云端按名寻址的必要条件);
- 可通过 shortcut 缩短目录递归。
Obfuscate(混淆)这是对文件名的简单"旋转(rotate)",每个文件依据自身内容计算旋转距离并把距离数字存在文件名开头,例如hello可能变成53.jgnnq。源码实现见obfuscateSegment/deobfuscateSegment(backend/crypt/cipher.go):先累加明文字符码元再对 256 取模得到基础偏移,并对数字、字母、Latin-1 补充区、普通 Unicode 各自分桶旋转,无效 UTF-8 序列则加!前缀原样保留。注意:
- 混淆不是强加密,只是阻碍自动化扫描工具识别文件名规律,强度介于
off与standard之间; - 允许更长的路径段名;
- 某些基于 Unicode 的文件名可能混淆较弱,甚至把小写字母映射成大写等价形式;
- 不可依赖混淆做强保护;
- 相同文件名的上传名相同;目录结构可见;可用子路径与单文件拷贝。
云存储对文件名长度与总路径长度均有上限,standard模式更容易触限;文件名 ≤ 143 字符时通常各类云存储都不会出问题。为缓解该问题,实验性高级选项filename_encoding可用于缩短加密名:对大小写敏感的存储(如 Google Drive)可用base64;对内部以 UTF-16 存文件名的存储(如 OneDrive、Dropbox、Box)可用base32768大幅缩短名称(见后文高级参数表)。
目录名加密(Directory name encryption)
可独立控制是否加密目录名(directory_name_encryption,布尔):
- True(默认):整条文件路径含目录名全部加密。示例:
1/12/123.txt→p0e52nreeaj0a5ea7s64m4j72s/l42g6771hnv3an9cgc8cr2n1ng/qgm4avr35m5loi1th53ato71v0; - False:只加密文件名、跳过目录名。示例:
1/12/123.txt→1/12/qgm4avr35m5loi1th53ato71v0。
注意:当filename_encryption为off时该选项不生效。从代码看,cipher.go 中encryptFileName会针对每个/分段判断:若关闭目录名加密则仅对最后一个分段(文件本名)加密,目录段原样保留。
修改时间与哈希
- crypt 的修改时间依托底层 remote 存储,是否支持取决于底层实现;
- crypt不保存哈希;数据完整性由极强的加密认证器(Poly1305)保证;
- 完整性校验应使用
rclone cryptcheck(实现见 cmd/cryptcheck/cryptcheck.go),而非对普通后端使用的rclone check(后者无法正确校验 checksum); - 附带工具
rclone cryptdecode(cmd/cryptdecode)用于展示加密文件名的正反向映射,便于人工核对。
标准选项(Standard options)
以下选项与自动生成文档 docs/content/crypt.md 保持一致,其定义源头在 backend/crypt/crypt.go 的fs.RegInfo.Options中。
--crypt-remote
待加密/解密的 remote。通常应包含:与路径,例如"myremote:path/to/dir"、"myremote:bucket",也可以写作"myremote:"(不推荐)。
- Config:
remote| Env Var:RCLONE_CRYPT_REMOTE| Type: string | Required: true
--crypt-filename-encryption
文件名加密方式。
- Config:
filename_encryption| Env Var:RCLONE_CRYPT_FILENAME_ENCRYPTION| Type: string | Default:"standard" - 取值:
"standard"(加密文件名);"obfuscate"(极简文件名混淆);"off"(不加密文件名,仅追加.bin或自定义 suffix 扩展名)。
--crypt-directory-name-encryption
是否加密目录名。若filename_encryption为off,本选项无效。
- Config:
directory_name_encryption| Env Var:RCLONE_CRYPT_DIRECTORY_NAME_ENCRYPTION| Type: bool | Default:true - 取值:
true(加密目录名);false(保留目录名)。
--crypt-password
加密用密码/口令。
- 注意:本参数输入必须为 obscure 后的密文——参见
rclone obscure命令。 - Config:
password| Env Var:RCLONE_CRYPT_PASSWORD| Type: string | Required: true
--crypt-password2
用于 salt 的密码/口令。可选但推荐设置,应区别于主密码。
- 注意:输入同样必须是 obscure 后的密文。
- Config:
password2| Env Var:RCLONE_CRYPT_PASSWORD2| Type: string | Required: false
高级选项(Advanced options)
--crypt-server-side-across-configs
已弃用:请改用--server-side-across-configs。允许跨不同 crypt 配置执行服务端操作(如 copy)。常规情况下用不到它,但若有两个 crypt 指向同一后端则可启用——例如想不重传全部数据而更换文件名加密类型:建两个指向不同目录、仅目标参数不同的 crypt 后端,用rclone move在两者间搬运即可。
- Config:
server_side_across_configs| Env Var:RCLONE_CRYPT_SERVER_SIDE_ACROSS_CONFIGS| Type: bool | Default:false
--crypt-show-mapping
对列出的所有文件展示其名字如何被加密。开启后,每次 remote 被要求列出文件,都会以 INFO 级别记录一条"明文名 ↔ 密文名"的对照日志,便于排查或对密文做定向操作。
- Config:
show_mapping| Env Var:RCLONE_CRYPT_SHOW_MAPPING| Type: bool | Default:false
--crypt-no-data-encryption
选择加密文件数据或保持其不加密。
- Config:
no_data_encryption| Env Var:RCLONE_CRYPT_NO_DATA_ENCRYPTION| Type: bool | Default:false - 取值:
true(不加密文件数据);false(加密文件数据)。
--crypt-pass-bad-blocks
开启后将损坏块以全 0 数据透传。正常操作不应开启,仅在尝试恢复含错误的加密文件、希望尽量抢救内容时使用。
- Config:
pass_bad_blocks| Env Var:RCLONE_CRYPT_PASS_BAD_BLOCKS| Type: bool | Default:false
--crypt-strict-names
开启后,当 crypt 遇到无法解密的文件名时会直接报错(默认只记一条 NOTICE 日志并继续)。该情况通常出现在同一目录混存加密与未加密文件时(不推荐做法),也可能预示更严重的问题需要排查。
- Config:
strict_names| Env Var:RCLONE_CRYPT_STRICT_NAMES| Type: bool | Default:false
--crypt-filename-encoding
如何将加密后的文件名编码为文本串。有助于缩短加密名,具体取舍取决于 remote 如何统计文件名长度及是否大小写敏感。
- Config:
filename_encoding| Env Var:RCLONE_CRYPT_FILENAME_ENCODING| Type: string | Default:"base32" - 取值:
"base32"(适用于所有 remote);"base64"(适用于大小写敏感的 remote);"base32768"(适用于以 UTF-16 或 Unicode codepoint 计长的 remote,如 OneDrive、Dropbox)。
--crypt-suffix
覆盖默认后缀.bin。设为"none"得到空后缀,在路径长度受限时可能有用。
- Config:
suffix| Env Var:RCLONE_CRYPT_SUFFIX| Type: string | Default:".bin"
--crypt-description
remote 的描述信息。
- Config:
description| Env Var:RCLONE_CRYPT_DESCRIPTION| Type: string | Required: false
元数据(Metadata)
底层 remote 支持的任何元数据都会被 crypt 原样读写(见 backend/crypt/crypt.go 注册的MetadataInfo)。
后端命令(Backend commands)
crypt 专属后端命令统一通过rclone backend调用(相关实现注册在 backend/crypt/crypt.go 的CommandHelp中),也可在运行中的后端上通过 rc 接口backend/command调用:
rclone backend COMMAND remote:encode
编码给定的文件名。
rclone backend encode remote: [options] [<arguments>+]将参数中的文件名加密,返回编码结果字符串列表。示例:
rclone backend encode crypt: file1 [file2...] rclone rc backend/command command=encode fs=crypt: file1 [file2...]decode
解码给定的文件名。
rclone backend decode remote: [options] [<arguments>+]将参数中的密文文件名解密并返回结果;任一输入无效都会报错。示例:
rclone backend decode crypt: encryptedfile1 [encryptedfile2...] rclone rc backend/command command=decode fs=crypt: encryptedfile1 [encryptedfile2...]备份加密 remote 的推荐姿势
若要备份加密 remote,建议对密文执行rclone sync,并确保新加密 remote 使用相同口令。这样做的优势:
rclone sync拷贝过程中会校验 checksum;- 可以在两个加密 remote 之间直接
rclone check; - 避免了不必要的解密再加密。
典型拓扑:原始数据在remote:,加密版位于eremote:(其底层路径为remote:crypt)。备份时新建remote2:及加密版eremote2:(底层路径remote2:crypt,口令与eremote:一致)。随后同步并校验:
rclone sync --interactive remote:crypt remote2:crypt rclone check remote:crypt remote2:crypt文件格式详解
文件内容加密(File encryption)
文件按1:1 源文件 → 目标对象方式加密:目标文件含一个头(header),正文被切成若干块(chunk)。相关尺寸常量定义在 backend/crypt/cipher.go。
Header(头,共 32 字节)
- 8 字节魔数串
RCLONE\x00\x00(源码常量fileMagic = "RCLONE\x00\x00"); - 24 字节 Nonce(IV)。
初始 nonce 取自操作系统密码学级随机数生成器,每读一块即递增,保证每块 nonce 唯一;nonce 复用概率极低——即便写入 1 EB(10¹⁸ 字节)数据,nonce 复用概率也仅约 2×10⁻³²。
Chunk(数据块)每块含 64 KiB 数据(最后一块可能更少),采用标准 NaCl SecretBox 格式(XSalsa20 加密 + Poly1305 认证),即:
- 16 字节 Poly1305 认证码(源码
blockHeaderSize = secretbox.Overhead,即 16); - 1 ~ 65536 字节 XSalsa20 加密数据(源码
blockDataSize = 64 * 1024)。
选择 64k 块大小是实测的性能最优解:过小则认证开销占比过高,过大则缓存效应使性能回落;同时块在内存中缓冲,不能设得太大。文件加密使用由用户口令派生的32 字节(256 bit)密钥。
体积测算示例
- 1 字节文件加密后 = 32 字节头 + 17 字节数据块 =49 字节;
- 1 MiB(1048576 字节)文件加密后 = 32 字节头 + 16 个 65552 字节块 =1048864 字节,即大文件仅约 0.03% 开销。
文件名加密(Name encryption)
文件名按路径段逐个加密:先把路径按/切分成多段,再逐段处理。
- 每段先按PKCS#7填充到 16 字节的倍数(源码引用 backend/crypt/pkcs7 包),然后使用EME 模式 AES-256加密。EME(ECB-Mix-ECB)是宽块加密模式,出自 2003 年 Halevi 与 Rogaway 的论文 "A Parallelizable Enciphering Mode"(实现见
github.com/rfjakob/eme,backend/crypt/cipher.go)。 - 这样得到的是确定性加密——同名文件必须加密出相同名称,否则云端无法按名寻址。因此:同名文件名加密结果相同;开头相同的文件名不会共享公共前缀。
- 密钥为 32 字节(256 bit)名称密钥 + 16 字节(128 bit)tweak,两者均由用户口令派生。
加密结果用修改版标准base32(RFC4648)写出。两处修改:
- 全小写(大写文件名不友好);
- 去掉填充字符
=。
选择base32而非更省空间的base64,是为了兼容大小写不敏感的 remote(如 Windows、Box、Dropbox、OneDrive 等)——这正是 backend/crypt/cipher.go 注释中caseInsensitiveBase32Encoding命名的由来。
密钥派生(Key derivation)
rclone 用scrypt从口令派生所需的 32+32+16 =80 字节密钥材料(数据密钥 + 名称密钥 + 名称 tweak),参数为N=16384, r=8, p=1,并可使用用户提供的 salt(password2);未提供时使用内置 salt。源码在Cipher.Key(backend/crypt/cipher.go):
key, err = scrypt.Key([]byte(password), saltBytes, 16384, 8, 1, keySize) copy(c.dataKey[:], key) // 前 32 字节 copy(c.nameKey[:], key[32:]) // 中间 32 字节 copy(c.nameTweak[:], key[64:]) // 最后 16 字节scrypt 的内存密集特性使字典攻击在成本上不现实;要做到对此类攻击的充分防护,始终应设置 salt(password2)。
总结:crypt 的适用边界
crypt 把"强加密 + rclone 全功能"绑定成一层透明覆盖,可在任意后端上获得客户端加密;同时它也是本文自述使用限制最多的模块之一——不加密长度与 mtime、无法对存量密文改密、standard模式显著压缩文件名长度上限、obfuscate 不算强加密。正确搭配:独立的专用加密目录、standard+directory_name_encryption=true(默认)、推荐的 password2 salt、以cryptcheck校验、以密文sync备份,即可在不可信存储上安全、可运维地落地这套方案。相关测试(backend/crypt/cipher_test.go、backend/crypt/crypt_internal_test.go)覆盖了三种文件名模式、目录名开关及各类畸形密文报错路径,可作为进一步研读实现的入口。
【免费下载链接】rclone"rsync for cloud storage" - Google Drive, S3, Dropbox, Backblaze B2, One Drive, Swift, Hubic, Wasabi, Google Cloud Storage, Azure Blob, Azure Files, Yandex Files项目地址: https://gitcode.com/GitHub_Trending/rc/rclone
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考