Croc:一行命令背后的端到端加密文件传输
posts posts 2026-07-23T03:00:00+08:00Croc 用 PAKE 协议把跨平台加密传文件收敛成一行命令:P2P 优先、中继回退,v11 又长出了加密暂存、共享终端与浏览器互转。技术笔记端到端加密, CLI工具Croc:一行命令背后的端到端加密文件传输
Croc 解决的是"如何在两台任意电脑之间安全地传文件"这个老问题——不需要公网 IP、不需要端口映射、不需要注册账号、不需要把文件交给第三方服务器,同时保证端到端加密。
在它之前,大多数方案都有明显的短板:scp/sftp 需要双方能直连;WeTransfer 之类的网页工具要把文件上传到中间服务器;局域网传输工具出了内网就用不了。Croc 是 Go 写的命令行工具,作者 schollz,MIT 协议完全开源,2017 年 10 月建库,至今 40,500+ star。设计上明确致谢了 Magic Wormhole——口令认证、中继穿墙这个思路一脉相承,但 Croc 把入口压缩到了一行命令。
系统地图:Croc 的四层技术架构
| 层级 | 职责 | 关键技术 |
|---|---|---|
| 用户层 | 交互与发现 | 一串短助记词构成的 code phrase |
| 加密层 | 密钥协商与加密 | PAKE 协议 + 认证加密 |
| 传输层 | 建立数据通道 | P2P 直连优先,中继回退,浏览器走 WebSocket |
| 协议层 | 传输控制逻辑 | 断点续传、多文件、进度管理 |
这四层设计的要点是:用户只需要记住一串短助记词,就能在底层拿到完整的加密保障——不需要理解密码学,也不需要手动交换密钥。
四层的边界划分是刻意的:加密层负责"安全",传输层只负责"转发"。两层互不耦合,决定了整个系统的信任模型(下文详述)。
为什么 PAKE 是这项技术的核心
Croc 使用 PAKE(Password Authenticated Key Exchange,密码认证密钥交换) 协议,这是它与其他文件传输工具最大的区别。
传统的密钥交换有两种模式:
- 公钥加密:双方需要先知道对方的公钥,但如何安全地交换公钥本身就是个问题
- 对称加密:需要一个共享密钥,但如何在不安全的信道上安全地交换密钥?
PAKE 解决的就是这个问题:双方只需要共享一个短口令,就可以在协议层协商出一个安全的会话密钥,而攻击者即使截获了所有流量,也无法获得这个密钥。
更关键的一点:即使口令强度不高,PAKE 也能让离线暴力破解失效——协议的每一轮猜测都必须与通信对端做一次真实交互,攻击者无法把抓到的报文拿回去离线穷举。“破解口令"从"算得快就行"变成"必须在线上一次次试探”,攻击代价大幅上升。
这就是为什么 Croc 只需要几个助记词就能达到很高的安全性——不是因为口令本身难以猜测,而是协议把暴力破解限制在了在线、逐次进行的量级。Croc 的实现是 schollz 自己的 pake 库(v3),口令协商出的密钥再喂给认证加密层。
核心机制拆解
1. 连接建立:P2P 优先,中继回退
早期版本的 Croc 数据一律过中继;v11 把默认行为改成了先试直连:
- 双方完成 PAKE 握手后,创建绑定本次口令的 Tailcat 节点身份,在一个进程内的 Tailscale 用户态 WireGuard 网络里开 TCP 流
- Magicsock 先走 DERP 中转起步,NAT 穿透成功后自动升级为直连 UDP
- 对端是浏览器、客户端过旧、或 Tailcat 建不起来时,回退到传统的 croc 中继数据端口
--transport 参数可以控制这条路:默认 auto,derp 严格模式下要求 Tailcat 可用并禁用中继回退,relay 强制走 SOCKS5 兼容的中继传输(配合 --socks5 用于只放行代理流量的网络)。传输怎么选,加密都不变——WireGuard 通道和加密消息是两层。
无论走哪条路,两端都不需要知道对方 IP,也不需要配置任何端口映射。
2. 端到端加密流程
一次完整的加密传输流程是这样的:
- 发送方和接收方通过 PAKE 协议协商出共享会话密钥(双方都不需要暴露任何长期密钥)
- 发送方用认证加密算法加密文件内容
- 加密后的数据经直连通道或中继转发
- 接收方用会话密钥解密,并校验完整性与真实性
- 每次传输都重新协商密钥,会话结束即作废
整个过程中,未加密的明文永远不会离开发送方和接收方的机器。还有一个容易被忽略的细节:文件元信息(文件名、大小)也走加密通道。源码里所有协议消息——包括声明文件列表的 fileinfo 消息——都用会话密钥加密编码后才发出去,中继只能看到密文,拿不到文件名。
3. 断点续传与多文件支持
Croc 支持在传输中断后从断点恢复,而不需要从头开始:
- 接收方对已存在的同大小文件计算哈希,与发送方比对,一致就跳过
- 如果接收方已有部分数据,通知发送方从剩余处继续
- 传输进度实时显示在终端上
同时支持一次传输多个文件或整个文件夹。对超大文件而言,断点续传意味着几十 GB 也不会因为一次断网就前功尽弃。默认哈希算法够用,赶时间可以用 croc send --hash imohash 换快速哈希——代价是哈希碰撞概率略高,适合"大致校验"的场景。
4. IPv6 优先与代理支持
Croc 默认 IPv6 优先、IPv4 兜底。同时支持通过 --socks5 走 SOCKS5 代理(例如 Tor),满足更高的匿名性需求——注意代理要两端都设(或用 SOCKS5_PROXY 环境变量),中继域名也由代理解析,本机连 DNS 都可以不配。代理只负责传输路径,文件内容依旧是端到端加密的。
5. 加密暂存:croc store(v11 新增)
双方不方便同时在线时,v11 提供了客户端加密的暂存传输:
croc store file1.zip --downloads 3 --expiration 3d文件以密文上传到存储服务,命令打印一个浏览器链接和一个 CLI token。链接形如 https://host/s/id#v1.decryption-key——解密密钥放在 # 之后,URL fragment 不会进入 HTTP 请求,所以存储服务只拿到不透明的传输 ID,拿不到密钥。下载次数(默认 1 次)和有效期(默认 1 天,支持 m/h/d/w)任一耗尽即失效;发送方可以凭本地保存的回执执行 croc --revoke 随时撤销。
这个模式是可选项,和常规的实时中继传输是两条路。要注意完整链接本身就是秘密:谁拿到链接,谁就能解密文件并消耗下载次数。
6. 共享终端:croc ssh(v11 新增)
v11 还把"传东西"扩展到了"传终端":
croc ssh在 Linux、macOS、FreeBSD、OpenBSD 上,宿主运行这条命令后会拿到两份六词邀请:一份读写、一份只读。参与者用 CROC_SECRET='six-word-invitation' croc ssh 加入(继续避开进程名泄露,后述),所有人看到同一个持久终端,只读参与者的输入会被丢弃。
它不暴露 SSH 守护进程,不需要账号、公网 IP、入站端口或 SSH 密钥:邀请认证一条临时的 Tailcat WireGuard 路径并钉扎临时 SSH 主机密钥;Tailcat 不可用时,回退到普通 croc 中继承载加密流。远程命令执行、端口转发和 SFTP 都被禁用。两份邀请都按秘密对待——邀请上印着角色,谁拿到就能以对应权限加入。
常用命令速查
以下命令均可在发送或接收端灵活组合:
| 场景 | 命令 |
|---|---|
| 发送文件 / 文件夹 | croc send [文件或文件夹] |
| 接收 | croc [code-phrase] |
| 自定义口令(至少 6 字符) | croc send --code [口令] [文件] |
| 一次发多个文件 / 文件夹 | croc send [file1] [file2] [folder] |
| 发送一段文本 | croc send --text "hello" |
| 通过管道收发 | cat file | croc send / croc --yes [code] > out |
| 生成二维码(手机扫码即收) | croc send --qr [文件] |
| 覆盖同名文件 | croc --yes --overwrite [code] |
| 改名保存同名文件 | croc --yes --rename [code] |
| 排除子串匹配的路径 | croc send --exclude "node_modules,.venv" [folder] |
| 精确排除某个相对路径 | croc send --exclude-file "sub/a.log" [folder] |
| 静默模式(脚本用) | croc --quiet send [file] |
| 走 SOCKS5 代理 | croc --socks5 "127.0.0.1:9050" send [file] |
| 换加密曲线 | croc --curve p521 [code] |
| 环境变量传口令(Linux/macOS) | CROC_SECRET=口令 croc |
两个排除参数的区别值得说一句:--exclude 对每个文件的相对路径做大小写不敏感的子串匹配,路径里任何位置含给定字符串就排除;--exclude-file(v11 新增)按相对路径精确匹配,用于"两个不同深度的同名文件只排除其中一个"这类场景。
code phrase:从一个数字加四个词,到三个词
接收凭证 code phrase 本身也经历了一次重构。
v10 时代的自动生成格式是"4 位数字 + 4 个助记词"(mnemonicode 词表),例如 1234-tomato-acrobat-actor-silver 这样的四段式。v11 换成了 EFF 词表(1,296 词)生成的三词 code:第一个词定位中继房间,后两个词充当 PAKE 口令;croc ssh 的邀请则用六个词——两个词选房间、四个词进口令,熵更高。自定义 code 仍然只要求至少 6 个字符,新旧格式都能解析。
三词 code 还承担了一个新职责:公共中继路由。默认公共传输按 code 的 SHA-256 对三中继池取模决定用哪个部署;自动生成的发送端会探测全部三个中继、选第一个应活的;自定义 code 则直接映射、不探测不回退。探测选中的中继地址缓存进本地 best-relay 文件,下次直接复用;连接失败就清掉缓存重新探测。指定 --relay 或 CROC_RELAY、--ip、本地传输都会绕过这套公共路由。
自建中继:把信任握在自己手里
Croc 默认使用公开中继,但既然完全开源,也支持自建:
croc relay- 默认监听 TCP 端口
9009-9013,至少需要 2 个端口 - 用
croc relay --ports 1111,1112自定义端口范围 - 发送方 / 接收方通过
--relay "myrelay.example.com:9009"指定自己的中继 - Docker 一行起服务:
docker run -d -p 9009-9013:9009-9013 -e CROC_PASS='YOURPASSWORD' docker.io/schollz/croc,客户端配--pass对接
自建中继的价值有二:一是内网或隔离网络里无法访问公开中继时自建出口;二是把"转发流量"这一环收进自己手里。需要说明的是,自建中继依然看不到明文——它只是把加密的传输层也从默认服务商那里收回来而已,这正好检验了前面那句"加密层与传输层互不耦合"。
一个典型的文件传输流程
发送方 A 给接收方 B 传一个大文件:
- A 在终端输入
croc send big-file.zip - Croc 生成三词 code,如
briny-gadget-quantum(示意) - A 通过聊天工具把这个 code 发给 B
- B 在终端输入
croc briny-gadget-quantum - A 和 B 通过 PAKE 在本地协商出共享会话密钥(中继全程看不到这个密钥)
- 双方先尝试 Tailcat 直连;穿透失败则回落中继,A 的加密数据开始流动
- B 接收加密数据,在本地解密,实时显示进度
- 如果网络中断,任何一方重新执行命令即可从断点继续
- 传输完成,本次会话密钥作废
全程 A 和 B 都不需要知道对方的 IP 地址,也不需要配置任何网络参数。
安全与隐私约定
这里把 Croc 的安全性质明确为四条"约定",方便你判断它在自己的场景下是否够用:
- 中继无知情权:中继只能看到密文,拿不到文件名、内容和会话密钥;被攻破也不泄露文件。
- 信任锚是口令:code phrase 是唯一的访问凭证。它应通过可信信道(如加密聊天)传递,且不要反复使用同一个口令,避免在线上为攻击者堆积试探机会。
- 进程列表也会泄露秘密:在 Linux / macOS 上,若把 code phrase 直接作为命令行参数传入,它会出现在进程列表中(安全公告 CVE-2023-43621)。官方要求改用环境变量传入(
CROC_SECRET=... croc);单用户系统可以运行croc --classic永久恢复传统行为。croc --extended-clipboard会把带CROC_SECRET=的完整命令复制进剪贴板,省去手敲。 - 直连优先,中继兜底:理想网络下双方建立端到端直连(Tailcat WireGuard,NAT 穿透成功后为直连 UDP),中继只在回退时介入,数据经过中间节点的机会被压到最低。
另外两条来自 v11 新功能的提醒:croc ssh 的两份邀请同 code phrase 一样是秘密;croc store 的完整链接(含 # 后的密钥)也一样——链接发给谁,等于把文件发给谁。
适用边界与采用建议
谁应该优先使用
- 需要跨平台传文件的人:Windows、Linux、Mac 之间互传,再也不用找 U 盘。
- 需要传大文件的人:断点续传意味着几十 GB 的文件也不怕断网。
- 注重隐私的用户:文件不在第三方服务器明文落地,只有发送方和接收方能解密。
- CLI 用户:终端完成所有操作,也方便脚本化。
谁可以暂时不用
- 只在同一局域网内传输:用
--ip直接指定发送方地址(如10.0.0.1:9009)可以建立点对点直连,无需依赖中继。 - 传输极度敏感的数据:PAKE 协议很安全,但极端敏感场景可能还是需要物理介质。
- 完全不会用命令行的用户:现在的选择比以前多了——浏览器版 getcroc.com 已转正为正式能力,与 CLI 完全兼容、可互相收发,
--qr扫码即进接收页;Android 上有 crocgui、croc-app 等 F-Droid 客户端,桌面社区 GUI 也有好几个。不过完整能力仍在命令行。
采用顺序
- 先安装:
brew install croc,或用对应平台的其他包管理器(scoop、choco、MacPorts、Nix、pacman、pkg、conda 等),也可以curl https://getcroc.com | bash直接装。 - 试传一个小文件,体验基本流程。
- 尝试传文件夹和大文件,测试断点续传。
- 正式使用前,最好自建一个中继(
croc relay),把传输链路收进自己手里。 - 需要时配
--socks5走 Tor 等代理提高匿名性。 - 双方无法同时在线的场景,试试
croc store的加密暂存。
顺带一提:CLI 现在自带更新机制——每 24 小时最多一次后台检查新版本,传输结束后提示;croc update(别名 croc upgrade)手动升级,且不会覆盖包管理器安装的二进制。
总结
Croc 把一个复杂的问题——安全跨平台文件传输——封装成了极简的体验:发送方输入命令得到一串助记词,接收方输入这串助记词,文件就开始传了。PAKE 保证口令可以很短,直连优先保证速度,加密元信息和断点续传把细节兜住。
发文时它还只是"一个加密传文件的工具";三个月后 v11 把边界推到了加密暂存(croc store)、共享终端(croc ssh)和浏览器互转。方向没有变:凡是需要两端安全交换的东西,都收敛到同一行命令、同一个口令协议上。
如果你还在为"怎么把这个大文件传给另一台电脑"而烦恼,Croc 值得立即尝试——你唯一需要记住的,就是那串助记词。
参与讨论
使用 GitHub 登录。欢迎补充事实、异议与实践。
讨论暂时无法加载。