在以太坊乃至整个加密货币世界中,私钥的安全性是资产安全的基石,用户通常不会直接与一长串无意义的十六进制私钥打交道,而是通过一个名为 Keystore 的文件来间接管理和保护它,这个文件通常以 UTC--<timestamp>_<address> 的命名方式出现,并常常伴随着一个密码,Keystore 的核心思想是:用用户自己设置的密码,对私钥进行加密,从而将私钥从“明文”转换为“密文”存储,即使文件泄露,没有密码也无法恢复出私钥。

本文将深入以太坊官方客户端 go-ethereum (geth) 的源码,剖析 Keystore 的实现原理,带你了解一个 Keystore 文件是如何被创建、解析以及其背后所依赖的加密学技术。

Keystore 文件是什么?

我们来看一个典型的 Keystore 文件内容(为了可读性,已格式化):

{
  "address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
  "crypto": {
    "cipher": "aes-128-ctr",
    "ciphertext": "a1f8a7d4...",
    "cipherparams": {
      "iv": "6087dab2ef5d8fb1a6e8..."
    },
    "kdf": "scrypt",
    "kdfparams": {
      "dklen": 32,
      "n": 262144,
      "p": 1,
      "r": 8,
      "salt": "badae9f3e6..."
    },
    "mac": "7c1a9e1b..."
  },
  "id": "b8c8e5f0-3a2b-4e1d-9c6f-2a3b5c6d7e8f",
  "version": 3
}

从结构上可以看出,一个 Keystore 文件主要包含以下几个部分:

  1. address: 账户的以太坊地址,由私钥派生而来,这是公开信息。
  2. crypto: 加密相关的核心信息,包含了加密私钥所需的所有元数据。
    • cipher: 使用的对称加密算法,这里是 aes-128-ctr
    • ciphertext: 被加密后的私钥密文。
    • cipherparams: 对称加密算法的参数,主要是初始化向量 iv
    • kdf: 密钥派生函数,这里是 scrypt,用于从用户密码中派生出加密密钥。
    • kdfparams: KDF 的参数,如计算成本 n、并行度 p、内存成本 r 和盐值 salt,这些参数是抵抗暴力破解的关键。
    • mac: 消息认证码,用于验证解密过程是否成功,防止篡改。
  3. id: 一个随机生成的 UUID,用于唯一标识该 Keystore 文件。
  4. version: Keystore 的版本号,当前主流的是 3

理解了这个结构,我们就可以顺理成章地进入源码,看看这些字段是如何被生成的。

源码分析:Keystore 的创建与导出

go-ethereum 中,Keystore 的核心逻辑位于 accounts/keystore 包中,我们以导出 Keystore 为例,追踪其流程。

入口函数通常是 keystore.go 中的 Export 方法,但更核心的创建逻辑在 keystore.goencryptKey 函数中。

步骤 1:密码到加密密钥的派生

用户输入的密码本身并不直接用于加密私钥,直接使用密码作为密钥是不安全的,因为密码的熵通常较低,Keystore 使用一个密钥派生函数来“拉伸”密码,生成一个高强度的、长度合适的加密密钥。

随机配图