java - 如何使用EdDSA/Ed448签名算法重新生成私钥?

标签 java cryptography digital-signature java-15 eddsa

以下是我生成 key 对的方法:

var keyPairGenerator = KeyPairGenerator.getInstance("Ed448");
keyPairGenerator.initialize(448, SecureRandom.getInstanceStrong());
var keyPair = keyPairGenerator.generateKeyPair();
var privateKey = keyPair.getPrivate();
var publicKey = keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();

但是,当我尝试再次重新生成 key 时,出现异常:

var keyFactory = KeyFactory.getInstance("EdDSA");
var edECPoint = byteArrayToEdPoint(publicKeyBytes);
var edECPublicKeySpec = new EdECPublicKeySpec(new NamedParameterSpec("Ed448"), edECPoint);
var publicKey = keyFactory.generatePublic(edECPublicKeySpec);
var edECPrivateKeySpec = new EdECPrivateKeySpec(new NamedParameterSpec("Ed448"), privateKeyBytes);
var privateKey = keyFactory.generatePrivate(edECPrivateKeySpec); // generatePrivate() throws exception

异常堆栈跟踪:

Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: key length is 73, key length must be 57
    at jdk.crypto.ec/sun.security.ec.ed.EdDSAKeyFactory.engineGeneratePrivate(EdDSAKeyFactory.java:129)
    at java.base/java.security.KeyFactory.generatePrivate(KeyFactory.java:390)
    at io.fouad.Main.main(Main.java:48)
Caused by: java.security.InvalidKeyException: key length is 73, key length must be 57
    at jdk.crypto.ec/sun.security.ec.ed.EdDSAPrivateKeyImpl.checkLength(EdDSAPrivateKeyImpl.java:84)
    at jdk.crypto.ec/sun.security.ec.ed.EdDSAPrivateKeyImpl.<init>(EdDSAPrivateKeyImpl.java:61)
    at jdk.crypto.ec/sun.security.ec.ed.EdDSAKeyFactory.generatePrivateImpl(EdDSAKeyFactory.java:171)
    at jdk.crypto.ec/sun.security.ec.ed.EdDSAKeyFactory.engineGeneratePrivate(EdDSAKeyFactory.java:127)
    ... 2 more

这是我从 OpenJDK repo 复制的一些实用程序:

private static EdECPoint byteArrayToEdPoint(byte[] arr)
{
    byte msb = arr[arr.length - 1];
    boolean xOdd = (msb & 0x80) != 0;
    arr[arr.length - 1] &= (byte) 0x7F;
    reverse(arr);
    BigInteger y = new BigInteger(1, arr);
    return new EdECPoint(xOdd, y);
}

private static void reverse(byte [] arr)
{
    int i = 0;
    int j = arr.length - 1;
    
    while(i < j)
    {
        swap(arr, i, j);
        i++;
        j--;
    }
}

private static void swap(byte[] arr, int i, int j)
{
    byte tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
}

最佳答案

由于 privateKey.getEncoded(实例将为 EdDSAPrivateKeyImpl 类型)将返回 PKCS8 格式的 key ,因此您应该使用 PKCS8EncodedKeySpec :

var keyFactory = KeyFactory.getInstance("EdDSA");
var pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
var privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

否则,您必须自己解开序列并获取 PrivateKey(这是 OctetString),如 RFC5958-section2 中所述。 。然后您可以使用 EdECPrivateKeySpec

关于java - 如何使用EdDSA/Ed448签名算法重新生成私钥?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63990653/

相关文章:

java - Spring RequestMapping 404错误

java - 在 Java 中将 List<Object> 转换为 String[]

php - 从客户端到服务器的安全文件传输

c# - 在 C# 中验证用 Java (RSA) 签名的内容时出现问题

c++ - 我们如何在 C++ 和 Windows API 中验证 openssl 数字签名

java - 将相对目录添加到 java 类路径并使用 ClassLoader().getResourceAsStream ("")

java - Java 中查询 Excel 工作表以获取数据子集

erlang - 使用 Erlang 生成 RSA key 对?

c# - RSA.SignHash SHA512 和 SHA256 给出相同的签名长度

c# - 您如何验证数字证书 SSL?