Sign/Verify Json 将 ED25519 密钥与 Bouncy Castle (Java) 结合使用
Sign/Verify Json using ED25519 keys with Bouncy Castle (Java)
我使用 ssh-keygen -t ed25519:
生成了以下密钥
PRIVATE KEY:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1r.....dFUQE=
-----END OPENSSH PRIVATE KEY-----
PUBLIC KEY:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWZbgFOWl97YZJ5Voljoz0f52jRO24jqLLcEhWtalo6 USER@LAPTOP
我正在尝试使用上述密钥来签名和验证 json 字符串,但是,verifySignature 总是返回 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);
这个已验证总是错误的。任何想法...
正在尝试关注
私有密钥和 public Ed25519 密钥的大小均为 32 字节。它们可以被封装成不同的格式。 ssh-keygen 使用所使用的语句生成 OpenSSH 格式的两个 Ed25519 密钥。这种格式不能直接导入。但是,BouncyCastle 为此目的提供了帮助程序 类。
可以使用 PemReader
加载私钥并使用 OpenSSHPrivateKeyUtil.parsePrivateKeyBlob()
导入到 Ed25519PrivateKeyParameters
实例中。 OpenSSHPublicKeyUtil.parsePublicKey()
允许将 public 密钥的 Base64 解码主体导入 Ed25519PublicKeyParameters
实例。
使用 ssh-keygen -t ed25519
创建的密钥对看起来例如如下:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDbBP+5jmEtjh1JvhzVQsvvTC2IQrX6P68XzrV7ZbnGsQAAAKBgtw9/YLcP
fwAAAAtzc2gtZWQyNTUxOQAAACDbBP+5jmEtjh1JvhzVQsvvTC2IQrX6P68XzrV7ZbnGsQ
AAAEAaKYn22N1O78HfdG22C7hcG2HiezKMzlq4JTdgYG1DstsE/7mOYS2OHUm+HNVCy+9M
LYhCtfo/rxfOtXtlucaxAAAAHHRmbG9yZXNfZHQwMUB0ZmxvcmVzX2R0MDEtUEMB
-----END OPENSSH PRIVATE KEY-----
和
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINsE/7mOYS2OHUm+HNVCy+9MLYhCtfo/rxfOtXtlucax whatever
两个密钥都可以导入并用于签名和验证,如下所示:
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
请注意,您可以导入原始密钥,即 32 字节密钥,直接 与 Ed25519PrivateKeyParameters
或 Ed25519PublicKeyParameters
。因此,另一种解决方案是从 OpenSSH 格式的密钥中获取原始密钥并使用它们。
我使用 ssh-keygen -t ed25519:
生成了以下密钥PRIVATE KEY:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1r.....dFUQE=
-----END OPENSSH PRIVATE KEY-----
PUBLIC KEY:
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGWZbgFOWl97YZJ5Voljoz0f52jRO24jqLLcEhWtalo6 USER@LAPTOP
我正在尝试使用上述密钥来签名和验证 json 字符串,但是,verifySignature 总是返回 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);
这个已验证总是错误的。任何想法...
正在尝试关注
私有密钥和 public Ed25519 密钥的大小均为 32 字节。它们可以被封装成不同的格式。 ssh-keygen 使用所使用的语句生成 OpenSSH 格式的两个 Ed25519 密钥。这种格式不能直接导入。但是,BouncyCastle 为此目的提供了帮助程序 类。
可以使用 PemReader
加载私钥并使用 OpenSSHPrivateKeyUtil.parsePrivateKeyBlob()
导入到 Ed25519PrivateKeyParameters
实例中。 OpenSSHPublicKeyUtil.parsePublicKey()
允许将 public 密钥的 Base64 解码主体导入 Ed25519PublicKeyParameters
实例。
使用 ssh-keygen -t ed25519
创建的密钥对看起来例如如下:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDbBP+5jmEtjh1JvhzVQsvvTC2IQrX6P68XzrV7ZbnGsQAAAKBgtw9/YLcP
fwAAAAtzc2gtZWQyNTUxOQAAACDbBP+5jmEtjh1JvhzVQsvvTC2IQrX6P68XzrV7ZbnGsQ
AAAEAaKYn22N1O78HfdG22C7hcG2HiezKMzlq4JTdgYG1DstsE/7mOYS2OHUm+HNVCy+9M
LYhCtfo/rxfOtXtlucaxAAAAHHRmbG9yZXNfZHQwMUB0ZmxvcmVzX2R0MDEtUEMB
-----END OPENSSH PRIVATE KEY-----
和
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINsE/7mOYS2OHUm+HNVCy+9MLYhCtfo/rxfOtXtlucax whatever
两个密钥都可以导入并用于签名和验证,如下所示:
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
请注意,您可以导入原始密钥,即 32 字节密钥,直接 与 Ed25519PrivateKeyParameters
或 Ed25519PublicKeyParameters
。因此,另一种解决方案是从 OpenSSH 格式的密钥中获取原始密钥并使用它们。