Related
I am looking for any sample java code that will decrypt the messages encrypted using "openssl enc -aes-256-cbc) -a -salt" command provided the key is known.
https://pastebin.com/YiwbCAW8
So far i was able to get the following java code that encrypts and also decrypts the message. But i am not able to decrypt the encrypted message using openssl command. Getting "Bad Magic Number" error. Any idea ?
Encrypt the message using the code >
Encrypt("sample text", "test$password") = "i+5zkPPgnDdV7fr/w8uHkw=="
Decrypt("i+5zkPPgnDdV7fr/w8uHkw==", "test$password") = "sample text"
Decrypt the message using openssl >
F:\cipher>echo i+5zkPPgnDdV7fr/w8uHkw== | openssl aes-256-cbc -a -salt -d
enter aes-256-cbc decryption password:
bad magic number
import java.security.spec.KeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class AES {
private static final byte[] SALT = {
(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32,
(byte) 0x56, (byte) 0x35, (byte) 0xE3, (byte) 0x03
};
private static final int ITERATION_COUNT = 65536;
private static final int KEY_LENGTH = 256;
private Cipher ecipher;
private Cipher dcipher;
AES(String passPhrase) throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(passPhrase.toCharArray(), SALT, ITERATION_COUNT, KEY_LENGTH);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
ecipher.init(Cipher.ENCRYPT_MODE, secret);
dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = ecipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
dcipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
}
public String encrypt(String encrypt) throws Exception {
byte[] bytes = encrypt.getBytes("UTF8");
byte[] encrypted = encrypt(bytes);
return Base64.getEncoder().encodeToString(encrypted);
}
public byte[] encrypt(byte[] plain) throws Exception {
return ecipher.doFinal(plain);
}
public String decrypt(String encrypt) throws Exception {
byte[] bytes = Base64.getDecoder().decode(encrypt);
byte[] decrypted = decrypt(bytes);
return new String(decrypted, "UTF8");
}
public byte[] decrypt(byte[] encrypt) throws Exception {
return dcipher.doFinal(encrypt);
}
public static void main(String[] args) throws Exception {
String message = "sample text";
String password = "test$password";
AES encrypter = new AES(password);
String encrypted = encrypter.encrypt(message);
String decrypted = encrypter.decrypt(encrypted);
System.out.println("Encrypt(\"" + message + "\", \"" + password + "\") = \"" + encrypted + "\"");
System.out.println("Decrypt(\"" + encrypted + "\", \"" + password + "\") = \"" + decrypted + "\"");
}
}
You may search stackoverflow for many similar questions.
you have multiple issues in your code:
You use different keys:
In Java you use PBKDF2 to generate an encryption key from the provided password. Openssl uses its EVP_BytesToKey. Search internet for Java implementation. Please note the hash used in the EVP_BytesToKey changed with some openssl version (from MD5 to SHA-1 SHA-256), if someone is having more details, please comment
And you use random IV. you don't pass the IV along the ciphertext, so you may be able to decrypt the ciphertext with the same cipher instance (kkeping the same iv), but lets try your Java code to decrypt your ciphertext other time or with other instance, it won't work. You need to pass IV along the ciphertext (usually it's prepended)
Openssl expect following format:
Salted_<8 byte salt>ciphertext
Salted__<8 byte salt>ciphertext
8 byte salt is a random byte array used to generate the encryption key and IV from the provided password. Try encrypt with openssl with -pparameter, it will print the salt, IV and Key generated so you can check and compare
Using CBC without any integrity check (hmac, ..) may be unsafe in many implementations
Suggestions:
you can find an openssl java library implementing the same required (EVP_BytesToKey)
you can implement EVP_BytesToKey yourself
you can use openssl directly with -K/-ivparameters providing the encryption key and IV (in hex format) instead of password, then openssl expects pure ciphertext (no Salted_ or salt inside the input)
Thanks a lot for the clues. As mentioned, did some search and modified the code from one of the post. I have seen similar code with EVP_BytesToKeys in many places, but took some time to figure out the usage. I am able to decrypt the msg encrypted by openssl.
Trying to search the code for encryption as well. Meanwhile any help of encryption is appreciated as well.
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class AES5 {
private static final Charset ASCII = Charset.forName("ASCII");
private static final int INDEX_KEY = 0;
private static final int INDEX_IV = 1;
private static final int ITERATIONS = 1;
private static final int SALT_OFFSET = 8;
private static final int SALT_SIZE = 8;
private static final int CIPHERTEXT_OFFSET = SALT_OFFSET + SALT_SIZE;
private static final int KEY_SIZE_BITS = 256;
/**
* Thanks go to Ola Bini for releasing this source on his blog. The source was
* obtained from here
*
*/
public static byte[][] EVP_BytesToKey(int key_len, int iv_len, MessageDigest md, byte[] salt, byte[] data,
int count) {
byte[][] both = new byte[2][];
byte[] key = new byte[key_len];
int key_ix = 0;
byte[] iv = new byte[iv_len];
int iv_ix = 0;
both[0] = key;
both[1] = iv;
byte[] md_buf = null;
int nkey = key_len;
int niv = iv_len;
int i = 0;
if (data == null) {
return both;
}
int addmd = 0;
for (;;) {
md.reset();
if (addmd++ > 0) {
md.update(md_buf);
}
md.update(data);
if (null != salt) {
md.update(salt, 0, 8);
}
md_buf = md.digest();
for (i = 1; i < count; i++) {
md.reset();
md.update(md_buf);
md_buf = md.digest();
}
i = 0;
if (nkey > 0) {
for (;;) {
if (nkey == 0)
break;
if (i == md_buf.length)
break;
key[key_ix++] = md_buf[i];
nkey--;
i++;
}
}
if (niv > 0 && i != md_buf.length) {
for (;;) {
if (niv == 0)
break;
if (i == md_buf.length)
break;
iv[iv_ix++] = md_buf[i];
niv--;
i++;
}
}
if (nkey == 0 && niv == 0) {
break;
}
}
for (i = 0; i < md_buf.length; i++) {
md_buf[i] = 0;
}
return both;
}
public static byte[][] getKeyIV(byte[] headerSaltAndCipherText, Cipher aesCBC, String password) {
byte[] salt = Arrays.copyOfRange(headerSaltAndCipherText, SALT_OFFSET, SALT_OFFSET + SALT_SIZE);
byte[][] keyAndIV=null;
try {
MessageDigest md5 = MessageDigest.getInstance("MD5");
keyAndIV = EVP_BytesToKey(KEY_SIZE_BITS / Byte.SIZE, aesCBC.getBlockSize(), md5, salt,
password.getBytes(ASCII), ITERATIONS);
} catch (Exception e) {e.printStackTrace();}
return keyAndIV;
}
// https://stackoverflow.com/questions/11783062/how-to-decrypt-file-in-java-encrypted-with-openssl-command-using-aes
public static String decrypt(String encryptedMsg, String password) {
String decryptedMsg =null;
byte[] headerSaltAndCipherText = Base64.decodeBase64(encryptedMsg);
byte[] encrypted = Arrays.copyOfRange(headerSaltAndCipherText, CIPHERTEXT_OFFSET, headerSaltAndCipherText.length);
try {
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final byte[][] keyAndIV = getKeyIV(headerSaltAndCipherText, aesCBC, password);
SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
aesCBC.init(Cipher.DECRYPT_MODE, key, iv);
byte[] decrypted = aesCBC.doFinal(encrypted);
decryptedMsg = new String(decrypted, ASCII);
} catch (Exception e) {e.printStackTrace();}
return decryptedMsg;
}
//TODO - Encrypt the msg in same manner as "openssl enc -aes-256-cbc -a -salt"
public static String encrypt(String msg, String password) {
String decryptedMsg =null;
byte[] headerSaltAndCipherText = Base64.decodeBase64(msg);
byte[] encrypted = Arrays.copyOfRange(headerSaltAndCipherText, CIPHERTEXT_OFFSET, headerSaltAndCipherText.length);
try {
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final byte[][] keyAndIV = getKeyIV(headerSaltAndCipherText, aesCBC, password);
SecretKeySpec key = new SecretKeySpec(keyAndIV[INDEX_KEY], "AES");
IvParameterSpec iv = new IvParameterSpec(keyAndIV[INDEX_IV]);
aesCBC.init(Cipher.ENCRYPT_MODE, key, iv);
byte[] decrypted = aesCBC.doFinal(encrypted);
decryptedMsg = new String(decrypted, ASCII);
} catch (Exception e) {e.printStackTrace();}
return decryptedMsg;
}
public static void main(String[] args) {
String msg = "the decrypted message is this";
String password = "pass";
System.out.println(encrypt(msg, password));
String encryptedMsg = "U2FsdGVkX190A5FsNTanwTKBdex29SpnH4zWkZN+Ld+MmbJgK4BH1whGIRRSpOJT";
System.out.println(decrypt(encryptedMsg, password));
}
}
Also got an improved solution from the following site. Got the code for both encryption and decryption for now...
http://qaru.site/questions/19874/java-equivalent-of-an-openssl-aes-cbc-encryption
import java.net.URLEncoder;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import static java.nio.charset.StandardCharsets.*;
/**
* Mimics the OpenSSL AES Cipher options for encrypting and decrypting messages using a
* shared key (aka password) with symetric ciphers.
*/
public class OpenSslAesQu {
/** OpenSSL magic initial bytes. */
private static final String SALTED_STR = "Salted__";
private static final byte[] SALTED_MAGIC = SALTED_STR.getBytes(US_ASCII);
public static String encryptAndURLEncode(String password, String clearText) {
String encrypted = null;
try {
encrypted = URLEncoder.encode(encrypt(password, clearText),UTF_8.name());
} catch (Exception e) {e.printStackTrace();}
return encrypted;
}
/**
*
* #param password The password / key to encrypt with.
* #param data The data to encrypt
* #return A base64 encoded string containing the encrypted data.
*/
public static String encrypt(String password, String clearText) {
String encryptedMsg = null;
final byte[] pass = password.getBytes(US_ASCII);
final byte[] salt = (new SecureRandom()).generateSeed(8);
final byte[] inBytes = clearText.getBytes(UTF_8);
final byte[] passAndSalt = array_concat(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
try {
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = array_concat(hash, passAndSalt);
final MessageDigest md = MessageDigest.getInstance("MD5");
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] data = cipher.doFinal(inBytes);
data = array_concat(array_concat(SALTED_MAGIC, salt), data);
//return Base64.getEncoder().encodeToString( data );
encryptedMsg = org.apache.commons.codec.binary.Base64.encodeBase64String(data);
} catch(Exception e) {e.printStackTrace();}
return encryptedMsg;
}
/**
* #see http://stackoverflow.com/questions/32508961/java-equivalent-of-an-openssl-aes-cbc-encryption for what looks like a useful answer. The not-yet-commons-ssl also has an implementation
* #param password
* #param source The encrypted data
*/
public static String decrypt(String password, String source) {
String decryptedMsg = null;
final byte[] pass = password.getBytes(US_ASCII);
//final byte[] inBytes = Base64.getDecoder().decode(source);
final byte[] inBytes = Base64.decodeBase64(source);
final byte[] shouldBeMagic = Arrays.copyOfRange(inBytes, 0, SALTED_MAGIC.length);
if (!Arrays.equals(shouldBeMagic, SALTED_MAGIC)) {
throw new IllegalArgumentException("Initial bytes from input do not match OpenSSL SALTED_MAGIC salt value.");
}
final byte[] salt = Arrays.copyOfRange(inBytes, SALTED_MAGIC.length, SALTED_MAGIC.length + 8);
final byte[] passAndSalt = array_concat(pass, salt);
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
try {
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = array_concat(hash, passAndSalt);
final MessageDigest md = MessageDigest.getInstance("MD5");
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final SecretKeySpec key = new SecretKeySpec(keyValue, "AES");
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
final byte[] clear = cipher.doFinal(inBytes, 16, inBytes.length - 16);
decryptedMsg = new String(clear, UTF_8);
} catch (Exception e) {e.printStackTrace();}
return decryptedMsg;
}
private static byte[] array_concat(final byte[] a, final byte[] b) {
final byte[] c = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
public static void main(String[] args) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
String msg = "the decrypted message is this";
String password = "pass";
System.out.println(">> "+encrypt(password,msg));
//System.out.println("<< "+decrypt(encrypt(msg, password), password));
String encryptedMsg = "U2FsdGVkX190A5FsNTanwTKBdex29SpnH4zWkZN+Ld+MmbJgK4BH1whGIRRSpOJT";
String encryptedMsg2 = "U2FsdGVkX1/B6oOznz5+nd7W/qXwXI7G7rhj5o9pjx8MS0TXp9SNxO3AhM9HBJ/z";
System.out.println(decrypt(password,encryptedMsg));
System.out.println(decrypt(password,encryptedMsg2));
System.out.println(decrypt(password,encrypt(password,msg)));
}
}
I have got this code from Server guys:
public string Encryption(string PlainText)
{
string key = "twelve_digit_key";
TripleDES des = CreateDES(key);
ICryptoTransform ct = des.CreateEncryptor();
byte[] input = Encoding.Unicode.GetBytes(PlainText);
byte[] buffer = ct.TransformFinalBlock(input, 0, input.Length);
return Convert.ToBase64String(buffer);
}
static TripleDES CreateDES(string key)
{
MD5 md5 = new MD5CryptoServiceProvider();
TripleDES des = new TripleDESCryptoServiceProvider();
des.Key = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
des.IV = new byte[des.BlockSize / 8];
return des;
}
This is my code against above :
public String encryptDES(String message) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(getNativeKey3().getBytes("utf-8"));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8; ) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(digestOfPassword, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
return Base64.encodeToString(cipherText, Base64.DEFAULT)
.replace("\n", "")
.replace("\r", "");
}
Problem :
First Code gives below result :
Encrypted Text for 121212 is VvRQkSUj5SQ69mGXsL+h6w==
But Second Code returns this :
Encrypted Text for 121212 is 2STVJSd1mnw=
Observations :
When I increase the plainttext to 10 digits I am getting 24 digit cipher text
Can any one help me in this:
Thanks in Advance
You've been fooled by the badly named Unicode class, which actually specifies UTF-16LE rather than UTF-8.
You can use StandardCharsets.UTF_16LE for specifying the encoding rather than the string; this saves you from one exception to handle.
If there are still issues with the length (test!) then you may have to deal with the Byte Order Mark or BOM - but I don't think so.
I even use the AES algorithm to encrypt and decrypt files, but according to my research, the performance of this algorithm is slower than the RC4 algorithm in Java.
I'm use this code for encrypt files in C#
public static class RC4
{
public static byte[] Encrypt(byte[] key, byte[] data)
{
return EncryptOutput(key, data).ToArray();
}
private static byte[] EncryptInitalize(byte[] key)
{
byte[] s = Enumerable.Range(0, 256)
.Select(i => (byte)i)
.ToArray();
for (int i = 0, j = 0; i < 256; i++)
{
j = (j + key[i % key.Length] + s[i]) & 255;
Swap(s, i, j);
}
return s;
}
private static IEnumerable<byte> EncryptOutput(byte[] key, IEnumerable<byte> data)
{
byte[] s = EncryptInitalize(key);
int i = 0;
int j = 0;
return data.Select((b) =>
{
i = (i + 1) & 255;
j = (j + s[i]) & 255;
Swap(s, i, j);
return (byte)(b ^ s[(s[i] + s[j]) & 255]);
});
}
private static void Swap(byte[] s, int i, int j)
{
byte c = s[i];
s[i] = s[j];
s[j] = c;
}
}
I need to encrypt a file in C # and decrypt this file with java, but found no implementation for both languages.
This solution implemented by Michael Remijan showed better performance to decrypt files using AES. Encrypt and Decrypt files for I implemented just a string conversion to byte array.
Java Code
package org.ferris.aes.crypto;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
*
* #author Michael Remijan mjremijan#yahoo.com #mjremijan
*/
public class AesBase64Wrapper {
private static String IV = "IV_VALUE_16_BYTE";
private static String PASSWORD = "PASSWORD_VALUE";
private static String SALT = "SALT_VALUE";
public String encryptAndEncode(String raw) {
try {
Cipher c = getCipher(Cipher.ENCRYPT_MODE);
byte[] encryptedVal = c.doFinal(getBytes(raw));
String s = getString(Base64.encodeBase64(encryptedVal));
return s;
} catch (Throwable t) {
throw new RuntimeException(t);
}
}
public String decodeAndDecrypt(String encrypted) throws Exception {
byte[] decodedValue = Base64.decodeBase64(getBytes(encrypted));
Cipher c = getCipher(Cipher.DECRYPT_MODE);
byte[] decValue = c.doFinal(decodedValue);
return new String(decValue);
}
private String getString(byte[] bytes) throws UnsupportedEncodingException {
return new String(bytes, "UTF-8");
}
private byte[] getBytes(String str) throws UnsupportedEncodingException {
return str.getBytes("UTF-8");
}
private Cipher getCipher(int mode) throws Exception {
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = getBytes(IV);
c.init(mode, generateKey(), new IvParameterSpec(iv));
return c;
}
private Key generateKey() throws Exception {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
char[] password = PASSWORD.toCharArray();
byte[] salt = getBytes(SALT);
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
byte[] encoded = tmp.getEncoded();
return new SecretKeySpec(encoded, "AES");
}
}
C# Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;
namespace EncryptDecryptTest
{
class Program
{
class AesBase64Wrapper
{
private static string IV = "IV_VALUE_16_BYTE";
private static string PASSWORD = "PASSWORD_VALUE";
private static string SALT = "SALT_VALUE";
public static string EncryptAndEncode(string raw)
{
using (var csp = new AesCryptoServiceProvider())
{
ICryptoTransform e = GetCryptoTransform(csp, true);
byte[] inputBuffer = Encoding.UTF8.GetBytes(raw);
byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
string encrypted = Convert.ToBase64String(output);
return encrypted;
}
}
public static string DecodeAndDecrypt(string encrypted)
{
using (var csp = new AesCryptoServiceProvider())
{
var d = GetCryptoTransform(csp, false);
byte[] output = Convert.FromBase64String(encrypted);
byte[] decryptedOutput = d.TransformFinalBlock(output, 0, output.Length);
string decypted = Encoding.UTF8.GetString(decryptedOutput);
return decypted;
}
}
private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting)
{
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(PASSWORD), Encoding.UTF8.GetBytes(SALT), 65536);
byte[] key = spec.GetBytes(16);
csp.IV = Encoding.UTF8.GetBytes(IV);
csp.Key = key;
if (encrypting)
{
return csp.CreateEncryptor();
}
return csp.CreateDecryptor();
}
}
static void Main(string[] args)
{
string encryptMe;
string encrypted;
string decrypted;
encryptMe = "please encrypt me";
Console.WriteLine("encryptMe = " + encryptMe);
encrypted = AesBase64Wrapper.EncryptAndEncode(encryptMe);
Console.WriteLine("encypted: " + encrypted);
decrypted = AesBase64Wrapper.DecodeAndDecrypt(encrypted);
Console.WriteLine("decrypted: " + decrypted);
Console.WriteLine("press any key to exit....");
Console.ReadKey();
}
}
}
Based on your comments, I am assuming you want to know how to speed up your encryption / decryption process, and changing the main algorithm is not mandatory.
You could look at different modes for AES. For example, AES in counter (CTR) mode is significantly faster than cipher block chaining (CBC) which is often used.
Try creating your cipher like
Cipher myCipher = Cipher.getInstance("AES/CTR/NoPadding");
and you should see a performance increase. Additionally, using NoPadding will keep the size the same as the plaintext.
(Yes, I know that CTR mode turn AES into a stream cipher, never mind my comment)
UPDATE
I have used this in the past along these lines:
Key key = new SecretKeySpec(yourKeyValue, "AES");
Cipher enc = Cipher.getInstance("AES/CTR/NoPadding");
enc.init(Cipher.ENCRYPT_MODE, key);
// Get the IV that was generated
byte[] iv = enc.getIV();
// Encrypt your data
...
Cipher dec = Cipher.getInstance("AES/CTR/NoPadding");
dec.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
// Decrypt your data
...
I am new to encryption and decryption. I was given a PSKC file and asked for decryption. I was given the password for decryption. The PSKC file doenot have initialization vector value.
I wrote the code trying to decrypt it. But i am unsuccessful in achieving the outcome.
below is the PSKC file example
<?xml version="1.0"?>
<pskc:KeyContainer xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:pkcs5="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:xenc11="http://www.w3.org/2009/xmlenc11#" xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc">
<pskc:EncryptionKey>
<xenc11:DerivedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:pkcs5="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#" xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc11="http://www.w3.org/2009/xmlenc11#">
<xenc11:KeyDerivationMethod Algorithm="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#pbkdf2">
<pkcs5:PBKDF2-params xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:pskc="urn:ietf:params:xml:ns:keyprov:pskc" xmlns:xenc11="http://www.w3.org/2009/xmlenc11#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:pkcs5="http://www.rsasecurity.com/rsalabs/pkcs/schemas/pkcs-5v2-0#">
<Salt>
<Specified>EW0h0yUcDX72WU9UiKiCwDpXsJg=</Specified>
</Salt>
<IterationCount>128</IterationCount>
<KeyLength>16</KeyLength>
<PRF />
</pkcs5:PBKDF2-params>
</xenc11:KeyDerivationMethod>
<xenc:ReferenceList>
<xenc:DataReference URI="#ED" />
</xenc:ReferenceList>
<xenc11:MasterKeyName>Passphrase1</xenc11:MasterKeyName>
</xenc11:DerivedKey>
</pskc:EncryptionKey>
<pskc:MACMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1">
<pskc:MACKey>
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<xenc:CipherData>
<xenc:CipherValue>jq/NdikC7AZf0Z+HEL5NrCICV8XW+ttzl/8687hVGHceoyJAaFws+111plQH6Mlg</xenc:CipherValue>
</xenc:CipherData>
</pskc:MACKey>
</pskc:MACMethod>
<pskc:KeyPackage>
<pskc:DeviceInfo>
<pskc:Manufacturer>Gemalto</pskc:Manufacturer>
<pskc:SerialNo>GAKT000047A5</pskc:SerialNo>
</pskc:DeviceInfo>
<pskc:CryptoModuleInfo>
<pskc:Id>CM_ID_007</pskc:Id>
</pskc:CryptoModuleInfo>
<pskc:Key Id="GAKT000047A5" Algorithm="urn:ietf:params:xml:ns:keyprov:pskc:totp">
<pskc:Issuer>Issuer0</pskc:Issuer>
<pskc:AlgorithmParameters>
<pskc:ResponseFormat Encoding="DECIMAL" Length="6" />
</pskc:AlgorithmParameters>
<pskc:Data>
<pskc:Secret>
<pskc:EncryptedValue>
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" />
<xenc:CipherData>
<xenc:CipherValue>pM7VB/KomPjq2cKaxPr5cKT1tUZN5tGMI+u1XKJTG1la+ThraPpLKlL2plKk6vQE</xenc:CipherValue>
</xenc:CipherData>
</pskc:EncryptedValue>
<pskc:ValueMAC>lbu+9OcLArnj6mS7KYOKDa4zRU0=</pskc:ValueMAC>
</pskc:Secret>
<pskc:Time>
<pskc:PlainValue>0</pskc:PlainValue>
</pskc:Time>
<pskc:TimeInterval>
<pskc:PlainValue>30</pskc:PlainValue>
</pskc:TimeInterval>
</pskc:Data>
</pskc:Key>
</pskc:KeyPackage>
</pskc:KeyContainer>
below is the java code which i have written for decryption.
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import com.sun.org.apache.xerces.internal.impl.dv.util.HexBin;
public class test {
/**
* #param args
*/
public static void main(String[] args) {
test te = new test();
try {
te.decryptSeedValue();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
e.printStackTrace();
}
// TODO Auto-generated method stub
}
public static HashMap decryptSeedValue()throws Exception{
String password = "G?20R+I+3-/UcWIN";
String pbesalt ="EW0h0yUcDX72WU9UiKiCwDpXsJg=";
String iv = "aaaaaaaaaaaaaaaaaaaaaaaa";
int iteration = 128;
String value = "pM7VB/KomPjq2cKaxPr5cKT1tUZN5tGMI+u1XKJTG1la+ThraPpLKlL2plKk6vQE";
String valueDigest = "lbu+9OcLArnj6mS7KYOKDa4zRU0=";
byte[] cipherText =null;
//some parameters need to decode from Base64 to byte[]
byte[] data = base64Decode(value.getBytes());
//System.out.println("data(hex string) = " + HexBin.encode(data));//debug
byte[] salt = base64Decode(pbesalt.getBytes());
//System.out.println("salt(hex string) = " + HexBin.encode(salt));//debug
byte[] initVec = base64Decode(iv.getBytes());
//System.out.println("iv(hex string) = " + HexBin.encode(initVec));//debug
//perform PBE key generation and AES/CBC/PKCS5Padding decrpyption
HashMap hs = myFunction(data, password, initVec, salt, iteration);
String seedValue = (String)hs.get("DECRYPTED_SEED_VALUE");
byte[] temp = (byte[])hs.get("HASH_OUTPUT");
//System.out.println("hashed output(hex string) = " + HexBin.encode(temp));//debug
//perform Base64 Encode
byte[] out = base64Encode(temp);
String output = new String((out));
System.out.println("output = "+output);
System.out.println("valueD = "+valueDigest);
//System.out.println("hashed output(base64) = " + output);
//compare the result
if(output.equals(valueDigest)){
System.out.println("Hash verification successful for:-->" );
System.out.println("\n");
//hs.put("SEED_VALUE", HexBin.encode(temp));
hs.put("SEED_VALUE", seedValue);
return hs;
}
else{
System.out.println("Hash verification failed for :-->");
return null;
}
}
public static HashMap myFunction(byte[] data, String password, byte[] initVec,
byte[] salt, int iteration) throws Exception{
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator();
byte[] pBytes = password.getBytes();
generator.init(pBytes, salt, iteration);
int keysize = 128;//fixed at AES key of 16 bytes
int ivsize = initVec.length;
ParametersWithIV params = (ParametersWithIV) generator.generateDerivedParameters(keysize, ivsize);
KeyParameter keyParam = (KeyParameter) params.getParameters();
//System.out.println("derived key = " + HexBin.encode(keyParam.getKey()));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec paramSpec = new IvParameterSpec(initVec);
SecretKeySpec key = new SecretKeySpec(keyParam.getKey(), "AES");
cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
//perform decryption
byte[] secret = cipher.doFinal(data);
//display the 20 bytes secret of the token
//System.out.println("token secret(hex string) = " + HexBin.encode(secret));
//perform HMAC-SHA-1
byte[] output = hmac_sha1(secret, keyParam.getKey());
HashMap hs = new HashMap();
hs.put("ENCRYPTION_KEY", HexBin.encode(keyParam.getKey()));
hs.put("HASH_OUTPUT", output);
hs.put("DECRYPTED_SEED_VALUE", HexBin.encode(secret));
return hs;
}
public static byte[] base64Encode(byte[] passwordBytes) throws NoSuchAlgorithmException {
Base64 base64 = new Base64();
byte[] hashBytes2 = base64.encode(passwordBytes);
return hashBytes2;
}
public static byte[] base64Decode(byte[] passwordBytes) throws NoSuchAlgorithmException {
Base64 base64 = new Base64();
byte[] hashBytes2 = base64.decode(passwordBytes);
return hashBytes2;
}
public static byte[] hmac_sha1(byte[] dataByte, byte[] keyByte) throws Exception{
Mac hmacSha1;
hmacSha1 = Mac.getInstance("HmacSHA1");
SecretKeySpec macKey = new SecretKeySpec(keyByte, "HmacSHA1");
hmacSha1.init(macKey);
byte[] result = hmacSha1.doFinal(dataByte);
return result;
}
/**
* Convert a byte array of 8 bit characters into a String.
*
* #param bytes the array containing the characters
* #param length the number of bytes to process
* #return a String representation of bytes
*/
private static String toString(
byte[] bytes,
int length)
{
char[] chars = new char[length];
for (int i = 0; i != chars.length; i++)
{
chars[i] = (char)(bytes[i] & 0xff);
}
return new String(chars);
}
}
it doesn't throw any exception, but it prints "Hash verification failed for" which is defined in my code when decryption fails.
Can some one please help me out.
As per the pskc standard http://www.rfc-editor.org/rfc/rfc6030.txt the IV is prepended to the ciphervalue. This is aes128, so it'll be the first 16 bytes once it's been base64 decoded.
Adding onto what bcharlton is describing; what you are not doing is check the hmac_sha1 for the encrypted data (which has the iv prepended in encrypted form), using the MACKey described in the xml document.
With AES-128 CBC the initialization vector is explicitly defined, and since there is no verification built into it, it uses HMAC for it.
So given your example the following will work:
public static HashMap decryptSeedValue() throws Exception
{
String password = "G?20R+I+3-/UcWIN";
String pbesalt = "EW0h0yUcDX72WU9UiKiCwDpXsJg=";
String iv = "aaaaaaaaaaaaaaaaaaaaaaaa";
int iteration = 128;
String value = "pM7VB/KomPjq2cKaxPr5cKT1tUZN5tGMI+u1XKJTG1la+ThraPpLKlL2plKk6vQE";
String valueDigest = "lbu+9OcLArnj6mS7KYOKDa4zRU0=";
//YOU NEED THIS GUY BELOW TO VERIFY
String macKey = "jq/NdikC7AZf0Z+HEL5NrCICV8XW+ttzl/8687hVGHceoyJAaFws+111plQH6Mlg";
byte[] cipherText = null;
//some parameters need to decode from Base64 to byte[]
byte[] data = base64Decode(value.getBytes());
//System.out.println("data(hex string) = " + HexBin.encode(data));//debug
byte[] salt = base64Decode(pbesalt.getBytes());
//System.out.println("salt(hex string) = " + HexBin.encode(salt));//debug
byte[] initVec = base64Decode(iv.getBytes());
//System.out.println("iv(hex string) = " + HexBin.encode(initVec));//debug
//perform PBE key generation and AES/CBC/PKCS5Padding decrpyption
HashMap hs = myFunction(data, password, base64Decode(macKey.getBytes()), salt, iteration);
String seedValue = (String) hs.get("DECRYPTED_SEED_VALUE");
byte[] temp = (byte[]) hs.get("HASH_OUTPUT");
//System.out.println("hashed output(hex string) = " + HexBin.encode(temp));//debug
//perform Base64 Encode
byte[] out = base64Encode(temp);
String output = new String((out));
System.out.println("output = " + output);
System.out.println("valueD = " + valueDigest);
//System.out.println("hashed output(base64) = " + output);
//compare the result
if (output.equals(valueDigest)) {
System.out.println("Hash verification successful for:-->");
System.out.println("\n");
//hs.put("SEED_VALUE", HexBin.encode(temp));
hs.put("SEED_VALUE", seedValue);
return hs;
} else {
System.out.println("Hash verification failed for :-->");
return null;
}
}
public static HashMap myFunction(byte[] data, String password, byte[] macData,
byte[] salt, int iteration) throws Exception
{
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator();
byte[] pBytes = password.getBytes();
generator.init(pBytes, salt, iteration);
byte[] iv = new byte[16];
int ivsize = iv.length;
byte[] encryptedData = new byte[data.length - ivsize];
System.arraycopy(data, 0, iv, 0, iv.length);
System.arraycopy(data, ivsize, encryptedData, 0, encryptedData.length);
byte[] maciv = new byte[16];
byte[] encryptedMac = new byte[macData.length - maciv.length];
System.arraycopy(macData, 0, maciv, 0, maciv.length);
System.arraycopy(macData, maciv.length, encryptedMac, 0, encryptedMac.length);
int keysize = 128;//fixed at AES key of 16 bytes
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iteration, keysize);
SecretKey tmp = factory.generateSecret(spec);
SecretKey key = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] decryptedData = dcipher.doFinal(encryptedData);
// decryptedData is your token value!
dcipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(maciv));
byte[] decryptedMac = dcipher.doFinal(encryptedMac);
//display the 20 bytes secret of the token
//System.out.println("token secret(hex string) = " + HexBin.encode(secret));
//perform HMAC-SHA-1
//Use the decrypted MAC key here for hashing!
byte[] output = hmac_sha1(data, decryptedMac);
HashMap hs = new HashMap();
hs.put("ENCRYPTION_KEY", password);
hs.put("HASH_OUTPUT", output);
hs.put("DECRYPTED_SEED_VALUE", HexBin.encode(decryptedData));
return hs;
}
Keep in mind that as https://www.rfc-editor.org/rfc/rfc6030#section-6.2 describes, a different iv can be used for the MAC and the token key.
I have to create a weservice that sends an encrypted String with AES, a salt size of 32 and a given password. I'm trying to make my code work but when I try to decrypt a String that they gave me to check if the decrypting is working I get an error:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
My code is below:
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
/**
* parts of this code were copied from the StandardPBEByteEncryptor class from the Jasypt (www.jasypt.org) project
*/
public class AESCrypt {
//private final String KEY_ALGORITHM = "PBEWITHSHA256AND128BITAES-CBC-BC";
private final String KEY_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
private final String MODE_PADDING = "/CBC/PKCS5Padding";
private final int DEFAULT_SALT_SIZE_BYTES = 32;
private final SecureRandom rand;
private final String passwd = "8g5qT74KdUY";
public AESCrypt() throws Exception {
rand = SecureRandom.getInstance("SHA1PRNG");
}
private byte[] generateSalt(int size) {
byte[] salt = new byte[size];
rand.nextBytes(salt);
return salt;
}
private SecretKey generateKey(String algorithm, int keySize, byte[] salt) throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray(), salt, 100000);
SecretKey tmpKey = factory.generateSecret(pbeKeySpec);
byte[] keyBytes = new byte[keySize / 8];
System.arraycopy(tmpKey.getEncoded(), 0, keyBytes, 0, keyBytes.length);
return new SecretKeySpec(keyBytes, algorithm);
}
private byte[] generateIV(Cipher cipher) {
byte[] iv = new byte[cipher.getBlockSize()];
rand.nextBytes(iv);
return iv;
}
private byte[] appendArrays(byte[] firstArray, byte[] secondArray) {
final byte[] result = new byte[firstArray.length + secondArray.length];
System.arraycopy(firstArray, 0, result, 0, firstArray.length);
System.arraycopy(secondArray, 0, result, firstArray.length, secondArray.length);
return result;
}
public byte[] encrypt(String algorithm, int keySize, final byte[] message) throws Exception {
Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);
// The salt size for the chosen algorithm is set to be equal
// to the algorithm's block size (if it is a block algorithm).
int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
int algorithmBlockSize = cipher.getBlockSize();
if (algorithmBlockSize > 0) {
saltSizeBytes = algorithmBlockSize;
}
// Create salt
final byte[] salt = generateSalt(saltSizeBytes);
SecretKey key = generateKey(algorithm, keySize, salt);
// create a new IV for each encryption
final IvParameterSpec ivParamSpec = new IvParameterSpec(generateIV(cipher));
// Perform encryption using the Cipher
cipher.init(Cipher.ENCRYPT_MODE, key, ivParamSpec);
byte[] encryptedMessage = cipher.doFinal(message);
// append the IV and salt
encryptedMessage = appendArrays(ivParamSpec.getIV(), encryptedMessage);
encryptedMessage = appendArrays(salt, encryptedMessage);
return encryptedMessage;
}
public byte[] decrypt(String algorithm, int keySize, final byte[] encryptedMessage) throws Exception {
Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);
// determine the salt size for the first layer of encryption
int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
int algorithmBlockSize = cipher.getBlockSize();
if (algorithmBlockSize > 0) {
saltSizeBytes = algorithmBlockSize;
}
System.out.println("saltSizeBytes:"+saltSizeBytes);
byte[] decryptedMessage = new byte[encryptedMessage.length];
System.arraycopy(encryptedMessage, 0, decryptedMessage, 0, encryptedMessage.length);
// extract the salt and IV from the incoming message
byte[] salt = null;
byte[] iv = null;
byte[] encryptedMessageKernel = null;
final int saltStart = 0;
final int saltSize = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes : decryptedMessage.length);
//final int saltSize = 32;
//System.out.println("saltSize:"+saltSize);
final int ivStart = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes : decryptedMessage.length);
final int ivSize = cipher.getBlockSize();
final int encMesKernelStart = (saltSizeBytes + ivSize < decryptedMessage.length ? saltSizeBytes + ivSize : decryptedMessage.length);
final int encMesKernelSize = (saltSizeBytes + ivSize < decryptedMessage.length ? (decryptedMessage.length - saltSizeBytes - ivSize) : 0);
salt = new byte[saltSize];
iv = new byte[ivSize];
System.out.println("saltSize:"+saltSize);
System.out.println("ivSize:"+ivSize);
encryptedMessageKernel = new byte[encMesKernelSize];
System.out.println("encryptedMessageKernel");
System.arraycopy(decryptedMessage, saltStart, salt, 0, saltSize);
System.arraycopy(decryptedMessage, ivStart, iv, 0, ivSize);
System.arraycopy(decryptedMessage, encMesKernelStart, encryptedMessageKernel, 0, encMesKernelSize);
SecretKey key = generateKey(algorithm, keySize, salt);
System.out.println("ekey");
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
// Perform decryption using the Cipher
cipher.init(Cipher.DECRYPT_MODE, key, ivParamSpec);
decryptedMessage = cipher.doFinal(encryptedMessageKernel);
// Return the results
return decryptedMessage;
}
Now I have this information I know it was crypted and I would like to decrypt:
Original String: 12334567
Crypted String: SsH6NO9a64g0U7szvFwSbCkdUF5dNgmxgpt2jU/nFVntG3r2nYxgxLRXri4MW9Z2
Password: 8g5qT74KdUY
When I try to decrypt the SsH... I get the given error. Where is the problem? This is what I do:
String toDecrypt = "SsH6NO9a64g0U7szvFwSbCkdUF5dNgmxgpt2jU/nFVntG3r2nYxgxLRXri4MW9Z2";
byte[] criptata = Base64.decode(toDecrypt);
byte[] decriptata = engine.decrypt("AES", 128, criptata);
String msgdecriptato = new String(decriptata);
This gives me an error.
Here is the code in C# they use to do decrypt:
private const int SaltSize = 32;
/// <summary>
/// Decrypts the ciphertext using the Key.
/// </summary>
/// <param name="ciphertext">The ciphertext to decrypt.</param>
/// <param name="key">The plain text encryption key.</param>
/// <returns>The decrypted text.</returns>
public string Decrypt(string ciphertext, string key)
{
if (string.IsNullOrEmpty(ciphertext))
throw new ArgumentNullException("ciphertext");
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException("key");
// Extract the salt from our ciphertext
var allTheBytes = Convert.FromBase64String(ciphertext);
var saltBytes = allTheBytes.Take(SaltSize).ToArray();
var ciphertextBytes = allTheBytes.Skip(SaltSize).Take(allTheBytes.Length - SaltSize).ToArray();
using (var keyDerivationFunction = new Rfc2898DeriveBytes(key, saltBytes))
{
// Derive the previous IV from the Key and Salt
var keyBytes = keyDerivationFunction.GetBytes(32);
var ivBytes = keyDerivationFunction.GetBytes(16);
// Create a decrytor to perform the stream transform.
// Create the streams used for decryption.
// The default Cipher Mode is CBC and the Padding is PKCS7 which are both good
using (var aesManaged = new AesManaged())
using (var decryptor = aesManaged.CreateDecryptor(keyBytes, ivBytes))
using (var memoryStream = new MemoryStream(ciphertextBytes))
using (var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read))
using (var streamReader = new StreamReader(cryptoStream))
{
// Return the decrypted bytes from the decrypting stream.
return streamReader.ReadToEnd();
}
}
}
Any hint?
I've run your code and It seems to be a problem with your original string. You have to be aware that if it was encrypted with 128bit key it cannot be encrypted with 256bit key. And if the key-sizes do not match you get a bad padding error. This is your code with a main that works:
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
/**
* parts of this code were copied from the StandardPBEByteEncryptor class from
* the Jasypt (www.jasypt.org) project
*/
public class AESCrypt {
// private final String KEY_ALGORITHM = "PBEWITHSHA256AND128BITAES-CBC-BC";
private final String KEY_ALGORITHM = "PBEWithSHA256And256BitAES-CBC-BC";
private final String MODE_PADDING = "/CBC/PKCS5Padding";
private final int DEFAULT_SALT_SIZE_BYTES = 32;
private final SecureRandom rand;
private final String passwd = "8g5qT74KdUY";
public AESCrypt() throws Exception {
rand = SecureRandom.getInstance("SHA1PRNG");
}
private byte[] generateSalt(int size) {
byte[] salt = new byte[size];
rand.nextBytes(salt);
return salt;
}
private SecretKey generateKey(String algorithm, int keySize, byte[] salt)
throws NoSuchProviderException, NoSuchAlgorithmException,
InvalidKeySpecException {
SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray(), salt,
100000);
SecretKey tmpKey = factory.generateSecret(pbeKeySpec);
byte[] keyBytes = new byte[keySize / 8];
System.arraycopy(tmpKey.getEncoded(), 0, keyBytes, 0, keyBytes.length);
return new SecretKeySpec(keyBytes, algorithm);
}
private byte[] generateIV(Cipher cipher) {
byte[] iv = new byte[cipher.getBlockSize()];
rand.nextBytes(iv);
return iv;
}
private byte[] appendArrays(byte[] firstArray, byte[] secondArray) {
final byte[] result = new byte[firstArray.length + secondArray.length];
System.arraycopy(firstArray, 0, result, 0, firstArray.length);
System.arraycopy(secondArray, 0, result, firstArray.length,
secondArray.length);
return result;
}
public byte[] encrypt(String algorithm, int keySize, final byte[] message)
throws Exception {
Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);
// The salt size for the chosen algorithm is set to be equal
// to the algorithm's block size (if it is a block algorithm).
int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
int algorithmBlockSize = cipher.getBlockSize();
if (algorithmBlockSize > 0) {
saltSizeBytes = algorithmBlockSize;
}
// Create salt
final byte[] salt = generateSalt(saltSizeBytes);
SecretKey key = generateKey(algorithm, keySize, salt);
// create a new IV for each encryption
final IvParameterSpec ivParamSpec = new IvParameterSpec(
generateIV(cipher));
// Perform encryption using the Cipher
cipher.init(Cipher.ENCRYPT_MODE, key, ivParamSpec);
byte[] encryptedMessage = cipher.doFinal(message);
// append the IV and salt
encryptedMessage = appendArrays(ivParamSpec.getIV(), encryptedMessage);
encryptedMessage = appendArrays(salt, encryptedMessage);
return encryptedMessage;
}
public byte[] decrypt(String algorithm, int keySize,
final byte[] encryptedMessage) throws Exception {
Cipher cipher = Cipher.getInstance(algorithm + MODE_PADDING);
// determine the salt size for the first layer of encryption
int saltSizeBytes = DEFAULT_SALT_SIZE_BYTES;
int algorithmBlockSize = cipher.getBlockSize();
if (algorithmBlockSize > 0) {
saltSizeBytes = algorithmBlockSize;
}
System.out.println("saltSizeBytes:" + saltSizeBytes);
byte[] decryptedMessage = new byte[encryptedMessage.length];
System.arraycopy(encryptedMessage, 0, decryptedMessage, 0,
encryptedMessage.length);
// extract the salt and IV from the incoming message
byte[] salt = null;
byte[] iv = null;
byte[] encryptedMessageKernel = null;
final int saltStart = 0;
final int saltSize = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes
: decryptedMessage.length);
// final int saltSize = 32;
// System.out.println("saltSize:"+saltSize);
final int ivStart = (saltSizeBytes < decryptedMessage.length ? saltSizeBytes
: decryptedMessage.length);
final int ivSize = cipher.getBlockSize();
final int encMesKernelStart = (saltSizeBytes + ivSize < decryptedMessage.length ? saltSizeBytes
+ ivSize
: decryptedMessage.length);
final int encMesKernelSize = (saltSizeBytes + ivSize < decryptedMessage.length ? (decryptedMessage.length
- saltSizeBytes - ivSize)
: 0);
salt = new byte[saltSize];
iv = new byte[ivSize];
System.out.println("saltSize:" + saltSize);
System.out.println("ivSize:" + ivSize);
encryptedMessageKernel = new byte[encMesKernelSize];
System.out.println("encryptedMessageKernel");
System.arraycopy(decryptedMessage, saltStart, salt, 0, saltSize);
System.arraycopy(decryptedMessage, ivStart, iv, 0, ivSize);
System.arraycopy(decryptedMessage, encMesKernelStart,
encryptedMessageKernel, 0, encMesKernelSize);
SecretKey key = generateKey(algorithm, keySize, salt);
System.out.println("ekey");
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
// Perform decryption using the Cipher
cipher.init(Cipher.DECRYPT_MODE, key, ivParamSpec);
decryptedMessage = cipher.doFinal(encryptedMessageKernel);
// Return the results
return decryptedMessage;
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
AESCrypt aesCrypt = new AESCrypt();
String originalText = "1234567";
String toDecrypt = new String(Base64.encode(aesCrypt.encrypt("AES", 256, originalText.getBytes())));
System.out.println(toDecrypt);
byte[] criptata = Base64.decode(toDecrypt);
byte[] decriptata = aesCrypt.decrypt("AES", 256, criptata);
String msgdecriptato = new String(decriptata);
System.out.println(msgdecriptato);
if (!originalText.equals(msgdecriptato)) {
throw new IllegalStateException("Strings do not match!");
}
}
}