JavaCard AES加密与Javax AES解密结果不一致问题咨询
Let’s walk through the most likely causes of your encryption/decryption mismatch, along with actionable checks and fixes:
1. Session Key Length Mismatch (High Probability)
Looking at your JavaCard code, you’re generating a 32-byte KEY_SESSION but initializing an AES-128 key (KeyBuilder.LENGTH_AES_128). When you call sessionKeySP.setKey(KEY_SESSION, (short) 0);, JavaCard automatically takes only the first 16 bytes of KEY_SESSION as the AES-128 key.
If your Javax code uses the full 32 bytes of the RSA-decrypted KEY_SESSION as the AES key, this will immediately break decryption.
Fix:
- In your Javax code, after decrypting the RSA-encrypted session key, extract only the first 16 bytes to use as the AES-128 key.
- Verify this by logging the first 16 bytes of
KEY_SESSIONin JavaCard (if possible) and comparing them to the first 16 bytes of the RSA-decrypted key in Javax.
2. IV Inconsistency
Your JavaCard code initializes AES-CBC with a 16-byte all-zero IV:
cipherAES.init(sessionKeySP, Cipher.MODE_ENCRYPT, new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, (short) 0, (short) 16);
For CBC mode, the IV used during decryption must exactly match the IV used during encryption.
Check:
- Ensure your Javax code uses the same all-zero IV when initializing the decrypt cipher:
IvParameterSpec ivSpec = new IvParameterSpec(new byte[16]); Cipher decryptCipher = Cipher.getInstance("AES/CBC/NoPadding"); decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ivSpec); - Double-check that no code is accidentally modifying the IV during transmission or initialization.
3. Input/Output Alignment (No-Pad Requirement)
Since you’re using no padding, the input to AES must be a multiple of the block size (16 bytes for AES-128). Your JavaCard code constructs a 128-byte messageBytes (8 blocks) which is valid, but:
- Confirm the encrypted
messageBytesEncryptedreceived in Javax is exactly 128 bytes (no truncation or extra bytes added during APDU transmission). - Ensure your Javax decrypt code doesn’t attempt to process a partial block (this would throw an exception in most implementations, but double-check anyway).
4. Byte Order & Transmission Integrity
JavaCard and Javax both use big-endian byte order for crypto operations, but transmission errors can still break things:
- Capture the raw bytes sent from the card (session key ciphertext + message ciphertext) and compare them to the bytes received in your Javax code. Ensure no bytes are missing, duplicated, or reversed.
- Verify that the RSA-decrypted session key in Javax matches the first 16 bytes of
KEY_SESSIONgenerated in JavaCard (use debug logs or test with a fixed key temporarily if possible).
5. Cipher Algorithm String Mismatch
Make sure your Javax code uses the exact algorithm string that matches JavaCard’s ALG_AES_BLOCK_128_CBC_NOPAD:
// Correct for no-padding CBC mode Cipher.getInstance("AES/CBC/NoPadding");
Avoid variations like "AES/CBC/PKCS5Padding" or misspelled modes—these will produce incompatible results.
Step-by-Step Verification Test
Isolate the AES operation to narrow down the issue:
- In JavaCard, hardcode a fixed 16-byte AES key, all-zero IV, and 128-byte test plaintext.
- Encrypt this plaintext and log the ciphertext (or send it over APDU).
- In Javax, use the same fixed key, IV, and ciphertext to decrypt. If this works, the problem lies in session key transmission or message construction. If not, double-check your cipher initialization code on both sides.
内容的提问来源于stack exchange,提问作者Ruben Vervaeke

