简体   繁体   中英

Sign/Verify Json using ED25519 keys with Bouncy Castle (Java)

I have generated following keys using ssh-keygen -t ed25519 :

PRIVATE KEY:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1r.....dFUQE=
-----END OPENSSH PRIVATE KEY-----

PUBLIC KEY:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWZbgFOWl97YZJ5Voljoz0f52jRO24jqLLcEhWtalo6 USER@LAPTOP

Iam trying to use the above keys to sign and verify json string, however, verifySignature always returning false.

    byte[] privateKeyBytes = Files.readAllBytes(Paths.get("C:\\workspace\\ssh\\ed25519"));
    Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(privateKeyBytes, 0);

    byte[] publicKeyBytes = Files.readAllBytes(Paths.get("C:\\workspace\\ssh\\ed25519.pub"));
    Ed25519PublicKeyParameters publicKey = new Ed25519PublicKeyParameters(publicKeyBytes, 0);

    byte[] message = "Json String".getBytes("utf-8");

    // create the signature
    Signer signer = new Ed25519Signer();
    signer.init(true, privateKey);
    signer.update(message, 0, message.length);
    byte[] signature = signer.generateSignature();

    // verify the signature
    Signer verifier = new Ed25519Signer();
    verifier.init(false, publicKey);
    verifier.update(message, 0, message.length);
    boolean verified = verifier.verifySignature(signature);

This verified is always false. Any idea...

Trying to follow Rebuild of ED25519 keys with Bouncy Castle (Java)

The private and public Ed25519 keys are each 32 bytes in size. They can be encapsulated in different formats. ssh-keygen generates both Ed25519 keys in OpenSSH format with the statement used. This format cannot be imported directly. However, BouncyCastle provides helper classes for this purpose.

The private key can be loaded with a PemReader and imported into an Ed25519PrivateKeyParameters instance with OpenSSHPrivateKeyUtil.parsePrivateKeyBlob() . OpenSSHPublicKeyUtil.parsePublicKey() allows importing the Base64 decoded body of the public key into an Ed25519PublicKeyParameters instance.

A key pair created with ssh-keygen -t ed25519 looks eg as follows:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDbBP+5jmEtjh1JvhzVQsvvTC2IQrX6P68XzrV7ZbnGsQAAAKBgtw9/YLcP
fwAAAAtzc2gtZWQyNTUxOQAAACDbBP+5jmEtjh1JvhzVQsvvTC2IQrX6P68XzrV7ZbnGsQ
AAAEAaKYn22N1O78HfdG22C7hcG2HiezKMzlq4JTdgYG1DstsE/7mOYS2OHUm+HNVCy+9M
LYhCtfo/rxfOtXtlucaxAAAAHHRmbG9yZXNfZHQwMUB0ZmxvcmVzX2R0MDEtUEMB
-----END OPENSSH PRIVATE KEY-----

and

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINsE/7mOYS2OHUm+HNVCy+9MLYhCtfo/rxfOtXtlucax whatever

Both keys can be imported and used for signing and verification as below:

import java.io.FileReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import org.bouncycastle.crypto.Signer;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.signers.Ed25519Signer;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
import org.bouncycastle.util.io.pem.PemReader;

...

byte[] message = "Json String".getBytes("utf-8");

// Load private key
AsymmetricKeyParameter privateKeyParameters = null;
String pathPrivateKey = "<path to private key>";
try (FileReader fileReader = new FileReader(pathPrivateKey);
     PemReader pemReader = new PemReader(fileReader)) {     
    byte[] privateKeyContent = pemReader.readPemObject().getContent();
    privateKeyParameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(privateKeyContent);
}
    
// Load public key  
String pathPublicKey = "<path to public key>";      
String publicKeyBody = new String(Files.readAllBytes(Paths.get(pathPublicKey)), StandardCharsets.UTF_8).split(" ")[1];
AsymmetricKeyParameter publicKeyParameters = OpenSSHPublicKeyUtil.parsePublicKey(Base64.getDecoder().decode(publicKeyBody));

// Sign
Signer signer = new Ed25519Signer();
signer.init(true, privateKeyParameters);
signer.update(message, 0, message.length);
byte[] signature = signer.generateSignature();

// Verify
Signer verifier = new Ed25519Signer();
verifier.init(false, publicKeyParameters);
verifier.update(message, 0, message.length);
boolean verified = verifier.verifySignature(signature);

System.out.println("Verification: " + verified); // Verification: true

Note that you can import the raw keys, ie the 32 bytes keys, directly with Ed25519PrivateKeyParameters or Ed25519PublicKeyParameters . So an alternative solution would be to get the raw keys from the OpenSSH formatted keys and use those.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM