使用具有Java安全性的openssh公钥(ecdsa-sha2-nistp256)
是否有Java库/示例可以将openssh格式的ecdsa公钥读取到Java中的JCE使用具有Java安全性的openssh公钥(ecdsa-sha2-nistp256),java,openssh,jce,elliptic-curve,ecdsa,Java,Openssh,Jce,Elliptic Curve,Ecdsa,是否有Java库/示例可以将openssh格式的ecdsa公钥读取到Java中的JCEPublicKey?我想用电子商务来解决这个问题 我试图读取的格式是根据授权密钥或Github API(例如):ecdsa-sha2-nistp256 aae2vjzhnhlxnoytibmlzdhanytaaaibmlzdhanytaabbk8hptb72/sfYgNw1WTska2DNOJFx+QhUxuV6OLINSD2ty+6gxcM8yZrvMqWdMePGRb2cGh8L/0bGOk+64IQ/pM
PublicKey
?我想用电子商务来解决这个问题
我试图读取的格式是根据授权密钥或Github API(例如):ecdsa-sha2-nistp256 aae2vjzhnhlxnoytibmlzdhanytaaaibmlzdhanytaabbk8hptb72/sfYgNw1WTska2DNOJFx+QhUxuV6OLINSD2ty+6gxcM8yZrvMqWdMePGRb2cGh8L/0bGOk+64IQ/pM=
我找到了这个答案,这对于RSA和DSS来说很好:
,并讨论了ECDSA的openssh格式:
然而,我在尝试将RSS/DSA代码改编为ECDSA时迷失了方向——我不知道如何设置一个新的应用程序。它需要ECPoint
,EllipticCurve
,ECParameterSpec
,ECField
。openssh格式只包含两个整数,这对于ECPoint
是有意义的,但我不知道如何设置其余的整数
我在很多图书馆闲逛过,包括《古董》和《古董》。最接近我的是:
com.jcraft.jsch.KeyPair load=com.jcraft.jsch.KeyPair.load(jsch,null,bytes[openSshKey])代码>
它可以很好地加载密钥,但不能让我访问JCEPublicKey
——只是一个byte[]getPublicKeyBlob()
方法
我是否遗漏了一些明显的东西?我已经找到了一种使用Bouncycastle实现这一点的方法(但希望找到一种JCE方法)
修改并引用添加到decodePublicKey
的以下块中的代码将解析单个BigInt值Q,即“从椭圆曲线点编码的公钥”:
使用Bouncycastle API,我找到了从Q到ECPublicKey
的解决方案如下(由于提供了起点,请参见):
这将使您从openssh格式的椭圆曲线公钥(ssh-keygen-t ecdsa-b[256 | 384 | 521]
)转换为JCEECPublicKey
,为了完整起见,下面是我使用的代码。它几乎是纯JCE,在助手方法中有少量Bouncycastle(这更新了中的示例代码):
通过使用,我在设置ECPublicKeySpec
方面取得了一些进展。这提供了一个ECKey.Curve.P_256.toECParameterSpec()
调用,该调用对大多数神秘参数进行排序。这就剩下了,所以看起来RSA/DSA的例子更有可能被改编。所以,很有趣。我正在修改RSA/DSA示例,得到值“ecdsa-sha2-nistp256”、“nistp256”,然后只得到一个BigInt(而不是两个)。我想知道这是否是“公共部分”,只是因为它是一个公钥?我想是时候阅读了。我发布了一个新问题,关于是否有JCE方法可以做到这一点:我是否可以说服您在github上共享您的项目?我担心我看似相同的问题会被标记为重复你的问题,并且对密码学的理解有限。谢谢——幸好代码在Github上是可见的,至少现在是这样:我会做一个备份以防万一,随时询问它是否消失了。
if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1)
// The string [identifier] is the identifier of the elliptic curve
// domain parameters. The format of this string is specified in
// Section 6.1 (https://tools.ietf.org/html/rfc5656#section-6.1).
// Information on the REQUIRED and RECOMMENDED sets of
// elliptic curve domain parameters for use with this algorithm can be
// found in Section 10 (https://tools.ietf.org/html/rfc5656#section-10).
String identifier = decodeType();
if (!type.endsWith(identifier)) {
throw new IllegalArgumentException("Invalid identifier " + identifier + " for key type " + type + ".");
}
// Q is the public key encoded from an elliptic curve point into an
// octet string as defined in Section 2.3.3 of [SEC1];
// (https://tools.ietf.org/html/rfc5656#ref-SEC1)
// point compression MAY be used.
BigInteger q = decodeBigInt();
ECPublicKey keyBC = getKeyBC(q, identifier);
return keyBC;
}
ECPublicKey getKeyBC(BigInteger q, String identifier) {
// https://stackoverflow.com/questions/42639620/generate-ecpublickey-from-ecprivatekey
try {
// This only works with the Bouncycastle library:
Security.addProvider(new BouncyCastleProvider());
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", "BC");
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, ecSpec);
ECPublicKey publicKey = (ECPublicKey) keyFactory.generatePublic(pubSpec);
return publicKey;
} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) {
throw new RuntimeException(e);
}
}
...
} else if (type.startsWith("ecdsa-sha2-") &&
(type.endsWith("nistp256") || type.endsWith("nistp384") || type.endsWith("nistp521"))) {
// Based on RFC 5656, section 3.1 (https://tools.ietf.org/html/rfc5656#section-3.1)
String identifier = decodeType();
BigInteger q = decodeBigInt();
ECPoint ecPoint = getECPoint(q, identifier);
ECParameterSpec ecParameterSpec = getECParameterSpec(identifier);
ECPublicKeySpec spec = new ECPublicKeySpec(ecPoint, ecParameterSpec);
return KeyFactory.getInstance("EC").generatePublic(spec);
} ...
/**
* Provides a means to get from a parsed Q value to the X and Y point values.
* that can be used to create and ECPoint compatible with ECPublicKeySpec.
*
* @param q According to RFC 5656:
* "Q is the public key encoded from an elliptic curve point into an octet string"
* @param identifier According to RFC 5656:
* "The string [identifier] is the identifier of the elliptic curve domain parameters."
* @return An ECPoint suitable for creating a JCE ECPublicKeySpec.
*/
ECPoint getECPoint(BigInteger q, String identifier) {
String name = identifier.replace("nist", "sec") + "r1";
ECNamedCurveParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
org.bouncycastle.math.ec.ECPoint point = ecSpec.getCurve().decodePoint(q.toByteArray());
BigInteger x = point.getAffineXCoord().toBigInteger();
BigInteger y = point.getAffineYCoord().toBigInteger();
System.out.println("BC x = " + x);
System.out.println("BC y = " + y);
return new ECPoint(x, y);
}
/**
* Gets the curve parameters for the given key type identifier.
*
* @param identifier According to RFC 5656:
* "The string [identifier] is the identifier of the elliptic curve domain parameters."
* @return An ECParameterSpec suitable for creating a JCE ECPublicKeySpec.
*/
ECParameterSpec getECParameterSpec(String identifier) {
try {
// http://www.bouncycastle.org/wiki/pages/viewpage.action?pageId=362269#SupportedCurves(ECDSAandECGOST)-NIST(aliasesforSECcurves)
String name = identifier.replace("nist", "sec") + "r1";
AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
parameters.init(new ECGenParameterSpec(name));
return parameters.getParameterSpec(ECParameterSpec.class);
} catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
throw new IllegalArgumentException("Unable to get parameter spec for identifier " + identifier, e);
}
}