I have found the code of AES encryption and decryption on git hub as bellow:
public static String 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 new String(Base64.getEncoder().encode(encryptedIVAndText));
}
// decrypt method
public static String decrypt(String encrypted, String key) throws Exception {
int ivSize = 16;
int keySize = 16;
byte[] encryptedIvTextBytes = Base64.getDecoder().decode(encrypted);
// 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);
}
I've found the information that java determine aes algorithm 128 or 256 by key size, so I have modify the code above by changing fixed value of "keySize" to key.length() as bellow:
public static String encryptAes(String plainText, String key){
byte[] clean = plainText.getBytes();
String str = null;
int keyLen = key.length();
try{
// 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[keyLen];
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);
str = new String(Base64.getEncoder().encode(encryptedIVAndText));
}
catch (Exception e) {
// TODO: handle exception
System.out.println("Error");
}
return str;
}
public static String decryptAes(String encrypted, String key){
int ivSize = 16;
int keySize = key.length();
String str = null;
try{
byte[] encryptedIvTextBytes = Base64.getDecoder().decode(encrypted);
// 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);
str = new String(decrypted);
}
catch (Exception e) {
// TODO: handle exception
System.out.println("Error");
}
return str;
}
And here is Main with and input
public static void main (String[] args){
String txtInput = "11700000108";
String key256 = "SxKFF2Kunz7tjyUZ4sb7TzzZBR83e8FL"; //length of key will be fixed as 32
String cipher256 = encryptAes(txtInput, key256);
System.out.println("CipherAes256: " + cipher256);
String key128 = "RfZVnF76FshjN46e"; //length of key will be fixed as 16
String cipher128 = encryptAes(txtInput, key128);
System.out.println("CipherAes128: " + cipher128);
}
But the result's length of cipher256 and cipher128 are same (44 characters in this example) I'm not sure if I need to make any further changes.
Please give me advice, Thanks.
Related
I am trying to implement encryption in Flutter, I'm using java as a backend and dart for the mobile application. I have taken code from this Encryption in Java and Decryption in Flutter (AES-256)
But it only supplies decryption in Flutter, and I want to implement encryption in Flutter so the Java code can decrypt it.
Can you help me by providing the code for encryption in Flutter?
This is the java code for encryption and decryption.
public class EncryptionService {
public String encrypt(String item) throws Exception {
byte[] ivBytes;
String password = "Hello";
/* you can give whatever you want for password. This is for testing purpose */
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
random.nextBytes(bytes);
byte[] saltBytes = bytes;
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65556, 256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
System.out.println("saltBytes : " + saltBytes);
// encrypting the word
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
System.out.println("ivBytes : " + ivBytes);
byte[] encryptedTextBytes = cipher.doFinal(item.getBytes("UTF-8"));
// prepend salt and vi
byte[] buffer = new byte[saltBytes.length + ivBytes.length + encryptedTextBytes.length];
System.arraycopy(saltBytes, 0, buffer, 0, saltBytes.length);
System.arraycopy(ivBytes, 0, buffer, saltBytes.length, ivBytes.length);
System.arraycopy(encryptedTextBytes, 0, buffer, saltBytes.length + ivBytes.length, encryptedTextBytes.length);
return new Base64().encodeToString(buffer);
}
public String decrypt(String encryptedText) throws Exception {
String password = "Hello";
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// strip off the salt and iv
ByteBuffer buffer = ByteBuffer.wrap(new Base64().decode(encryptedText));
byte[] saltBytes = new byte[20];
buffer.get(saltBytes, 0, saltBytes.length);
byte[] ivBytes1 = new byte[cipher.getBlockSize()];
buffer.get(ivBytes1, 0, ivBytes1.length);
byte[] encryptedTextBytes = new byte[buffer.capacity() - saltBytes.length - ivBytes1.length];
buffer.get(encryptedTextBytes);
// Deriving the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65556, 256);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes1));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
}
Dart implementation for decryption is something like this
class EncryptionHelper {
static String decrypt(
String ciphertext,
) {
Uint8List ciphertextlist = base64.decode(ciphertext);
var salt = ciphertextlist.sublist(0, 20);
var iv = ciphertextlist.sublist(20, 20 + 16);
var encrypted = ciphertextlist.sublist(20 + 16);
Uint8List key = generateKey("Hello", salt);
CBCBlockCipher cipher = new CBCBlockCipher(new AESFastEngine());
ParametersWithIV<KeyParameter> params =
new ParametersWithIV<KeyParameter>(new KeyParameter(key), iv);
PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>
paddingParams =
new PaddedBlockCipherParameters<ParametersWithIV<KeyParameter>, Null>(
params, null);
PaddedBlockCipherImpl paddingCipher =
new PaddedBlockCipherImpl(new PKCS7Padding(), cipher);
paddingCipher.init(false, paddingParams);
var val = paddingCipher.process(encrypted);
return new String.fromCharCodes(val);
}
static Uint8List generateKey(String passphrase, Uint8List salt) {
Uint8List passphraseInt8List = Uint8List.fromList(passphrase.codeUnits);
KeyDerivator derivator =
PBKDF2KeyDerivator(HMac(SHA1Digest(), 64)); // 64 byte block size
Pbkdf2Parameters params =
Pbkdf2Parameters(salt, 65556, 32); // 32 byte key size
derivator.init(params);
return derivator.process(passphraseInt8List);
}
}
Why don't you use pointcastle ?
it is a dart porting of Bouncy castle and, as I can read in their page, there is yet the implementation of the AES algorithm for decrypt/encrpyt.
Moreover use :
https://pub.dev/packages/encrypt
that is a convenient wrapper on top of pointcastle.
I am trying to encrypt and decrypt data using CBC mode.
Here, I am first reading the data from a plaintext.txt file and writing the output which is the data of the plaintext.txt to another ciphertext.txt file. While trying to decrypt, I am reading the encrypted data from the file into bytes but for some reason, it's giving me an error. Can someone help me solving this?
Here is my encryption function
// The encryption Function CBC MODE
public static byte[] encrypt(String plainText, String key) throws Exception
{
// Loading the secret key from the Key.txt file
String fileName="../data/key.txt";
try
{
BufferedReader in = new BufferedReader(new FileReader(fileName)); // Initialize a Buffer reader
key = in.readLine(); // Reading the data from txt file
}
//error message if the file is not found
catch(FileNotFoundException ex)
{
System.out.println("Unable to open file '" + fileName + "'");
}
catch(IOException ex)
{
System.out.println("Error reading file '" + fileName + "'");
}
byte[] clean = plainText.getBytes(); //Getting the data in bytes from the plain text
// Generating IV.
//From the initialization vector, we create an IvParameterSpec which is required when creating the Cipher.
int ivSize = 16;
byte[] iv = new byte[ivSize];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
//System.out.println("The Iv is = "+ivParameterSpec);
// Hashing key.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(key.getBytes("UTF-8"));
byte[] keyBytes = new byte[32];
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);
try
{
PrintWriter writer = new PrintWriter("../data/ciphertext.txt");
writer.println(encryptedIVAndText);
writer.close();
}
catch(Exception ex)
{
System.out.println(ex);
System.out.println("File is not there");
}
return encryptedIVAndText;
}
And here is my decryption function.
// Decrypting fucntion CBC mode
public static String decrypt(byte[] encryptedIvTextBytes, String key) throws Exception
{
FileInputStream encryptedTextFis = new FileInputStream("../data/ciphertext.txt");
byte[] encText = new byte[encryptedTextFis.available()];
int lol = encryptedTextFis.available();
System.out.println("lol "+ lol);
encryptedTextFis.read(encText);
encryptedTextFis.close();
// encrypted = readFile("../data/ciphertext.txt", StandardCharsets.UTF_8).getBytes();
encryptedIvTextBytes = encText;
//System.out.println("..........??????");
String fileName="../data/key.txt";
String fileName2="../data/ciphertext.txt";
try
{
BufferedReader in = new BufferedReader(new FileReader(fileName));
BufferedReader in2 = new BufferedReader(new FileReader(fileName2));
key = in.readLine();
// byte[] array = Files.readAllBytes(new File("/path/to/file").toPath());
}
//error message if the file is not found
catch(FileNotFoundException ex)
{
System.out.println("Unable to open file '" + fileName + "'");
}
catch(IOException ex)
{
System.out.println("Error reading file '" + fileName + "'");
}
int ivSize = 16;
int keySize = 32;
//System.out.println("..........??????");
// Extract IV.
byte[] iv = new byte[ivSize];
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
System.out.println("..........??????");
// Extract encrypted part.
int encryptedSize = encryptedIvTextBytes.length - ivSize;
byte[] encryptedBytes = new byte[encryptedSize];
System.arraycopy(encryptedIvTextBytes, ivSize, encryptedBytes, 0, encryptedSize);
System.out.println("..........??????");
// 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); //Decrypting the encrypted data to a cipherblock data
byte[] decrypted = cipherDecrypt.doFinal(encryptedBytes); // Decrypting the cipher dadat to Plaintext
//Writing the output to a txt file
try
{
PrintWriter writer = new PrintWriter("../data/result.txt");
writer.println(new String(decrypted));
writer.close();
}
catch(Exception ex)
{
System.out.println(ex);
System.out.println("File is not there");
}
return new String(decrypted); //Returning the decrypted data to main function
}
The output of the encrypted text file is of the form [B#3159c4b8.
I am getting the below error.
It seems exception is here:
System.arraycopy(encryptedIvTextBytes, 0, iv, 0, iv.length);
The length of array encryptedIvTextBytes is 11 (as you say and the result is shown also). Now you want to copy 16 (as the length of iv) bytes from encryptedIvTextBytes.
But the main reason is from this note that your saving method to save encrypted data is not valid. Encrypted data may contain some bytes which are not a readable character. When you save encrypted data as a string such bytes are dropped. To solve this problem see #Maarten and #MS90 comments.
Here is a code that suits your needs:
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws Exception {
String key = "abcdefghijklmop";// you could store it somewhere ...
justToMakePlainTextFile();
byte[] encrypted = encrypt("plaintext",key);
decrypt(encrypted, key);
}
public static void justToMakePlainTextFile() {
try {
RandomAccessFile randomAccessFile = new RandomAccessFile("plaintext", "rw");
FileChannel fileChannel = randomAccessFile.getChannel();
String randomText = "Ho-ho-ho-ho! This is going to be a nice weekend and I am going to swim soon.";
byte[] bytes = randomText.getBytes();
ByteBuffer byteBuffer = ByteBuffer.allocate(randomText.length());//alocate new ByteBuffer of size randomeText.length
byteBuffer.put(bytes);
byteBuffer.flip();
fileChannel.write(byteBuffer);
randomAccessFile.close();
fileChannel.close();
} catch (IOException ioE) {
System.err.println("JVM reported an error! Take a look: " + ioE);
}
}
public static byte[] encrypt(String file, String key) throws Exception {
RandomAccessFile reader = new RandomAccessFile(file, "r");
FileChannel channel = reader.getChannel();
int bufferSize = 1024;
if (bufferSize > channel.size()) {
bufferSize = (int) channel.size();
}
ByteBuffer buff = ByteBuffer.allocate(bufferSize);
channel.read(buff);
buff.flip();
byte[] clean = buff.array();
channel.close();
reader.close();
// 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 void 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);
try {
RandomAccessFile randomAccessFile = new RandomAccessFile("ciphertext", "rw");
FileChannel fileChannel = randomAccessFile.getChannel();
byte[] bytes = decrypted;
ByteBuffer byteBuffer = ByteBuffer.allocate(decrypted.length);//alocate new ByteBuffer of size randomeText.length
byteBuffer.put(bytes);
byteBuffer.flip();
fileChannel.write(byteBuffer);
randomAccessFile.close();
fileChannel.close();
} catch (IOException ioE) {
System.err.println("JVM reported an error! Take a look: " + ioE);
}
}
ciphertext and plaintext files are in your projects home folder created.
I have encrypted the string in php. Decrypted successfully from php and node.js. In addition, it must be decrypted by java.
Help me an example of decrypting from java?
PHP Encrypt code
/* encrypt */
$encryption_method = 'aes-256-cbc';
$secretHash = "d95acd54c6a821ff32c52825b931c194";
$iv_size = openssl_cipher_iv_length($encryption_method);
$iv = openssl_random_pseudo_bytes($iv_size);
//encrypt
$encryptedMessage = openssl_encrypt($new_token, $encryption_method, $secretHash, 0, $iv);
//Concatenate iv with data
$ciphertext = bin2hex($iv).$encryptedMessage;
/* decrypt the cipher */
$iv_size = openssl_cipher_iv_length($encryptionMethod);
$iv = hex2bin(substr($encryptedMessageWithIv, 0, $iv_size * 2));
$decryptedMessage = openssl_decrypt(substr($encryptedMessageWithIv, $iv_size * 2), $encryptionMethod, $secretHash, 0, $iv);
Below is the encryption and decryption process for a string using AES algorithm.
private static final String key = "aesEncryptionKey";
private static final String initVector = "encryptionIntVec";
public static String encrypt(String value) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(value.getBytes());
return Base64.encodeBase64String(encrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
public static String decrypt(String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] original = cipher.doFinal(Base64.decodeBase64(encrypted));
return new String(original);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
In case init vector is not known, try using below code segment.
public byte[] decrypt(String encryptedString) throws DataLengthException, InvalidCipherTextException {
byte[] input = encryptedString.getBytes("UTF-8");
CBCBlockCipher cbcBlockCipher = new CBCBlockCipher(new AESEngine());
SecureRandom random = new SecureRandom();;
KeyParameter key = new KeyParameter("$secretHash".getBytes());// your key string
BlockCipherPadding blockCipherPadding = new PKCS7Padding();;
PaddedBufferedBlockCipher pbbc = new PaddedBufferedBlockCipher(cbcBlockCipher, blockCipherPadding);
int blockSize = cbcBlockCipher.getBlockSize(); // Make sure this block size is same as that used while encrypting the string.
int inputOffset = 0;
int inputLength = input.length;
int outputOffset = 0;
byte[] initializationVector = new byte[blockSize];
System.arraycopy(input, 0, initializationVector, 0, blockSize);
inputOffset += blockSize;
inputLength -= blockSize;
pbbc.init(encrypt, new ParametersWithIV(key, initializationVector));
byte[] output = new byte[pbbc.getOutputSize(inputLength) + outputOffset];
int outputLength = outputOffset + pbbc.processBytes(input, inputOffset, inputLength, output, outputOffset);
outputLength += pbbc.doFinal(output, outputLength);
return Arrays.copyOf(output, outputLength);
}
Just in case it helps someone in the future: encryption with AES/CBC/PKCS5PADDING along with the generation of a dynamic IV that is appended to the final ciphertext in Java can be done through the following code:
Encryption (JAVA)
public String encryptPlainText(String plainText) {
String cipherText = "";
try {
String keyString = "examplesecretkeyexamplesecretkey";
//Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy
Security.setProperty("crypto.policy", "unlimited");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec keyspec = new SecretKeySpec(keyString.getBytes(), "AES");
byte[] v = new byte[16];
new SecureRandom().nextBytes(v);
IvParameterSpec iv = new IvParameterSpec(v);
cipher.init(Cipher.ENCRYPT_MODE, keyspec, iv);
byte[] cipherTextByteArray = cipher.doFinal(plainText.getBytes());
//appending iv to ciphertext without any additional libraries to handle the concatenation of the two byte arrays
byte[] ivWithCipherTextByteArray = new byte[v.length + cipherTextByteArray.length];
System.arraycopy(v, 0, ivWithCipherTextByteArray, 0, v.length);
System.arraycopy(cipherTextByteArray, 0, ivWithCipherTextByteArray, v.length, cipherTextByteArray.length);
cipherText = new String(Base64.getEncoder().encode(ivWithCipherTextByteArray));
} catch (Exception e) {
LOG.info("Exception", e);
}
return cipherText;
}
Decryption of the cipherText obtained with the code above can be implemented in the following way:
Decryption (JAVA)
public static String decryptCipherText(String cipherText) {
String plainText="";
try {
String keyString = "examplesecretkeyexamplesecretkey";
Security.setProperty("crypto.policy", "unlimited");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec keyspec = new SecretKeySpec(keyString.getBytes(), "AES");
byte[] cipherTextByteArray = Base64.getDecoder().decode(cipherText);
//initialize the IvParameterSpec with the first 16 bytes of the cipherText
IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(cipherTextByteArray, 0, 16));
//cipherText to decrypt is now the original one with the first 16 bytes removed (the IV used above)
cipherTextByteArray = Arrays.copyOfRange(cipherTextByteArray, 16, cipherTextByteArray.length);
cipher.init(Cipher.DECRYPT_MODE, keyspec, iv);
plainText = new String(cipher.doFinal(cipherTextByteArray));
} catch (Exception e) {
LOG.info("Exception", e);
}
return plainText;
}
public static String decryption(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);
}
My error is illegal Block Size Exception. Am I missing something? How can I correct I don't know. I tried convert to BAse64. But my error's increased. This code better my the others.
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:936)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:847)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at mysafe.MySafe.decryption(MySafe.java:171)
at mysafe.MySafe.main(MySafe.java:55)
C:\Users\Tuba\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53:
Java returned: 1
I am trying to use AES/GCM/NoPadding for encryption in Java8. But I can't figure out why I am having a AEADBadTagException when decrypting.
Here's my code:
private final int GCM_IV_LENGTH = 12;
private final int GCM_TAG_LENGTH = 16;
private static String encrypt(String privateString, SecretKey skey) {
byte[] iv = new byte[GCM_IV_LENGTH];
(new SecureRandom()).nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));
byte[] encrypted = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
Base64Encoder encoder = new Base64Encoder();
String encoded = encoder.encode(encrypted);
return encoded;
}
private static String decrypt(String encrypted, SecretKey skey) {
Base64Decoder decoder = new Base64Decoder();
String decoded = encoder.encode(encrypted);
byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(decoded, GCM_IV_LENGTH, decoded.length - GCM_IV_LENGTH);
String newString = new String(ciphertext, "UTF8");
return newString;
}
Hope someone can help me fix this exception. Thanks!
I've corrected a few typos, and used Java 8's base64 utilities, and it seems to work fine for me. Here is my version and you can compare it to yours.
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;
public class Main {
private final static int GCM_IV_LENGTH = 12;
private final static int GCM_TAG_LENGTH = 16;
private static String encrypt(String privateString, SecretKey skey) throws Exception {
byte[] iv = new byte[GCM_IV_LENGTH];
(new SecureRandom()).nextBytes(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.ENCRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(privateString.getBytes("UTF8"));
byte[] encrypted = new byte[iv.length + ciphertext.length];
System.arraycopy(iv, 0, encrypted, 0, iv.length);
System.arraycopy(ciphertext, 0, encrypted, iv.length, ciphertext.length);
String encoded = Base64.getEncoder().encodeToString(encrypted);
return encoded;
}
private static String decrypt(String encrypted, SecretKey skey) throws Exception {
byte[] decoded = Base64.getDecoder().decode(encrypted);
byte[] iv = Arrays.copyOfRange(decoded, 0, GCM_IV_LENGTH);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec ivSpec = new GCMParameterSpec(GCM_TAG_LENGTH * Byte.SIZE, iv);
cipher.init(Cipher.DECRYPT_MODE, skey, ivSpec);
byte[] ciphertext = cipher.doFinal(decoded, GCM_IV_LENGTH, decoded.length - GCM_IV_LENGTH);
String result = new String(ciphertext, "UTF8");
return result;
}
public static void main(String[] args) throws Exception {
SecretKey key = new SecretKeySpec(new byte[16], "AES"); // key is 16 zero bytes
String s = decrypt(encrypt("This is the first string to test", key), key);
System.out.println(s);
}
}