开始,我是新的密码学和不同类型的密钥/编码/格式,如果我说错了,请纠正我。我有一个Java应用程序需要将Ed 25519密钥保存到密钥库。该应用程序是遗留的,一些方法和库无法更改。它使用Apache MINA SSHD和BouncyCastle将密钥存储在密钥库中,并将公钥编码为SSH格式。RSA和DSA密钥没有问题。问题是Apache MINA使用了EdDSA密钥的net.i2p实现,而BouncyCastle使用了自己的BCEdDSA密钥。我们使用的一个方法来自MINA,并返回net.i2p密钥,因为我在将其保存到密钥库时遇到了麻烦,因为BouncyCastle的JCAContentSigner无法识别密钥的这种实现。问题出现在对公钥进行编码时。
我创建了一个实现ContentSigner的类,并使用net.i2p的EdDSAEngine类来创建签名器。
private class EdDSAContentSigner implements ContentSigner
{
private final AlgorithmIdentifier sigAlgId;
private final PrivateKey privateKey;
private ByteArrayOutputStream stream;
public EdDSAContentSigner(AlgorithmIdentifier sigAlgId, PrivateKey privKey)
{
this.sigAlgId = sigAlgId;
this.privateKey = privKey;
this.stream = new ByteArrayOutputStream();
}
@Override
public AlgorithmIdentifier getAlgorithmIdentifier()
{
return sigAlgId;
}
@Override
public OutputStream getOutputStream()
{
stream.reset();
return stream;
}
@Override
public byte[] getSignature()
{
byte[] dataToSign = stream.toByteArray();
try
{
EdDSAEngine sig = new EdDSAEngine();
sig.initSign(privateKey);
return sig.signOneShot(dataToSign);
}
catch (GeneralSecurityException e)
{
LOG.error("Cannot sign data : " + e.getMessage(), e);
throw new IllegalStateException("Cannot sign data : " + e.getMessage(), e);
}
}
}
字符串
然后我设法创建了一个证书并将密钥保存到密钥库。该应用程序具有上传私钥文件的功能,它以SSH格式生成公钥-从ssh-ed 25519开始。
现在我有一个问题,将公钥编码为SSH格式。即使我使用相同的私钥文件,它总是与ssh-keygen工具生成的公钥不同。同样,公钥可以是不同的类型net.i2p/BouncyCastle/sun.security.ec.ed. EdDSA PublicKeyImpl,这取决于什么方法调用我的encodeEdDSA PublicKey方法。我尝试了不同的方法来编码它,从调用.getEncoded()方法对PublicKey本身使用BouncyCastle的ASN 1 InputStream这是我最新的方法.我还将提供RSA密钥编码方法女巫返回相同的编码作为ssh-keygen工具.我希望能够使用公共密钥连接到一个服务器使用腻子.任何帮助/建议将不胜感激.
private static String encodeEdDSAPublicKey(PublicKey publicKey)
throws IOException
{
try(ASN1InputStream asn1InputStream = new ASN1InputStream(publicKey.getEncoded()))
{
ASN1Primitive primitive = asn1InputStream.readObject();
byte[] keyBytes ((ASN1Sequence)primitive).getObjectAt(1).toASN1Primitive().getEncoded();
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(byteOs);
dos.writeInt("ssh-ed25519".getBytes().length);
dos.write("ssh-ed25519".getBytes());
dos.writeInt(keyBytes.length);
dos.write(keyBytes);
return Base64.getEncoder().encodeToString(byteOs.toByteArray());
}
}
private static String encodeRSAPublicKey(PublicKey publicKey)
throws IOException
{
String publicKeyEncoded;
RSAPublicKey rsaPublicKey = (RSAPublicKey)publicKey;
ByteArrayOutputStream byteOs = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(byteOs);
dos.writeInt("ssh-rsa".getBytes().length);
dos.write("ssh-rsa".getBytes());
dos.writeInt(rsaPublicKey.getPublicExponent().toByteArray().length);
dos.write(rsaPublicKey.getPublicExponent().toByteArray());
dos.writeInt(rsaPublicKey.getModulus().toByteArray().length);
dos.write(rsaPublicKey.getModulus().toByteArray());
publicKeyEncoded = Base64.getEncoder().encodeToString(byteOs.toByteArray());
return publicKeyEncoded;
}
这是我根据算法选择正确编码方法的方法
public static String encodePublicKey(PublicKey publicKey, String name)
throws IOException
{
String suffix = "";
String algorithm = publicKey.getAlgorithm();
if (name != null)
{
suffix = name);
}
switch (algorithm)
{
case "RSA":
return "ssh-rsa " + encodeRSAPublicKey(publicKey) + suffix;
case "DSA":
return "ssh-dss " + encodeDSAPublicKey(publicKey) + suffix;
case "Ed25519":
case "EdDSA":
return "ssh-ed25519 " + encodeEdDSAPublicKey(publicKey) + suffix;
default:
throw new IOException("Unknown public key encoding: " + publicKey.getAlgorithm());
}
}
型
1条答案
按热度按时间xtfmy6hx1#
你非常接近了。Java
PublicKey.getEncoded()
是一个SPKI structure,它的字段1是一个BIT STRING *,包含 * 算法特定的数据,对于EdDSA来说,它是原始点编码。用途:字符串
或者使用特定于类型的Bouncy类来处理解析和类型转换:
型
或者,如果使用Bouncy提供程序(和密钥类),则更简单地使用用途:
型
在任何情况下,将
point
的长度和内容写入SSH格式。