BouncyCastle ECDSA Signature Verification Failed Using prime256v1 and SHA256withECDSA Algorithm

QuestionsCategory: QuestionsBouncyCastle ECDSA Signature Verification Failed Using prime256v1 and SHA256withECDSA Algorithm
Brightn-n-Fresh Staff asked 1 year ago

I need to verify an ECDSA signature with Java using BouncyCastle crypto provider. So far BouncyCastle failed to verify the signature.

The signature is created in Atmel AT88CK590 Crypto Authentication module and Public key can be obtained out from the module. Here is the Public Key, in C/C++ format, of 64 octets long:

uint8_t pubKey[] = {
    // X coordinate of the elliptic curve.
    0xc1, 0x71, 0xCB, 0xED, 0x65, 0x71, 0x82, 0x2E, 0x8F, 0x8A, 0x43, 0x8D, 0x72, 0x56, 0xD1, 0xC8,
    0x86, 0x3C, 0xD0, 0xBC, 0x7F, 0xCC, 0xE3, 0x6D, 0xE7, 0xB7, 0x17, 0xED, 0x29, 0xC8, 0x38, 0xCB,

    // Y coordinate of the elliptic curve.
    0x80, 0xCD, 0xBE, 0x0F, 0x1D, 0x5C, 0xC5, 0x46, 0x99, 0x24, 0x8F, 0x6E, 0x0A, 0xEA, 0x1F, 0x7A,
    0x43, 0xBA, 0x2B, 0x03, 0x80, 0x90, 0xE9, 0x25, 0xB2, 0xD0, 0xE6, 0x48, 0x93, 0x91, 0x64, 0x83
};

The original message, the signature and Public key in Base64 encoding:

// Raw message to sign
private static final String tokenStr = "12345678901234567890123456789012";
// Base64 encoded
private static final String pubKeyStr = "wXHL7WVxgi6PikONclbRyIY80Lx/zONt57cX7SnIOMuAzb4PHVzFRpkkj24K6h96
Q7orA4CQ6SWy0OZIk5Fkgw==";
// Base64 encoded
private static final String signatureStr = "XF2WossFTA82ndYFGEH0FPqAldkFQLGd/Bv/Qh8UYip7sXUvCUnFgi1YXjN3WxLn
IwSo3OaHLCOzGAtIis0b3A==";

To convert the Public key I am using the following:

private static PublicKey getPublicKeyFromBytes(byte[] pubKey, String ecSpec, String provider)
        throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
    ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(ecSpec);
    KeyFactory kf = KeyFactory.getInstance(ECDSA_CRYPTO, provider);
    ECNamedCurveSpec params = new ECNamedCurveSpec(ecSpec, spec.getCurve(), spec.getG(), spec.getN());
    ECPoint pubPoint =  ECPointUtil.decodePoint(params.getCurve(), pubKey);
    ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(pubPoint, params);
    PublicKey publicKey = kf.generatePublic(pubKeySpec);

    return publicKey;
}

To convert the signature to DER format I am using the following:

private static byte[] toDERSignature(byte[] tokenSignature) throws IOException {
    byte[] r = Arrays.copyOfRange(tokenSignature, 0, tokenSignature.length / 2);
    byte[] s = Arrays.copyOfRange(tokenSignature, tokenSignature.length / 2, tokenSignature.length);
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    DEROutputStream derOutputStream = new DEROutputStream(byteArrayOutputStream);
    ASN1EncodableVector v = new ASN1EncodableVector();

    v.add(new ASN1Integer(new BigInteger(1, r)));
    v.add(new ASN1Integer(new BigInteger(1, s)));
    derOutputStream.writeObject(new DERSequence(v));

    byte[] derSignature = byteArrayOutputStream.toByteArray();

    return derSignature;
}

Here is the code to verify the signature:

Security.addProvider(new BouncyCastleProvider());

byte[] tokenBytes = tokenStr.getBytes("UTF-8");
String urlDecodePubKeyStr = pubKeyStr.replace(newlineHtml, "");
byte[] pubKeyBytes = DatatypeConverter.parseBase64Binary(urlDecodePubKeyStr);
String urlDecodeSignatureStr = signatureStr.replace(newlineHtml, "");
byte[] signBytes = DatatypeConverter.parseBase64Binary(urlDecodeSignatureStr);
byte[] derSignature = toDERSignature(signBytes);
ByteBuffer bb = ByteBuffer.allocate(pubKeyBytes.length + 1);

bb.put((byte)4);
bb.put(pubKeyBytes);

PublicKey ecPublicKey = getPublicKeyFromBytes(bb.array(), "prime256v1", "BC");

System.out.println("\nSignature: " + Hex.toHexString(signBytes).toUpperCase());
System.out.println("DER Signature: " + Hex.toHexString(derSignature).toUpperCase());
System.out.println(ecPublicKey.toString());

Signature signature = Signature.getInstance("SHA256withECDSA", "BC");

signature.initVerify(ecPublicKey);
signature.update(tokenBytes);

boolean result = signature.verify(derSignature);

System.out.println("BC Signature Valid: " + result);

The output:

Signature: 5C5D96A2CB054C0F369DD6051841F414FA8095D90540B19DFC1BFF421F14622A7BB1752F0949C5822D585E33775B12E72304A8DCE6872C23B3180B488ACD1BDC
DER Signature: 304402205C5D96A2CB054C0F369DD6051841F414FA8095D90540B19DFC1BFF421F14622A02207BB1752F0949C5822D585E33775B12E72304A8DCE6872C23B3180B488ACD1BDC
EC Public Key
           X: c171cbed6571822e8f8a438d7256d1c8863cd0bc7fcce36de7b717ed29c838cb
           Y: 80cdbe0f1d5cc54699248f6e0aea1f7a43ba2b038090e925b2d0e64893916483

BC Signature Valid: false

Have anyone run into the same problem before? What did I miss here?

(191)