This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Fail in verifying micro ECC signature in Android

In order to prevent communication from middle-man attack, I append the signature after ECDH publickey. However, though I get the correct share secret by ECDH, I fail in verifying the micro ecc signature in Android studio, and 52832 also fails in verify android signature. Here's my test codes:

private void showsignature() {
    KeyPair keyPair = ECC.CreateKeyPair();
    ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic();
    ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate();
    byte[] sk = ECC.ECPrivateKey2ByteArray(ecPrivateKey);
    byte[] pk = ECC.ECPublicKey2ByteArray(ecPublicKey);
    byte[] ss = ECC.ShareSecret(ecPublicKey, ecPrivateKey);
    byte[] msg = "hello".getBytes();
    byte[] sign = ECC.CreateSignature(msg, ecPrivateKey);
    System.out.println("sk:");
    System.out.println(Hex2Str(sk));
    System.out.println("pk:");
    System.out.println(Hex2Str(pk));
    System.out.println("ss:");
    System.out.println(Hex2Str(ss));
    System.out.println("sign:");
    System.out.println(Hex2Str(sign));
    if (ECC.VerifySignature(ecPublicKey, msg, sign)) {
        System.out.println("verify pass");
    }
}

I write a public class (ECC) to deal with the details about the format converting from micro ecc raw byte array to Android format.Because Android and nrf52832 can get the same share secret, so I do belive there's no bug in converting. Aftern I get some data created by the above Android function, I put the data to nrf52832 to verify the signature.

static void test(void)

{

		uint8_t sk[] ={
		0x81,0x37,0x42,0xA8,0x20,0xEE,0x40,0x04,
		0x6B,0xEF,0xB1,0x78,0x65,0x9F,0xE3,0x8A,
		0x35,0x35,0xA4,0x0C,0xB7,0xFC,0x16,0xE4,
		0xE0,0x9F,0xD6,0x24,0xE3,0x24,0x97,0x56};
		uint8_t pk[] = {
		0xDF,0xA7,0x14,0x97,0xDB,0x37,0x22,0xA3,
		0x82,0xE1,0x6D,0x2A,0xE1,0x60,0x82,0x85,
		0xB9,0x9A,0x10,0x40,0x27,0xC4,0x2E,0xCB,
		0xFB,0xFB,0x6D,0x13,0x62,0xD4,0x5F,0x17,
		0x26,0xE1,0x2E,0x34,0x0F,0xA1,0x5A,0x57,
		0x5B,0x2F,0x28,0x69,0xCA,0x76,0x9E,0x8C,
		0x7A,0xBD,0x60,0x05,0xA8,0xD3,0x16,0xC9,
		0x06,0xC4,0x05,0x3E,0x95,0xD4,0x98,0x5F};
		uint8_t sign[]={
		0x93,0xD3,0xB7,
		0x9C,0x8C,0x05,0xED,0x0C,0xF0,0x7D,0xF4,
		0x4C,0xFB,0x9B,0x89,0x2D,0x3E,0xAB,0xF9,
		0xDE,0x11,0x72,0x05,0xB2,0xBD,0x71,0x03,
		0x5E,0x63,0x81,0x0C,0xAC,
		0x0F,
		0xC9,0xAB,0x1F,0x55,0xA4,0x25,0x8D,0x50,
		0x81,0xF0,0xFE,0x17,0xDC,0x19,0x9A,0x40,
		0x45,0x8C,0x28,0x43,0xAA,0x23,0xA6,0xB2,
		0x6F,0x38,0xCC,0xC2,0x2D,0x31,0x89};
		
		char *msg="hello";
		uint8_t ss[32];
		ChangeENDIAN(sk,32);
		ChangeENDIAN(pk,32);
		ChangeENDIAN(&pk[32],32);
		uint8_t hash[32];
		Hash(msg,5,hash);//SHA256
		ChangeENDIAN(hash,32);
		if (ecc_p256_verify(pk,hash,32,sign)==NRF_SUCCESS)
		{
				NRF_LOG_INFO("PASS\n");
		}
		else
		{
			NRF_LOG_INFO("FAIL\n");			
		}
		NRF_LOG_FLUSH();

} Because the ENDIAN not the same,so change the endian before micro ecc use Android data.

static void ChangeENDIAN(uint8_t * msg, uint8_t length) {

             uint8_t buffer;
		for (uint8_t i=0;i<length/2;i++)
		{
			buffer=msg[i];
			msg[i]=msg[length-1-i];
			msg[length-1-i]=buffer;
		}

}

