Jan*_*tze 6 java ssh bouncycastle public-key
使用命令行连接到"新"SSH服务器时,将显示指纹:
无法建立主机'test.com(0.0.0.0)'的真实性.
ECDSA密钥指纹为SHA256:566gJgmcB43EXimrT0exEffxSd3xc7RBS6EPx1XZwYc.
您确定要继续连接(是/否)吗?
我知道指纹是公钥的SHA256哈希的Base64字符串.
我知道如何使用以下方法生成此指纹RSAPublicKey:
RSAPublicKey publicKey = ...;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeInt("ssh-rsa".getBytes().length);
dataOutputStream.write("ssh-rsa".getBytes());
dataOutputStream.writeInt(publicKey.getPublicExponent().toByteArray().length);
dataOutputStream.write(publicKey.getPublicExponent().toByteArray());
dataOutputStream.writeInt(publicKey.getModulus().toByteArray().length);
dataOutputStream.write(publicKey.getModulus().toByteArray());
MessageDigest digest = MessageDigest.getInstance("SHA256");
byte[] result = digest.digest(byteArrayOutputStream.toByteArray());
String fingerprint = Base64.getEncoder().encodeToString(result);
Run Code Online (Sandbox Code Playgroud)
但我怎么能这样做BCECPublicKey呢?
更新
我发现它BCECPublicKey根本不相似RSAPublicKey.我从来不知道SSH服务器公钥是ECDSA,客户端公钥是RSA.
字节结构的方式也是不同的.RSA公钥以头(ssh-rsa)开头.标头长度可以从前4个字节(readInt())中读取.但是,当我使用ECDSA执行此操作时,长度是表示标题的长度...
除了回答
要复制粘贴的东西:
BCECPublicKey publicKey = ...;
byte[] point = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(publicKey.getEncoded())).getPublicKeyData().getOctets();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeInt("ecdsa-sha2-nistp256".getBytes().length);
dataOutputStream.write("ecdsa-sha2-nistp256".getBytes());
dataOutputStream.writeInt("nistp256".getBytes().length);
dataOutputStream.write("nistp256".getBytes());
dataOutputStream.writeInt(point.length);
dataOutputStream.write(point);
MessageDigest digest = MessageDigest.getInstance("SHA256");
byte[] result = digest.digest(byteArrayOutputStream.toByteArray());
String fingerprint = Base64.getEncoder().encodeToString(result);
Run Code Online (Sandbox Code Playgroud)
OpenSSH 公钥格式(以及它所基于的 SSH 有线格式)确实以类型开头,但对于 ECDSA,类型包括曲线 id。例如,我的一个测试系统有一个 ecdsa/p256 密钥,如下所示:
$ awk '{print $2}' <id_ecdsa.pub |openssl base64 -d -A |xxd
0000000: 0000 0013 6563 6473 612d 7368 6132 2d6e ....ecdsa-sha2-n
0000010: 6973 7470 3235 3600 0000 086e 6973 7470 istp256....nistp
0000020: 3235 3600 0000 4104 8141 9c28 53e7 532e 256...A..A.(S.S.
0000030: 8c4b 9781 c6a5 1820 f41a bc95 4e62 13a9 .K..... ....Nb..
0000040: 8356 a517 be55 6ebc fbf4 de74 e216 8f17 .V...Un....t....
0000050: 6222 011c 5920 a3fc caed c880 4298 46d5 b"..Y ......B.F.
0000060: dd39 396e d72d 1e40 .99n.-.@
Run Code Online (Sandbox Code Playgroud)
包括:
4 个字节 00000013 bigendian int = 19:类型长度
19 个字节 'ecdsa-sha2-nistp256' 类型
4 个字节 00000008 bigendian int = 8:curveid 长度
8 个字节 'nistp256' curveid (冗余,但这是有线格式)
4 字节 00000041 bigendian int = 65: pub 点的长度
65 个字节开始 04: X9.62 格式的 pub 点,在 SEC1 中复制更方便,即 1 个字节 04=未压缩,N 个字节 X 坐标,N 个字节 Y-坐标,其中 N 是将曲线的基础字段表示为无符号所需的(固定)大小。
这些主要在rfc5656 第 3.1 节中定义,而 curveid 在 6.1 节中定义。RFC 允许压缩点格式,但 OpenSSH 不使用该选项。
BCECPublicKey.getEncoded()(与所有 Java PublicKey 类一样)返回所谓的 X.509(实际上是SubjectPublicKeyInfo,SPKI)编码,对于 EC,它包括X9.62 未压缩格式的公共点,但您需要一些解析来提取它。既然你有 BC,那么使用它是最简单的:
byte[] point = SubjectPublicKeyInfo.getInstance(ASN1Sequence.getInstance(encoded)).getPublicKeyData().getOctets();
Run Code Online (Sandbox Code Playgroud)
或者.getW(),.getQ()将点作为 JCE 或 BC 类获取,从中您可以分别获取(仿射)X 和 Y 坐标BigInteger。ECFieldElement依次产生BigInteger,并且每个都BigInteger可以转换为可变大小的字节数组,然后您必须将其左填充或左截断到正确的大小。
结果是要散列的数据。如果您不知道,只有 OpenSSH 6.8 及以上版本使用 base64(sha256(pubkey)) 作为指纹(默认情况下)。在此之前它是 hex-with-colons(md5(pubkey)),较新的版本可以使用旧的指纹以实现兼容性(请参阅forFingerprintHash中的选项和中的flag )。ssh_configssh-Essh-keygen
需要明确的是,这只是OpenSSH指纹。密钥指纹也用于 PGP 和 X.509/PKIX(SSL/TLS、CMS/SMIME 等)领域,并且它们完全不同。
| 归档时间: |
|
| 查看次数: |
282 次 |
| 最近记录: |