Ed25519 可以使用以下命令通过特定数量的 KDF 轮次生成 SSH 密钥:
ssh-keygen -t ed25519 -a 21
(默认为 16)
给定文件id_ed25519
和id_ed25519.pub
,如何找到这个轮数?
答案1
请注意,这是私人财产密钥文件,不是私钥。它用于从密码短语中派生密钥加密密钥(作为基于密码的密钥导出函数)。您可以在更改密码时更改轮数ssh-keygen -p
。
似乎没有办法找到这个属性ssh-keygen
。ssh-keygen -l -v
仅显示密钥的属性和一些关联的元数据,不包括密钥的加密方式。
私钥文件格式部分记录在PROTOCOL.key
。我的回答是基于此、基于源码阅读和实验观察。
OpenSSH 私钥的本机格式由包裹在两行-----BEGIN OPENSSH PRIVATE KEY-----
和之间的 Base64 编码数据组成-----END OPENSSH PRIVATE KEY-----
。PROTOCOL.key
描述 Base64 编码的二进制数据的内容。二进制数据是以下类型的字段序列:
byte[]
:预先知道长度的字节串。string
:一串字节,其长度在字符串之前编码为 4 字节大端数字。uint32
或int
:一个 4 字节数字编码的大尾数。
二进制数据包含以下字段:
- 文字字符串
openssh-key-v1␀
,其中␀
有空字节 (byte[]
) - 密码名称 (例如
aes256-ctr
) (string
) - PBKDF 名称(自 OpenSSH 8.1 起:
bcrypt
或none
)(string
) - PBKDF 选项 (
string
) - (我们不关心其余的)
PBKDF 选项本身被构造为一系列字段。对于bcrypt
,它们是:
- 盐 (
string
) - 轮数 (
uint32
)
以下是如何直观地检查私钥文件以查找 KDF 信息。
$ <id_ed25519 grep -v '^-' | base64 -d | xxd -g1
00000000: 6f 70 65 6e 73 73 68 2d 6b 65 79 2d 76 31 00 00 openssh-key-v1..
00000010: 00 00 0a 61 65 73 32 35 36 2d 63 74 72 00 00 00 ...aes256-ctr...
00000020: 06 62 63 72 79 70 74 00 00 00 18 00 00 00 10 fe .bcrypt.........
00000030: 57 c1 fe c6 47 cf 63 34 ef 83 35 61 aa f6 31 00 W...G.c4..5a..1.
00000040: 00 00 15 00 00 00 01 00 00 00 33 00 00 00 0b 73 ..........3....s
00000050: 73 68 2d 65 64 32 35 35 31 39 00 00 00 20 7b c8 sh-ed25519... {.
…
从一开始,遵循三个人类可读的字符串 ( openssh-key-v1
、aes256-ctr
、bcrypt
。之后,是一个包含 PBKDF 选项的复合字符串,由 24 个字节组成,前面是00 00 00 18
。这 24 个字节包括:
- 盐长度 (
00 00 00 10
)。 - 盐(由盐长度指示的 16 个字节)。
- 轮数 (
00 00 00 15
) — 即 0x15 = 21。
如果您想以编程方式提取此内容,而不是编写自己的脚本,可以使用一个 Python 库:openssh-key-parser
。
$ pip install -U openssh-key-parser
…
$ python3 -m openssh_key id_ed25519 | jq '.header.kdf'
Key passphrase:
"bcrypt"
$ python3 -m openssh_key id_ed25519 | jq '.kdf_options.data.rounds'
Key passphrase:
21