1

Both ed25519-java and js-nacl have an implementation of ed25519 crypto-signature methods. However, I obtained a public key and a signed message (signed using the public key's corresponding private key) from ed25519-java and tried verifying the signed message using the public key in js-nacl. This gave a null value i.e. the signed message could not be opened with the public key.

My question is, shouldn't it be possible to sign in Java and verify the signature in Javascript? If so, or if not, why?

The Java code:

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

The checkvalid call returns true.

The output signature: oFMU_mC_zzZcJP2C-uTqsyUHoyLUSnwirJbhcdkSTnj2nI_p-VgKAqN5bFMPKsKYiWvyiUgHWu3s4OyB9WbKDg

The output public key: O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik

The javascript code:

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 is null, but should give "www.example.com" as output if the signature could be opened with the public key.

Not sure if it impacts the working, but Java's byte arrays are signed, whereas js-nacl uses Javascript's Uint8Array unsigned byte arrays.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • 2
    1) Are you talking about encryption (with `crypto_box` based on Curve25519 + xsalsa20poly1305) or signatures (with Ed25519-SHA512)? 2) Please post the relevant code together with an example message/signature – CodesInChaos Apr 16 '14 at 11:00
  • Yep, you are still talking about an encryption method. Then you talk about a signed message. Example code would make it clear what you are actually asking and it even may show us what goes wrong. – Maarten Bodewes Apr 16 '14 at 14:08
  • Don't use `string.getBytes()` in java, it uses the locale dependent legacy encoding. Explicitly specify an encoding, preferably UTF-8. – CodesInChaos Apr 23 '14 at 11:37

1 Answers1

5

Ed25519 implementations differ in two ways:

  1. The private key format is a bit different. Some work with an expanded private key, others ask for both the seed and the public key when signing. Your java implementation falls in the latter category.

    This difference only applies to the signing function, not the verification function. It doesn't cause any problems for you.

  2. Some implementations use a "signature box", where signing returns the concatenation of signature and message (signedMessage.Length = 64 + message.Length). When verifying they expect that signed message as input. The original NaCl implementation and your javascript implementation fall in this category.

    Some implementations return a 64 byte signature. They expect the plaintext as a separate parameter when verifying. Your java implementation falls in this category.

    This mismatch is causing your trouble. To fix it you need to pass concat(signature, message) to crypto_sign_open.

You should read Brian Warner's Ed25519 Keys article for a more detailed explanation.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262