ed25519-java和js-nacl都有ed25519加密签名方法的实现。但是,我从ed25519-java获得了一个公钥和一个签名消息(使用公钥的相应私钥签名),并尝试使用js-nacl中的公钥验证签名消息。这给出了null
值,即无法使用公钥打开已签名的消息。
我的问题是,是否可以登录Java并验证Javascript中的签名?如果是,或者如果没有,为什么?
Java代码:
public static void main(String[] args) {
byte[] privateKey = new byte[32];
Arrays.fill(privateKey, (byte) 0);
byte[] publicKey = ed25519.publickey(privateKey);
byte[] signature = ed25519.signature("www.example.com".getBytes(), privateKey, publicKey);
System.out.println("Signature: " + Base64.encodeBase64URLSafeString(signature) + "\nPublicKey: " + Base64.encodeBase64URLSafeString(publicKey));
try{
System.out.println("Verification: " + ed25519.checkvalid(signature, "www.example.com".getBytes(), publicKey));
} catch (Exception e){
System.out.println(e.getStackTrace());
}
}
checkvalid调用返回true。
输出签名:oFMU_mC_zzZcJP2C-uTqsyUHoyLUSnwirJbhcdkSTnj2nI_p-VgKAqN5bFMPKsKYiWvyiUgHWu3s4OyB9WbKDg
输出公钥:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik
javascript代码:
var signature = "oFMU_mC_zzZcJP2C-uTqsyUHoyLUSnwirJbhcdkSTnj2nI_p-VgKAqN5bFMPKsKYiWvyiUgHWu3s4OyB9WbKDg";
var pk = "O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik";
var nacl_factory = require('js-nacl');
var nacl = nacl_factory.instantiate();
var b64 = require('urlsafe-base64');
var x = nacl.crypto_sign_open(Uint8Array(b64.decode(signature)), Uint8Array(b64.decode(pk)));
response.send(x);
x
为空,但如果可以使用公钥打开签名,则应将"www.example.com"
作为输出。
不确定它是否会影响工作,但Java的字节数组是有符号的,而js-nacl使用Javascript的Uint8Array
无符号字节数组。
答案 0 :(得分:4)
Ed25519实现在两个方面有所不同:
私钥格式有点不同。一些使用扩展的私钥,其他人在签名时请求种子和公钥。您的java实现属于后一类。
此差异仅适用于签名功能,而不适用于验证功能。它不会给你带来任何问题。
某些实现使用"签名框",其中签名返回签名和消息(signedMessage.Length = 64 + message.Length
)的串联。验证时,他们希望将签名的邮件作为输入。原始的NaCl实施和您的javascript实现属于这一类。
某些实现返回64字节签名。他们希望在验证时将明文作为单独的参数。您的java实现属于此类别。
这种不匹配导致了你的麻烦。要解决此问题,您需要将concat(signature, message)
传递给crypto_sign_open
。
您应该阅读Brian Warner的Ed25519 Keys文章,以获得更详细的解释。