{"record":{"id":"52a3f8e6787419e3","repo":"spring-projects/spring-security","slug":"unable-to-encrypt-decrypt-52a3f8","errorCode":null,"errorMessage":"unable to encrypt/decrypt","messagePattern":"unable to encrypt/decrypt","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java","lineNumber":72,"sourceCode":"\t}\n\n\t@Override\n\tpublic byte[] decrypt(byte[] encryptedBytes) {\n\t\tbyte[] iv = EncodingUtils.subArray(encryptedBytes, 0, this.ivGenerator.getKeyLength());\n\t\tencryptedBytes = EncodingUtils.subArray(encryptedBytes, this.ivGenerator.getKeyLength(), encryptedBytes.length);\n\t\tAEADBlockCipher blockCipher = GCMBlockCipher.newInstance(AESEngine.newInstance());\n\t\tblockCipher.init(false, new AEADParameters(this.secretKey, 128, iv, null));\n\t\treturn process(blockCipher, encryptedBytes);\n\t}\n\n\tprivate byte[] process(AEADBlockCipher blockCipher, byte[] in) {\n\t\tbyte[] buf = new byte[blockCipher.getOutputSize(in.length)];\n\t\tint bytesWritten = blockCipher.processBytes(in, 0, in.length, buf, 0);\n\t\ttry {\n\t\t\tbytesWritten += blockCipher.doFinal(buf, bytesWritten);\n\t\t}\n\t\tcatch (InvalidCipherTextException ex) {\n\t\t\tthrow new IllegalStateException(\"unable to encrypt/decrypt\", ex);\n\t\t}\n\t\tif (bytesWritten == buf.length) {\n\t\t\treturn buf;\n\t\t}\n\t\tbyte[] out = new byte[bytesWritten];\n\t\tSystem.arraycopy(buf, 0, out, 0, bytesWritten);\n\t\treturn out;\n\t}\n\n}\n","sourceCodeStart":54,"sourceCodeEnd":83,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/crypto/src/main/java/org/springframework/security/crypto/encrypt/BouncyCastleAesGcmBytesEncryptor.java#L54-L83","documentation":"Thrown by BouncyCastleAesGcmBytesEncryptor.process when the GCM cipher's doFinal reports an InvalidCipherTextException, i.e. GCM tag verification failed. With AES-GCM this specifically indicates authentication failure: wrong key, corrupted or truncated ciphertext, or mismatched associated data. GCM detects tampering, so this is often a sign of intentional modification or key mismatch.","triggerScenarios":"Calling decrypt on bytes whose GCM authentication tag does not verify: different password/salt than encryption, bit rot or truncation of stored ciphertext, tampered token, or decrypting CBC-encrypted data with the GCM encryptor.","commonSituations":"Password or secret rotated without re-encrypting stored values; encrypted cookie/JWT-like tokens modified by a client; data passed through systems that alter bytes (e.g. treating binary as a String instead of Base64); cross-environment data copies.","solutions":["Ensure the same password and secure-random salt bytes are used on both encrypt and decrypt paths.","If ciphertext travels through text channels, always Base64-encode/decode — never new String(bytes) round-trips.","Re-encrypt stored data if the key was rotated; keep old key available for migration.","Treat the failure as tampered/unrecognized input: catch and return an authentication error.","Verify you decrypt with the same encryptor class that encrypted (CBC vs GCM outputs are incompatible)."],"exampleFix":"// before\nbyte[] plain = gcmEncryptor.decrypt(rawBytesFromRequest);\n// after\ntry {\n    byte[] plain = gcmEncryptor.decrypt(rawBytesFromRequest);\n} catch (IllegalStateException ex) {\n    throw new SecurityException(\"Ciphertext failed GCM authentication (wrong key or tampered)\", ex);\n}","handlingStrategy":"try-catch","validationCode":"// verify ciphertext integrity markers before decrypt\nif (cipherBytes == null || cipherBytes.length < 28) throw new IllegalArgumentException(\"ciphertext too short\");","typeGuard":null,"tryCatchPattern":"try {\n    return gcmEncryptor.decrypt(cipherBytes);\n} catch (IllegalStateException ex) {\n    throw new SecurityException(\"GCM authentication failed: wrong key or tampered data\", ex);\n}","preventionTips":["Never round-trip ciphertext through new String(bytes); always use Base64.","Pin key material in one place; avoid per-service password drift.","Detect tampering explicitly: GCM failure means data was modified or key mismatched.","Test decryption after every key rotation deployment."],"tags":["crypto","aes-gcm","authentication-tag","tampering","spring-security"],"backgroundTag":"invalid-argument-value","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}