Daniel Brox
Daniel Brox

Reputation: 1

AES-GCM 256 bit - Node.js encrypt / Android decrypt - 16 byte authentication tags don't match

Trying to use AES-GCM 256 to encrypt "Hello World" in Node.js in such a way that the encrypted string sent ota to an Android phone can be decrypted. The Node.js encryption code is:

const KEY = new Buffer('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21', 'hex');
var iv = Buffer.from("0000000000000000",'base64');                         
var cipher = crypt.createCipheriv('aes-256-gcm', Buffer.from(KEY, 'utf-8'), iv);                   
var ciph = cipher.update(Buffer.from("Hello World", 'utf-8'), 'utf8', 'base64');  
ciphered += cipher.final('base64');
console.log(cipher.getAuthTag().toString('base64'));

and the Android (Studio) decryption code is:

public static byte[] decrypt(byte[] data)
            throws CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException,
            KeyStoreException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        SecretKey secretKey = null;

        byte[] decodedKey = new byte[] {(byte)0x1b,(byte)0xc0,(byte)0xd5,(byte)0x63,(byte)0x32,(byte)0x9d,(byte)0x29,(byte)0xfc,(byte)0x62,(byte)0x36,(byte)0xf0,(byte)0x99,(byte)0x37,(byte)0x1e,(byte)0x33,(byte)0x4f,(byte)0xeb,(byte)0x9b,(byte)0xbf,(byte)0x3e,(byte)0x91,(byte)0xbb,(byte)0xa2,(byte)0xad,(byte)0xb4,(byte)0x04,(byte)0x3f,(byte)0xeb,(byte)0x87,(byte)0x0b,(byte)0x6b,(byte)0x21};

        secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
        

        byte[] iv = Base64.decode("0000000000000000", Base64.DEFAULT);
        GCMParameterSpec gcmspec = new GCMParameterSpec(128, iv);

        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmspec);
        return cipher.doFinal(data);
    }

which fails to decrypt because of authentication tag mismatch. I verified the tags don't match by encrypting the same string in Android with the same key and initialization vector:

public void TEST_ENCRYPT() throws IOException, CertificateException, NoSuchAlgorithmException, InvalidKeyException, UnrecoverableEntryException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, BadPaddingException, KeyStoreException, IllegalBlockSizeException {

        String inputString = "Hello World";
        byte[] byteArray = inputString.getBytes();
        String value = Base64.encodeToString(encrypt(byteArray), Base64.DEFAULT);
        Log.d("TEST_ENCRYPT", value);
}

public static byte[] encrypt(byte[] data)
            throws CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException,
            KeyStoreException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {

       
        SecretKey secretKey = null;

        byte[] decodedKey = new byte[] {(byte)0x1b,(byte)0xc0,(byte)0xd5,(byte)0x63,(byte)0x32,(byte)0x9d,(byte)0x29,(byte)0xfc,(byte)0x62,(byte)0x36,(byte)0xf0,(byte)0x99,(byte)0x37,(byte)0x1e,(byte)0x33,(byte)0x4f,(byte)0xeb,(byte)0x9b,(byte)0xbf,(byte)0x3e,(byte)0x91,(byte)0xbb,(byte)0xa2,(byte)0xad,(byte)0xb4,(byte)0x04,(byte)0x3f,(byte)0xeb,(byte)0x87,(byte)0x0b,(byte)0x6b,(byte)0x21};

        secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");

        Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
        
        byte[] iv = Base64.decode("0000000000000000", Base64.DEFAULT);
        GCMParameterSpec gcmspec = new GCMParameterSpec(128, iv);
        try {
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmspec);
        }catch(Exception e)
        {
            Log.d("error", e.toString());
        }
        return cipher.doFinal(data);
    }

and comparing the appended 16 bytes to the encrypted message (i.e. the Android authentication tag) to the Node.js authentication tag. This authentication tag mismatch occurs despite the fact the encrypted messages are the same, and makes decryption of messages on the Android phone throw errors. How can this problem be solved? I would expect the AES-GCM 256 algorithm to work the same on both client and server.

Upvotes: 0

Views: 591

Answers (1)

Criminal_Affair_At_SO
Criminal_Affair_At_SO

Reputation: 3443

Look at your Buffer:

new Buffer('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21');

This is not what you expect, this is simply a string.

You need this:

Buffer.from('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21', 'hex');

Upvotes: 0

Related Questions