I having trouble verifying an ECDSA signature signed using client side javascript with Java/BouncyCastle.
The javascript signing function source:
sign: function (hash, priv) {
var d = priv;
var n = ecparams.getN();
var e = BigInteger.fromByteArrayUnsigned(hash);
do {
var k = ECDSA.getBigRandom(n);
var G = ecparams.getG();
var Q = G.multiply(k);
var r = Q.getX().toBigInteger().mod(n);
} while (r.compareTo(BigInteger.ZERO) <= 0);
var s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n);
return ECDSA.serializeSig(r, s);
},
serializeSig: function (r, s) {
var rBa = r.toByteArrayUnsigned();
var sBa = s.toByteArrayUnsigned();
var sequence = [];
sequence.push(0x02); // INTEGER
sequence.push(rBa.length);
sequence = sequence.concat(rBa);
sequence.push(0x02); // INTEGER
sequence.push(sBa.length);
sequence = sequence.concat(sBa);
sequence.unshift(sequence.length);
sequence.unshift(0x30) // SEQUENCE
return sequence;
},
The server side verify function source:
/**
* Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key.
*
* @param data Hash of the data to verify.
* @param signature ASN.1 encoded signature.
* @param pub The public key bytes to use.
*/
public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
ECDSASigner signer = new ECDSASigner();
ECPublicKeyParameters params = new ECPublicKeyParameters(ecParams.getCurve().decodePoint(pub), ecParams);
signer.init(false, params);
try {
ASN1InputStream decoder = new ASN1InputStream(signature);
DERSequence seq = (DERSequence) decoder.readObject();
DERInteger r = (DERInteger) seq.getObjectAt(0);
DERInteger s = (DERInteger) seq.getObjectAt(1);
decoder.close();
return signer.verifySignature(data, r.getValue(), s.getValue());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Does anyone know what format the javascript signature is in (DER?) and if so how to convert it to ASN.1?
I tried:
public static byte[] toASN1(byte[] data) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(400);
ASN1OutputStream encoder = new ASN1OutputStream(baos);
encoder.write(data);
encoder.close();
return baos.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e); // Cannot happen, writing to memory stream.
}
}
but validation still fails.