russ
russ

Reputation: 65

Data encrypted with mbedtls not decrypting properly with Bouncy Castle

I have a microcontroller using mbedtls to encrypt data, which is transmitted to a Windows computer where it must be decrypted using Bouncy Castle. AES256 in CBC mode, with a 16-byte initialization vector, is used. My data will always be multiples of the AES block size (16 bytes), so padding is not needed. The encryption code is:

int Crypto_Encrypt_Data(unsigned char* data, int num_bytes, unsigned char* ct, unsigned char* IniVec)
{
  unsigned char iv[16];

  //Load the AES key into the AES context; specify key size in bits (NOT bytes)
  mbedtls_aes_setkey_enc( &AES_Context, (unsigned char*)AESKey, (key_size * 8) );

  //Load the initialization vector with a random number
  mbedtls_ctr_drbg_random( &DRBG_Context, iv, strlen((char*)iv) );

  //Save a copy of the IV for possible use decrypting
  memcpy(InitializationVector, iv, 16);

  //Return a copy of the IV to caller
  *IniVec = *InitializationVector;

  return mbedtls_aes_crypt_cbc( &AES_Context, MBEDTLS_AES_ENCRYPT, num_bytes, iv, data, ct );
}

On the Windows side, the decryption code is:

 public static byte[] CBCDecryptData(FipsAes.Key key, byte[] ciphertext, byte[] iv)
    {
        IBlockCipherService provider = CryptoServicesRegistrar.CreateService(key);
        IBlockCipherBuilder<IParameters<Algorithm>> decryptBuilder = provider.CreateBlockDecryptorBuilder(FipsAes.Cbc.WithIV(iv));
    IBlockCipher decryptor = decryptBuilder.BuildBlockCipher(new MemoryInputStream(ciphertext));

    byte[] plaintext;
    using (Stream decryptorStream = decryptor.Stream)
    {
        plaintext = Streams.ReadAll(decryptorStream);
    }
    return plaintext;
}

I have verified that the initialization vector and cipher text on the Windows side is the same as that in the microcontoller, but the decrypted plain text does not match, see below:

Microcontroller, mbedtls
Key: 4D:A6:E2:9D:AF:25:58:75:EE:5C:70:88:55:BA:4F:62:07:FE:B1:8A:58:59:91:FE:B3:3D:66:B7:DA:EF:2F:60
iv: 42:00:E0:0F:00:00:01:00:00:00:01:4A:FB:00:00:00
Plain Text: 54:68:69:73:20:68:65:72:65:20:69:73:20:61:6E:20:65:6E:63:72:79:70:74:69:6F:6E:20:74:65:73:74:2E
Cipher Text: 2D:6D:AB:63:BE:10:3D:87:AA:15:41:7C:8F:E5:16:81:AF:D9:E0:92:3E:37:DF:92:C4:15:41:55:7B:FD:0B:6B

Windows, Bouncy Castle
Key: 4D:A6:E2:9D:AF:25:58:75:EE:5C:70:88:55:BA:4F:62:07:FE:B1:8A:58:59:91:FE:B3:3D:66:B7:DA:EF:2F:60
iv: 42:00:E0:0F:00:00:01:00:00:00:01:4A:FB:00:00:00
Cipher Text: 2D:6D:AB:63:BE:10:3D:87:AA:15:41:7C:8F:E5:16:81:AF:D9:E0:92:3E:37:DF:92:C4:15:41:55:7B:FD:0B:6B
Plain Text: 54:EA:89:7C:20:68:64:72:65:20:68:39:FB:61:6E:20:65:6E:63:72:79:70:74:69:6F:6E:20:74:65:73:74:2E

I notice that the last (second) 16-bytes (one AES block) appears to decrypt OK, but not the first. This is probably a clue to the problem, but I can not figure out what it is. Also, the data does decrypt OK using mbedtls in the microcontroller.

Upvotes: 1

Views: 220

Answers (1)

russ
russ

Reputation: 65

The problem was indeed with the IV. Being quite rusty regarding pointers/arrays, I was not passing back the IV correctly. On the microcontroller side, giving the calling function access to the InitializationVector array allowed the correct IV to be sent to the Bouncy Castle decryption routine on the Windows side - which now produces the correct result.

The encryption routine in the microcontroller simplifies a bit to become:

int Crypto_Encrypt_Data(unsigned char* data, int num_bytes, unsigned char* ct)
{
  unsigned char iv[16];

  //Load the AES key into the AES context; specify key size in bits (NOT bytes)
  mbedtls_aes_setkey_enc( &AES_Context, (unsigned char*)AESKey, (key_size * 8) );

  //Load the initialization vector with a random number
  mbedtls_ctr_drbg_random( &DRBG_Context, iv, strlen((char*)iv) );

  //Save a copy of the IV, to be used for decryption
  memcpy(InitializationVector, iv, 16);

  return mbedtls_aes_crypt_cbc( &AES_Context, MBEDTLS_AES_ENCRYPT, num_bytes, iv, data, ct );
}

Since mbedtls_aes_crypt_cbc() modifies iv, the copy saved in InitializationVector is sent, along with the cipher text, ct, to the Windows side where Bouncy Castle can successfully decrypt it.

Upvotes: 1

Related Questions