I did everything I can do , but still failed in the verifying, why? Here's the total data from Android:

sk:

0x81,0x37,0x42,0xA8,0x20,0xEE,0x40,0x04, 0x6B,0xEF,0xB1,0x78,0x65,0x9F,0xE3,0x8A, 0x35,0x35,0xA4,0x0C,0xB7,0xFC,0x16,0xE4, 0xE0,0x9F,0xD6,0x24,0xE3,0x24,0x97,0x56,

pk:

0xDF,0xA7,0x14,0x97,0xDB,0x37,0x22,0xA3, 0x82,0xE1,0x6D,0x2A,0xE1,0x60,0x82,0x85, 0xB9,0x9A,0x10,0x40,0x27,0xC4,0x2E,0xCB, 0xFB,0xFB,0x6D,0x13,0x62,0xD4,0x5F,0x17, 0x26,0xE1,0x2E,0x34,0x0F,0xA1,0x5A,0x57, 0x5B,0x2F,0x28,0x69,0xCA,0x76,0x9E,0x8C, 0x7A,0xBD,0x60,0x05,0xA8,0xD3,0x16,0xC9, 0x06,0xC4,0x05,0x3E,0x95,0xD4,0x98,0x5F,

ss:

0x6B,0x7D,0x7A,0x27,0x8B,0x16,0xE7,0xEC, 0x67,0x0C,0x9C,0x84,0xE5,0x72,0x1A,0x04, 0x5E,0x60,0xE5,0xA3,0xAB,0xDF,0x75,0xE1, 0x49,0xB1,0x6F,0x21,0xAC,0xA8,0x22,0x61,

sign:

0x30,0x45,0x02,0x21,0x00,0x93,0xD3,0xB7, 0x9C,0x8C,0x05,0xED,0x0C,0xF0,0x7D,0xF4, 0x4C,0xFB,0x9B,0x89,0x2D,0x3E,0xAB,0xF9, 0xDE,0x11,0x72,0x05,0xB2,0xBD,0x71,0x03, 0x5E,0x63,0x81,0x0C,0xAC,0x02,0x20,0x0F, 0xC9,0xAB,0x1F,0x55,0xA4,0x25,0x8D,0x50, 0x81,0xF0,0xFE,0x17,0xDC,0x19,0x9A,0x40, 0x45,0x8C,0x28,0x43,0xAA,0x23,0xA6,0xB2, 0x6F,0x38,0xCC,0xC2,0x2D,0x31,0x89,

Because android' signature is in DER format, so it's not in 64bytes. nrf52832 supported by sdk12.2/keil 5.23

  • Hi, Could you check this code. It's using ECDSASigner class from Spongy Castle.

    private static final X9ECParameters curve = SECNamedCurves.getByName("secp256k1");
    private static final ECDomainParameters domain = new ECDomainParameters(curve.getCurve(), curve.getG(), curve.getN(), curve.getH());
    
    /**
     * Verifies the message using given signature and public key (given as X and Y points).
     * @param message the message to be verified
     * @param signature the messsage signature
     * @param x X coordinate of public key
     * @param y Y coordinate of public key
     * @return true if signature is valid, false otherwise
     */
    static boolean verify(@NonNull final byte[] message, @NonNull final byte[] signature, @NonNull final BigInteger x, @NonNull final BigInteger y) {
    	if (signature.length != 64)
    		return false;
    
    	try {
    		// Initialize signer
    		final ECDSASigner signer = new ECDSASigner();
    		signer.init(false, new ECPublicKeyParameters(curve.getCurve().createPoint(x, y), domain));
    
    		// Calculate SHA-256 of the message
    		final byte[] hash = sha256(message);
    
    		final int nLength = (curve.getN().bitLength() + 7) / 8;
    		final byte[] r = Arrays.copyOfRange(signature, 0, nLength);
    		final byte[] s = Arrays.copyOfRange(signature, nLength, 2 * nLength);
    		final BigInteger R = new BigInteger(r);
    		final BigInteger S = new BigInteger(s);
    		return signer.verifySignature(hash, R, S);
    	} catch (final Exception e) {
    		Log.e(TAG, "Verify failed", e);
    	}
    	return false;
    }
    
    /**
     * Calculates SHA-256 of given message
     * @param message the message to be hashed
     * @return hash
     */
    private static byte[] sha256(@NonNull final byte[] message) throws NoSuchAlgorithmException {
    	final MessageDigest digest = MessageDigest.getInstance("SHA-256");
    	return digest.digest(message);
    }
    
Related