Skip to content

Instantly share code, notes, and snippets.

@itarato
Created September 28, 2014 18:59
Show Gist options
  • Star 60 You must be signed in to star a gist
  • Fork 21 You must be signed in to fork a gist
  • Save itarato/abef95871756970a9dad to your computer and use it in GitHub Desktop.
Save itarato/abef95871756970a9dad to your computer and use it in GitHub Desktop.
Java AES CBC encryption example
package com.company;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.SecureRandom;
public class Main {
public static void main(String[] args) throws Exception {
String key = "abcdefghijklmop";
String clean = "Quisque eget odio ac lectus vestibulum faucibus eget.";
byte[] encrypted = encrypt(clean, key);
String decrypted = decrypt(encrypted, key);
}
public static byte[] encrypt(String plainText, String key) throws Exception {
byte[] clean = plainText.getBytes();
// Generating IV.
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Hashing key.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes("UTF-8"));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// Encrypt.
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(clean);
// Combine IV and encrypted part.
byte[] encryptedIVAndText = new byte[ivSize + encrypted.length];
System.arraycopy(iv, 0, encryptedIVAndText, 0, ivSize);
System.arraycopy(encrypted, 0, encryptedIVAndText, ivSize, encrypted.length);
return encryptedIVAndText;
}
public static String decrypt(byte[] encryptedIvTextBytes, String key) throws Exception {
int ivSize = 16;
int keySize = 16;
// Extract IV.
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Extract encrypted part.
int encryptedSize = encryptedIvTextBytes.length - ivSize;
byte[] encryptedBytes = new byte[encryptedSize];
System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);
// Hash key.
byte[] keyBytes = new byte[keySize];
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(key.getBytes());
System.arraycopy(md.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
// Decrypt.
Cipher cipherDecrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes);
return new String(decrypted);
}
}
@jamshoo
Copy link

jamshoo commented Dec 12, 2017

nice

@samuel-sflima
Copy link

Nice job !

@maztan
Copy link

maztan commented Feb 20, 2018

@yegermals
Copy link

i ma doing a thesis work in my base paper i got this concept
FileEncrypt(File)—It encrypts the File with Convergent Encryption using 256-bit AES algorithm in cipher block chaining (CBC) mode, where the con-vergent key is from SHA-256 Hashing of the file

so is this code is relly helps me ?

@patrickfav
Copy link

// Hashing key.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes("UTF-8"));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

This is really not a good way to derive a key. Look into proper KDF like HKDF: https://en.wikipedia.org/wiki/HKDF

@tsk0707
Copy link

tsk0707 commented Apr 30, 2020

but sir block diagram of CBC says iv should be added with original text and then need to be encrypted

@OmarBasem
Copy link

OmarBasem commented Jul 3, 2020

Thank you for that!
I think the following is more secure for generating secret key from password:
KeySpec spec = new PBEKeySpec(pass.toCharArray(), salt, 65536, 256); SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); byte[] secKey = f.generateSecret(spec).getEncoded(); SecretKeySpec secretKeySpec = new SecretKeySpec(secKey, "AES");

@akkishah1993
Copy link

@tsk0707
This code is working fine in this way. Like there is the main method and from that main method encrypt and decrypt both methods are getting called in single-shot so it's working fine as we are passing combined IV and encrypted text at a time in decrypt method. But how to handle this in real-life projects. For Example in my project, there is a mechanism like while Create Partner method is called, data should be encrypted and saved in the database. When I call the Get Partner method that encrypted data come back and it needs to be decrypted and returned to the client. Now, In my case, while decrypting how to get that combination of IV and Encrypted Bytes? Here we can not call encrypt method again because to call encrypt method we need plaintext which is already encrypted and stored in the database when we called Create method. So, here I got stuck while decryption process. Please do the needful.

@wrov
Copy link

wrov commented May 21, 2021

Thank you!
However, there seems to be a mistake in the code:
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes("UTF-8"));
byte[] keyBytes = new byte[16];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);

The digest is 32 bytes long, not 16! The code cuts off half of the key.
The fix is simple:
byte[] keyBytes = new byte[32];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment