Java AES encryption and decryption
The Advanced Encryption Standard (AES, Rijndael) is a block cipher encryption and decryption algorithm, the most used encryption algorithm in the worldwide. The AES processes block of 128 bits using a secret key of 128, 192, or 256 bits.
This article shows you a few of Java AES encryption and decryption examples:
- AES String encryption – (encrypt and decrypt a string).
- AES Password-based encryption – (The secret key will derive from a given password).
- AES File encryption. (password-based).
In this article, we are focus on the 256-bit AES encryption with Galois Counter Mode (GCM).
GCM = CTR + Authentication.
Further Reading
Read this – NIST – Recommendation for Galois/Counter Mode (GCM)
Don’t use AES Electronic codebook (ECB) Mode
The AES ECB mode, or AES/ECB/PKCS5Padding
(in Java) is not semantically secure – The ECB-encrypted ciphertext can leak information about the plaintext. Here is a discussion about Why shouldn’t I use ECB encryption?
1. Java and AES encryption inputs.
In AES encryption and decryption, we need the following inputs:
AES encryption best practice
Don’t reuse IV with the same key.
1.1 The IV (initial value or initial vector), it is random bytes, typically 12 bytes or 16 bytes. In Java, we can use SecureRandom
to generate the random IV.
// 16 bytes IV
public static byte[] getRandomNonce() {
byte[] nonce = new byte[16];
new SecureRandom().nextBytes(nonce);
return nonce;
}
// 12 bytes IV
public static byte[] getRandomNonce() {
byte[] nonce = new byte[12];
new SecureRandom().nextBytes(nonce);
return nonce;
}
1.2 The AES secret key, either AES-128
or AES-256
. In Java, we can use KeyGenerator
to generate the AES secret key.
// 256 bits AES secret key
public static SecretKey getAESKey() throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(256, SecureRandom.getInstanceStrong());
return keyGen.generateKey();
}
1.3 The AES secret key that derived from a given password. In Java, we can use the SecretKeyFactory
and PBKDF2WithHmacSHA256
to generate an AES key from a given password.
// AES key derived from a password
public static SecretKey getAESKeyFromPassword(char[] password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
// iterationCount = 65536
// keyLength = 256
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return secret;
}
We use salt
to protect rainbow attacks, and it is also a random byte, we can use the same 1.1 getRandomNonce
to generate it.
1.4 We group the above methods into a single util
class, so that we won’t repeat the same code again and again.
package com.mkyong.crypto.utils;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.ArrayList;
import java.util.List;
public class CryptoUtils {
public static byte[] getRandomNonce(int numBytes) {
byte[] nonce = new byte[numBytes];
new SecureRandom().nextBytes(nonce);
return nonce;
}
// AES secret key
public static SecretKey getAESKey(int keysize) throws NoSuchAlgorithmException {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(keysize, SecureRandom.getInstanceStrong());
return keyGen.generateKey();
}
// Password derived AES 256 bits secret key
public static SecretKey getAESKeyFromPassword(char[] password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
// iterationCount = 65536
// keyLength = 256
KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
return secret;
}
// hex representation
public static String hex(byte[] bytes) {
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02x", b));
}
return result.toString();
}
// print hex with block size split
public static String hexWithBlockSize(byte[] bytes, int blockSize) {
String hex = hex(bytes);
// one hex = 2 chars
blockSize = blockSize * 2;
// better idea how to print this?
List<String> result = new ArrayList<>();
int index = 0;
while (index < hex.length()) {
result.add(hex.substring(index, Math.min(index + blockSize, hex.length())));
index += blockSize;
}
return result.toString();
}
}
2. AES encryption and decryption.
The AES-GSM is the most widely used authenticated cipher. This example will encrypt and decrypt a string using 256-bit AES in Galois Counter Mode (GCM).
The AES-GCM inputs:
- AES Secret key (256 bits)
- IV – 96 bits (12 bytes)
- Length (in bits) of authentication tag – 128 bits (16 bytes)
2.1 In Java, we use AES/GCM/NoPadding
to represent the AES-GCM
algorithm. For the encrypted output, we prefix the 16 bytes IV to the encrypted text (ciphertext), because we need the same IV for decryption.
Is this ok if IV is publicly known?
It is ok for IV to be publicly known, the only secret is the key, keep it private and confidential.
This example will use AES to encrypt a plain text Hello World AES-GCM
and later decrypt it back to the original plain text.
package com.mkyong.crypto.encryptor;
import com.mkyong.crypto.utils.CryptoUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/**
* AES-GCM inputs - 12 bytes IV, need the same IV and secret keys for encryption and decryption.
* <p>
* The output consist of iv, encrypted content, and auth tag in the following format:
* output = byte[] {i i i c c c c c c ...}
* <p>
* i = IV bytes
* c = content bytes (encrypted content, auth tag)
*/
public class EncryptorAesGcm {
private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding";
private static final int TAG_LENGTH_BIT = 128;
private static final int IV_LENGTH_BYTE = 12;
private static final int AES_KEY_BIT = 256;
private static final Charset UTF_8 = StandardCharsets.UTF_8;
// AES-GCM needs GCMParameterSpec
public static byte[] encrypt(byte[] pText, SecretKey secret, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
cipher.init(Cipher.ENCRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
byte[] encryptedText = cipher.doFinal(pText);
return encryptedText;
}
// prefix IV length + IV bytes to cipher text
public static byte[] encryptWithPrefixIV(byte[] pText, SecretKey secret, byte[] iv) throws Exception {
byte[] cipherText = encrypt(pText, secret, iv);
byte[] cipherTextWithIv = ByteBuffer.allocate(iv.length + cipherText.length)
.put(iv)
.put(cipherText)
.array();
return cipherTextWithIv;
}
public static String decrypt(byte[] cText, SecretKey secret, byte[] iv) throws Exception {
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
cipher.init(Cipher.DECRYPT_MODE, secret, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
byte[] plainText = cipher.doFinal(cText);
return new String(plainText, UTF_8);
}
public static String decryptWithPrefixIV(byte[] cText, SecretKey secret) throws Exception {
ByteBuffer bb = ByteBuffer.wrap(cText);
byte[] iv = new byte[IV_LENGTH_BYTE];
bb.get(iv);
//bb.get(iv, 0, iv.length);
byte[] cipherText = new byte[bb.remaining()];
bb.get(cipherText);
String plainText = decrypt(cipherText, secret, iv);
return plainText;
}
public static void main(String[] args) throws Exception {
String OUTPUT_FORMAT = "%-30s:%s";
String pText = "Hello World AES-GCM, Welcome to Cryptography!";
// encrypt and decrypt need the same key.
// get AES 256 bits (32 bytes) key
SecretKey secretKey = CryptoUtils.getAESKey(AES_KEY_BIT);
// encrypt and decrypt need the same IV.
// AES-GCM needs IV 96-bit (12 bytes)
byte[] iv = CryptoUtils.getRandomNonce(IV_LENGTH_BYTE);
byte[] encryptedText = EncryptorAesGcm.encryptWithPrefixIV(pText.getBytes(UTF_8), secretKey, iv);
System.out.println("\n------ AES GCM Encryption ------");
System.out.println(String.format(OUTPUT_FORMAT, "Input (plain text)", pText));
System.out.println(String.format(OUTPUT_FORMAT, "Key (hex)", CryptoUtils.hex(secretKey.getEncoded())));
System.out.println(String.format(OUTPUT_FORMAT, "IV (hex)", CryptoUtils.hex(iv)));
System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (hex) ", CryptoUtils.hex(encryptedText)));
System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (hex) (block = 16)", CryptoUtils.hexWithBlockSize(encryptedText, 16)));
System.out.println("\n------ AES GCM Decryption ------");
System.out.println(String.format(OUTPUT_FORMAT, "Input (hex)", CryptoUtils.hex(encryptedText)));
System.out.println(String.format(OUTPUT_FORMAT, "Input (hex) (block = 16)", CryptoUtils.hexWithBlockSize(encryptedText, 16)));
System.out.println(String.format(OUTPUT_FORMAT, "Key (hex)", CryptoUtils.hex(secretKey.getEncoded())));
String decryptedText = EncryptorAesGcm.decryptWithPrefixIV(encryptedText, secretKey);
System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText));
}
}
Output
Plain Text : Hello World AES-GCM
------ AES GCM Encryption ------
Input (plain text) :Hello World AES-GCM
Key (hex) :603d87185bf855532f14a77a91ec7b025c004bf664e9f5c6e95613ee9577f436
IV (hex) :bdb271ce5235996a0709e09c
Encrypted (hex) :bdb271ce5235996a0709e09c2d03eefe319e9329768724755c56291aecaef88cd1e6bdf72b8c7b54d75a94e66b0cd3
Encrypted (hex) (block = 16) :[bdb271ce5235996a0709e09c2d03eefe, 319e9329768724755c56291aecaef88c, d1e6bdf72b8c7b54d75a94e66b0cd3]
------ AES GCM Decryption ------
Input (hex) :bdb271ce5235996a0709e09c2d03eefe319e9329768724755c56291aecaef88cd1e6bdf72b8c7b54d75a94e66b0cd3
Input (hex) (block = 16) :[bdb271ce5235996a0709e09c2d03eefe, 319e9329768724755c56291aecaef88c, d1e6bdf72b8c7b54d75a94e66b0cd3]
Key (hex) :603d87185bf855532f14a77a91ec7b025c004bf664e9f5c6e95613ee9577f436
Decrypted (plain text) :Hello World AES-GCM
Plain Text : Hello World AES-GCM, Welcome to Cryptography!
------ AES GCM Encryption ------
Input (plain text) :Hello World AES-GCM, Welcome to Cryptography!
Key (hex) :ddc24663d104e1c2f81f11aef98156503dafdc435f81e3ac3d705015ebab095c
IV (hex) :b05d6aedf023f73b9e1e2d11
Encrypted (hex) :b05d6aedf023f73b9e1e2d11f6f5137d971aea8c5cdd5b045e0960eb4408e0ee4635cccc2dfeec2c13a89bd400f659be82dc2329e9c36e3b032f38bd42296a8495ac840b0625c097d9
Encrypted (hex) (block = 16) :[b05d6aedf023f73b9e1e2d11f6f5137d, 971aea8c5cdd5b045e0960eb4408e0ee, 4635cccc2dfeec2c13a89bd400f659be, 82dc2329e9c36e3b032f38bd42296a84, 95ac840b0625c097d9]
------ AES GCM Decryption ------
Input (hex) :b05d6aedf023f73b9e1e2d11f6f5137d971aea8c5cdd5b045e0960eb4408e0ee4635cccc2dfeec2c13a89bd400f659be82dc2329e9c36e3b032f38bd42296a8495ac840b0625c097d9
Input (hex) (block = 16) :[b05d6aedf023f73b9e1e2d11f6f5137d, 971aea8c5cdd5b045e0960eb4408e0ee, 4635cccc2dfeec2c13a89bd400f659be, 82dc2329e9c36e3b032f38bd42296a84, 95ac840b0625c097d9]
Key (hex) :ddc24663d104e1c2f81f11aef98156503dafdc435f81e3ac3d705015ebab095c
Decrypted (plain text) :Hello World AES-GCM, Welcome to Cryptography!
3. AES Password-Based encryption and decryption.
For password-based encryption, we can use the Password-Based Cryptography Specification (PKCS), defined RFC 8018, to generate a key from a given password.
For PKCS inputs:
- Password, you provide this.
- Salt – At least 64 bits (8 bytes) random bytes.
- Iteration Count – Recommend a minimum iteration count of 1,000.
What is salt and iteration count?
- The
salt
produces a broad set of keys for a given password. For example, if the salt is 128 bits, there will be as many as 2^128 keys for each password. Therefore, it increases the difficulty of rainbow attacks. Furthermore, the rainbow table that attackers build for one user’s password became useless for another user. - The
iteration count
increasing the cost of producing keys from a password, therefore increasing difficulty and slow down the speed of attacks.
3.1 For the encrypted output, we prefix the 12 bytes IV
and password salt
to the ciphertext, because we need the same IV and password salt (for secret key) for decryption. Furthermore, we use Base64
encoder to encode the encrypted text into a string representation, so that we can send the encrypted text or ciphertext in string format (was byte array).
Is this ok if password salt is publicly known?
It is the same with IV, and it is ok for password salt to be publicly known, the only secret is the key, keeping it private and confidential.
package com.mkyong.crypto.encryptor;
import com.mkyong.crypto.utils.CryptoUtils;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
/**
* AES-GCM inputs - 12 bytes IV, need the same IV and secret keys for encryption and decryption.
* <p>
* The output consist of iv, password's salt, encrypted content and auth tag in the following format:
* output = byte[] {i i i s s s c c c c c c ...}
* <p>
* i = IV bytes
* s = Salt bytes
* c = content bytes (encrypted content)
*/
public class EncryptorAesGcmPassword {
private static final String ENCRYPT_ALGO = "AES/GCM/NoPadding";
private static final int TAG_LENGTH_BIT = 128; // must be one of {128, 120, 112, 104, 96}
private static final int IV_LENGTH_BYTE = 12;
private static final int SALT_LENGTH_BYTE = 16;
private static final Charset UTF_8 = StandardCharsets.UTF_8;
// return a base64 encoded AES encrypted text
public static String encrypt(byte[] pText, String password) throws Exception {
// 16 bytes salt
byte[] salt = CryptoUtils.getRandomNonce(SALT_LENGTH_BYTE);
// GCM recommended 12 bytes iv?
byte[] iv = CryptoUtils.getRandomNonce(IV_LENGTH_BYTE);
// secret key from password
SecretKey aesKeyFromPassword = CryptoUtils.getAESKeyFromPassword(password.toCharArray(), salt);
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
// ASE-GCM needs GCMParameterSpec
cipher.init(Cipher.ENCRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
byte[] cipherText = cipher.doFinal(pText);
// prefix IV and Salt to cipher text
byte[] cipherTextWithIvSalt = ByteBuffer.allocate(iv.length + salt.length + cipherText.length)
.put(iv)
.put(salt)
.put(cipherText)
.array();
// string representation, base64, send this string to other for decryption.
return Base64.getEncoder().encodeToString(cipherTextWithIvSalt);
}
// we need the same password, salt and iv to decrypt it
private static String decrypt(String cText, String password) throws Exception {
byte[] decode = Base64.getDecoder().decode(cText.getBytes(UTF_8));
// get back the iv and salt from the cipher text
ByteBuffer bb = ByteBuffer.wrap(decode);
byte[] iv = new byte[IV_LENGTH_BYTE];
bb.get(iv);
byte[] salt = new byte[SALT_LENGTH_BYTE];
bb.get(salt);
byte[] cipherText = new byte[bb.remaining()];
bb.get(cipherText);
// get back the aes key from the same password and salt
SecretKey aesKeyFromPassword = CryptoUtils.getAESKeyFromPassword(password.toCharArray(), salt);
Cipher cipher = Cipher.getInstance(ENCRYPT_ALGO);
cipher.init(Cipher.DECRYPT_MODE, aesKeyFromPassword, new GCMParameterSpec(TAG_LENGTH_BIT, iv));
byte[] plainText = cipher.doFinal(cipherText);
return new String(plainText, UTF_8);
}
public static void main(String[] args) throws Exception {
String OUTPUT_FORMAT = "%-30s:%s";
String PASSWORD = "this is a password";
String pText = "AES-GSM Password-Bases encryption!";
String encryptedTextBase64 = EncryptorAesGcmPassword.encrypt(pText.getBytes(UTF_8), PASSWORD);
System.out.println("\n------ AES GCM Password-based Encryption ------");
System.out.println(String.format(OUTPUT_FORMAT, "Input (plain text)", pText));
System.out.println(String.format(OUTPUT_FORMAT, "Encrypted (base64) ", encryptedTextBase64));
System.out.println("\n------ AES GCM Password-based Decryption ------");
System.out.println(String.format(OUTPUT_FORMAT, "Input (base64)", encryptedTextBase64));
String decryptedText = EncryptorAesGcmPassword.decrypt(encryptedTextBase64, PASSWORD);
System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText));
}
}
Output
------ AES GCM Password-based Encryption ------
Input (plain text) :AES-GSM Password-Bases encryption!
Encrypted (base64) :KmrvjnMusJTQo/hB7T5BvlQpvi3bVbdjpZP51NT7I/enrIfSQuDfSK6iXgdPzvUP2IE54mwrKiyHqMkG8224lRZ9tXHcclmdh98I8b3B
------ AES GCM Password-based Decryption ------
Input (base64) :KmrvjnMusJTQo/hB7T5BvlQpvi3bVbdjpZP51NT7I/enrIfSQuDfSK6iXgdPzvUP2IE54mwrKiyHqMkG8224lRZ9tXHcclmdh98I8b3B
Decrypted (plain text) :AES-GSM Password-Bases encryption!
3.2 If password is not match, Java throws AEADBadTagException: Tag mismatch!
// change the password to something else
String decryptedText = EncryptorAesGcmPassword.decrypt(encryptedTextBase64, "other password");
System.out.println(String.format(OUTPUT_FORMAT, "Decrypted (plain text)", decryptedText));
Output
Exception in thread "main" javax.crypto.AEADBadTagException: Tag mismatch!
at java.base/com.sun.crypto.provider.GaloisCounterMode.decryptFinal(GaloisCounterMode.java:623)
at java.base/com.sun.crypto.provider.CipherCore.finalNoPadding(CipherCore.java:1118)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1055)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:855)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2207)
at com.mkyong.crypto.encryptor.EncryptorAesGcmPassword.decrypt(EncryptorAesGcmPassword.java:88)
at com.mkyong.crypto.encryptor.EncryptorAesGcmPassword.main(EncryptorAesGcmPassword.java:109)
4. AES File encryption and decryption.
This example is an AES password-based file encryption. The ideas are the same, but we need some IO classes to work with the resources or files.
Here’s a text file, at the resources
folder.
This is line 1.
This is line 2.
This is line 3.
This is line 4.
This is line 5.
This is line 9.
This is line 10.
4.1 This example is similar to 3.1 EncryptorAesGcmPassword.java
, with some minor changes like return a byte[]
instead of base64 encoded string.
public static byte[] encrypt(byte[] pText, String password) throws Exception {
//...
// prefix IV and Salt to cipher text
byte[] cipherTextWithIvSalt = ByteBuffer.allocate(iv.length + salt.length + cipherText.length)
.put(iv)
.put(salt)
.put(cipherText)
.array();
// it works, even if we save the based64 encoded string into a file.
// return Base64.getEncoder().encodeToString(cipherTextWithIvSalt);
// we save the byte[] into a file.
return cipherTextWithIvSalt;
}
Add encryptFile
and decryptFile
to work with the file.
public static void encryptFile(String fromFile, String toFile, String password) throws Exception {
// read a normal txt file
byte[] fileContent = Files.readAllBytes(Paths.get(ClassLoader.getSystemResource(fromFile).toURI()));
// encrypt with a password
byte[] encryptedText = EncryptorAesGcmPasswordFile.encrypt(fileContent, password);
// save a file
Path path = Paths.get(toFile);
Files.write(path, encryptedText);
}
public static byte[] decryptFile(String fromEncryptedFile, String password) throws Exception {
// read a file
byte[] fileContent = Files.readAllBytes(Paths.get(fromEncryptedFile));
return EncryptorAesGcmPasswordFile.decrypt(fileContent, password);
}
4.2 Read the above readme.txt
file from the classpath, encrypt it, and the encrypted data to a new file c:\test\readme.encrypted.txt
.
String password = "password123";
String fromFile = "readme.txt"; // from resources folder
String toFile = "c:\\test\\readme.encrypted.txt";
// encrypt file
EncryptorAesGcmPasswordFile.encryptFile(fromFile, toFile, password);
Output
4.3 Read the encrypted file, decrypt it, and print the output.
String password = "password123";
String toFile = "c:\\test\\readme.encrypted.txt";
// decrypt file
byte[] decryptedText = EncryptorAesGcmPasswordFile.decryptFile(toFile, password);
String pText = new String(decryptedText, UTF_8);
System.out.println(pText);
Output
This is line 1.
This is line 2.
This is line 3.
This is line 4.
This is line 5.
This is line 9.
This is line 10.
P.S The AES image encryption is the same concept.
Download Source Code
$ git clone https://github.com/mkyong/core-java
$ cd java-crypto
Let me know if the article needs improvement. Thanks.
References
- Wikipedia – Cipher JavaDoc
- Wikipedia – Cipher Block Chaining (CBC)
- Wikipedia – Galois/Counter Mode (GCM)
- Oracle – KeyGenerator Algorithms JavaDoc
- Java – How to generate a random 12 bytes?
- Why shouldn’t I use ECB encryption?
- Spring Security Crypto Module
- Wikipedia – PBKDF2
- RFC 8018 – PKCS
- Java – How to join and split byte array
- Java Security Standard Algorithm Names
- NIST – Recommendation for Galois/Counter Mode (GCM)
Hi i have these errors, could you help
Exception in thread “main” java.lang.NullPointerException: Cannot invoke “java.net.URL.toURI()” because the return value of “java.lang.ClassLoader.getSystemResource(String)” is null
at AES.EncryptorAesGcmPasswordFile.encryptFile(EncryptorAesGcmPasswordFile.java:93)
at AES.EncryptorAesGcmPasswordFile.main(EncryptorAesGcmPasswordFile.java:121)
Can we able to get AES key by having only iv key and cipher key
Very nice, clear and useful article.
In my code, using buffer I got an exception: javax.crypto.AEADBadTagException: Tag mismatch! when I use update during the decryption. My code works fine with AES/CTR and works well with AES/GCM when there is only one doFinal. Any idea?
Hello mkyonng
Is there any way we can do encryption of a file in javascript with crypto js AES and decrypt the same in Java with AES?
I am able to encrypt the file but not able to decrypt the file in java side
Hi, Thanks for saving my day. After spending the whole day. I got this solution. which makes my day
Very good article, thanks! Just one typo: “2.1 In Java, we use AES/CBC/PKCS5Padding to represent the AES-GCM algorithm.” I think it should be “2.1 In Java, we use AES/GCM/NoPadding to represent the AES-GCM algorithm.”
Thanks for your help. Article is updated.
The initial draft is using both
AES/CBC/PKCS5Padding
andAES/GCM/NoPadding
, but the final draft looks complicated. In the end, I decided to focus on AES GCM.This is great, I have made a modified version of this using CipherInputStream/CipherOutputStream. My question is, would it not be more flexible when writing the iv/salt during encryption process to also write out their bit depth, i.e. [IV-LENGTH-BYTES][IV-VALUE][SALT_LENGTH_BYTES][SALT_VALUE], this way, when it comes time to decode, it can be decoded with a ‘different’ version of the code, that changed the encryption details. I suppose by that logic this could be extended to include ‘password-iterations/key_length), but that may reveal too much, and be come security issue?
Hello Mkyong,
Thank you very much for the article. I would like to know that a file encrypted in this method in java can be decrypted in Python. If it’s possible how can we find the key which is used to encrypt the file?
Veracode is flagging a couple of things here. one thing it flags is the the 12 byte IV — it wants to see 96. I think it sees it as each bit being stored in each byte. It’s also flagging the iterationCount… they recommend 200000 iterations or more.
See article at https://www.veracode.com/blog/research/encryption-and-decryption-java-cryptography
And corresponding example: https://github.com/1MansiS/java_crypto/blob/master/cipher/SecuredGCMUsage.java
It could that Veracode has it wrong… all other examples I see on the Web use 12 bytes like you. I’d be curious to get your thoughts mkyong. Thank you.
Thanks for the practical example. FYI, I scanned this code with veracode and it recommends using IV tLen of size 96 and iteration count of 200,000 or more.
Hi mkyong,
I am using this method to Encrypt and Decrypt my data into DB, but i am facing one issue. While searching for data i am not able to retrieve it. because every time encryption is generating different string and what i have already saved in DB is different.
Let me give one example :- while adding an document into repository, I am encrypting document’s title, but while i am searching, in a search criteria i am entering plain text(Document’s title) which i have entered at the time of adding document into repository. But i am getting different encrypt string for that. so i am unable to fetch my document. Can you please give some solution on that?
Only encrypt what is important, in your example, try to encrypt the document content, and search by the document title.
For search criteria, I will suggest you “hash” the document title, instead of encrypting it.
First of all, thank you for all this explanation.
i Have a problem, i want to use AES file encryption and decryption but i want to generate et secret key automatically…i don’t want to add it by myself.
Please How can i do it ?
He already did it on another project…You just have to use key.generator with random number.
Should this be in a singleton implementation – SecretKeyFactory factory = SecretKeyFactory.getInstance(“PBKDF2WithHmacSHA256”);
Looks like this takes a bit of time to get instantiated.
Very useful. Thank you very much. I’m new to Java, so I’m sorry if my question is wrong. How to verify when decoding a file if an incorrect password is entered. I know that it will make an exception, but how to compare in this example if password is correct?
I’ve already found a solution. Thank you.
Hi, my question is a bit stupid. The import com.mkyong.crypto.utils.CryptoUtils; says that doesn’t exist, and I’m trying for couple of hours to find how to download it or something, and I can’t find anything. Please someone do me a favor and help me out. Have a great day.
https://github.com/mkyong/core-java/tree/master/java-crypto/src/main/java/com/mkyong/crypto/utils
A very good article. I have one minor suggestion. I would not use SecureRandom.getInstanceStrong() to generate symmetric keys in most scenarios. The “strong” SecureRandom instances are designed to provide long-lived secrets, and therefore are allowed to be much slower. For a single use AES key, it is probably best to just use new SecureRandom().
Very Nice and Clear Article. How can we use AES for XML specifically. If possible can you please publish a tutorial about it.
Do you mean AES encrypt the XML content or?
How to run I have 8 error
hi mykong,
Great Article!
Does AES – CCM algorithm works in the same way?
Do you have any inputs for interaction with BLE security layers for example?
Hi mykong,
If i need to encrypt, i followed the implementation as step 2 showed, but later I need to decrypt from outside this method.
The idea is to generate this encrypted value and later from an outside method, decrypt the values.
In step 2 you use
And I am able to decrypt but only having the SecretKey, that was inside this method generated.
If an outside method (another API) would like to decrypt this values, how can i get the SecretKey value in order to get the info.
Thank you for your help. I would assume that using the method instead of the previous one
But not sure if my thinking is right.
The outside method (another API) needs to know the secret or private key for decryption.
It depends on how you design the system, base64 the secret key, and save it somewhere (both APIs sharing the same database?) for decryption.
i know we have Base64 example, but we are looking to do this but with AES-256, because its more secure.
I do not understand what pText and cText are for the AES Password-Based encryption and decryption
pText = plainText
cText = ciphertext (encrypted text)
thank you, and the password is the secret key 😀
SHA1PRNG, there is a SeedGenerator which does various things depending on the configuration.
If java.security.egd or securerandom.source point to “file:/dev/random” or “file:/dev/urandom”, we will use NativeSeedGenerator, which calls super() which calls SeedGenerator.URLSeedGenerator(/dev/random). (A nested class within SeedGenerator.) The only things that changed in this bug was that urandom will also trigger use of this code path.
If those properties point to another URL that exists, we’ll initialize SeedGenerator.URLSeedGenerator(url). This is why “file:///dev/urandom”, “file:/./dev/random”, etc. will work.
SecureRandom.getInstanceStrong()
SecureRandom. GetInstanceStrong () will cause congestion
n SHA1PRNG, there is a SeedGenerator which does various things depending on the configuration.
If java.security.egd or securerandom.source point to “file:/dev/random” or “file:/dev/urandom”, we will use NativeSeedGenerator, which calls super() which calls SeedGenerator.URLSeedGenerator(/dev/random). (A nested class within SeedGenerator.) The only things that changed in this bug was that urandom will also trigger use of this code path.
If those properties point to another URL that exists, we’ll initialize SeedGenerator.URLSeedGenerator(url). This is why “file:///dev/urandom”, “file:/./dev/random”, etc. will work.
Thanks for this article!
One typo in
2. AES encryption and decryption.
The AES-GSM is the most widely used authenticated cipher.
That should be AES-GCM
The initialisation vector for GCM shall have 12bit length, you can remove the question mark in the code sample.
Thanks again for your explicit and clear example!