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

huangapple go评论107阅读模式
英文:

How to regenerate private key using EdDSA/Ed448 signature algorithm?

问题

这是我生成密钥对的方式:

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();

然而,当我尝试再次生成密钥时,出现了异常:

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() 抛出异常

异常堆栈跟踪:

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 仓库 复制的一些实用程序:

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;
}
英文:

Here is how I generated the key pair:

var keyPairGenerator = KeyPairGenerator.getInstance(&quot;Ed448&quot;);
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();

However, when I tried to regenerate the keys again, I got an exception:

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

The exception stacktrace:

Exception in thread &quot;main&quot; 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.&lt;init&gt;(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

and here is some utilities I copied from OpenJDK repo:

private static EdECPoint byteArrayToEdPoint(byte[] arr)
{
	byte msb = arr[arr.length - 1];
	boolean xOdd = (msb &amp; 0x80) != 0;
	arr[arr.length - 1] &amp;= (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 &lt; 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;
}

答案1

得分: 4

// 获取私钥的编码(实例将是`EdDSAPrivateKeyImpl`类型),将返回PKCS8格式的密钥,因此您应该使用`PKCS8EncodedKeySpec`:
var keyFactory = KeyFactory.getInstance("EdDSA");
var pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
var privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

// 否则,您将不得不自己解包序列,并按照[RFC5958-section2](https://www.rfc-editor.org/rfc/rfc5958#section-2)中描述的方法获取`PrivateKey`(这是OctetString)。然后您可以使用`EdECPrivateKeySpec`。
英文:

Since privateKey.getEncoded(the instance will be of EdDSAPrivateKeyImpl type) will return a key in PKCS8 format, you should use PKCS8EncodedKeySpec :

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

Otherwise you would have to unwrap the the sequence yourself and get PrivateKey (this is OctetString) as described in RFC5958-section2. Then you could use EdECPrivateKeySpec.

答案2

得分: 1

方法 #1:

var keyPairGenerator = KeyPairGenerator.getInstance("Ed25519");
var keyPair = keyPairGenerator.generateKeyPair();
var privateKey = (EdECPrivateKey) keyPair.getPrivate();
var publicKey = (EdECPublicKey) keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getBytes().orElseThrow();
var edecPoint = publicKey.getPoint();
BigInteger y = edecPoint.getY();
boolean xOdd = edecPoint.isXOdd();

// 使用 (privateKeyBytes)、(y) 和 (xOdd) 重构密钥

var keyFactory = KeyFactory.getInstance("Ed25519");
var edECPublicKeySpec = new EdECPublicKeySpec(NamedParameterSpec.ED25519, new EdECPoint(xOdd, y));
var publicKey2 = keyFactory.generatePublic(edECPublicKeySpec);
var edECPrivateKeySpec = new EdECPrivateKeySpec(NamedParameterSpec.ED25519, privateKeyBytes);
var privateKey2 = keyFactory.generatePrivate(edECPrivateKeySpec);

方法 #2:

var keyPairGenerator = KeyPairGenerator.getInstance("Ed25519");
var keyPair = keyPairGenerator.generateKeyPair();
var privateKey = keyPair.getPrivate();
var publicKey = keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();

// 使用 (privateKeyBytes) 和 (publicKeyBytes) 重构密钥

var keyFactory = KeyFactory.getInstance("Ed25519");
var publicKey2 = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
var privateKey2 = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
英文:

Method #1:

var keyPairGenerator = KeyPairGenerator.getInstance(&quot;Ed25519&quot;);
var keyPair = keyPairGenerator.generateKeyPair();
var privateKey = (EdECPrivateKey) keyPair.getPrivate();
var publicKey = (EdECPublicKey) keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getBytes().orElseThrow();
var edecPoint = publicKey.getPoint();
BigInteger y = edecPoint.getY();
boolean xOdd = edecPoint.isXOdd();

// reconstruct the keys using (privateKeyBytes), (y) and (xOdd)

var keyFactory = KeyFactory.getInstance(&quot;Ed25519&quot;);
var edECPublicKeySpec = new EdECPublicKeySpec(NamedParameterSpec.ED25519, new EdECPoint(xOdd, y));
var publicKey2 = keyFactory.generatePublic(edECPublicKeySpec);
var edECPrivateKeySpec = new EdECPrivateKeySpec(NamedParameterSpec.ED25519, privateKeyBytes);
var privateKey2 = keyFactory.generatePrivate(edECPrivateKeySpec);

Method #2:

var keyPairGenerator = KeyPairGenerator.getInstance(&quot;Ed25519&quot;);
var keyPair = keyPairGenerator.generateKeyPair();
var privateKey = keyPair.getPrivate();
var publicKey = keyPair.getPublic();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] publicKeyBytes = publicKey.getEncoded();

// reconstruct the keys using (privateKeyBytes) and (publicKeyBytes)

var keyFactory = KeyFactory.getInstance(&quot;Ed25519&quot;);
var publicKey2 = keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
var privateKey2 = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

huangapple
  • 本文由 发表于 2020年9月21日 18:40:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/63990653.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定