I noticed that an application I was running was throwing exceptions upon simultaneous decryption. I wrote the following to test this:
public void run() {
for(int i=0; i<100000; i++){
String encrypted = Crypt.encrypt(
"Lorem ipsum dolor sit amet.",
"password"
);
String decrypted = Crypt.decrypt(encrypted, "password")[0];
System.out.println(decrypted);
}
}
public static void main(String[] args) {
Thread t1 = new Thread(new Main());
Thread t2 = new Thread(new Main());
t1.start();
t2.start();
}
The Crypt methods are as follows:
public static String encrypt(String input, String key){
try {
byte[] ivBytes = new byte[16];
SecureRandom.getInstance("SHA1PRNG").nextBytes(ivBytes);
IvParameterSpec ips = new IvParameterSpec(ivBytes);
byte[] keybytes = md5(key);//This isn't final. Don't worry ;)
byte[] crypted = null;
SecretKeySpec skey = new SecretKeySpec(keybytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skey, ips);
byte[] ptext = input.getBytes("UTF-8");
crypted = cipher.doFinal(ptext);
return Base64.encodeBase64String(ivBytes)+Base64.encodeBase64String(crypted);
}catch(Exception e){
e.printStackTrace();
}
return null;
}
public static String[] decrypt(String input, String key){
String iv = input.substring(0, 24);
String encrypted = input.substring(24);
try {
IvParameterSpec ips = new IvParameterSpec(Base64.decodeBase64(iv));
byte[] keybytes = md5(key);//This isn't final. Don't worry ;)
byte[] output = null;
SecretKeySpec skey = new SecretKeySpec(keybytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, skey, ips);
output = cipher.doFinal(Base64.decodeBase64(encrypted));
if(output==null){
throw new Exception();
}
return new String[]{new String(output),iv};
}catch(Exception e){
e.printStackTrace();
}
}
Sure enough the first attempt on both threads fail:
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
at common.Crypt.decrypt(Crypt.java:122)
at bootstrap.Main.run(Main.java:427)
at java.lang.Thread.run(Thread.java:680)
There are successes for approximately 20 attempts on each thread (presumably where the unsafe calls don't intersect) and then exceptions are thrown. This pattern seems to continue.
I'm running this on OS X 10.7.2 if that helps.
If I understand correctly this could simply be a vendor issue as it's using the Sun JDK which I could easily swap out, but I thought it would be best to get some more experienced opinions on this and put it up in case someone having the same issue stumbles across it.
If someone could point me in the direction of a thread safe encryption+decryption scheme which achieves the same results I'd be really grateful.
Thanks,
Marcus
The issue was caused by this line which was being used to generate a key from the password.
byte[] keybytes = md5(key);
The md5 function which used the MessageDigest class was prone to returning garbage which was then being fed into the decryption which proceeded to fail.
public static String[] decrypt(String input, String key){
String iv = input.substring(0, 24);
String encrypted = input.substring(24);
try {
IvParameterSpec ips = new IvParameterSpec(Base64.decodeBase64(iv));
byte[] keybytes = md5(key);//This isn't final. Don't worry ;)
byte[] output = null;
SecretKeySpec skey = new SecretKeySpec(keybytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); //Change here
cipher.init(Cipher.DECRYPT_MODE, skey, ips);
output = cipher.doFinal(Base64.decodeBase64(encrypted));
if(output==null){
throw new Exception();
}
return new String[]{new String(output),iv};
}catch(Exception e){
e.printStackTrace();
}
}
Related
I have data encrypted with AES/CBC/PKCS5Padding
I have the secret key but no iv.
I am unable to decrypt the data. What exactly are the steps. I copied a page's steps but I am sure I am doing something wrong since the data is hex.
Below is my code. I use the decrypt function with two params.
public class DCrypt2 {
private static String key = "3jiUqR/0J4/HX98XimcDvg==";//
private static String msg ="636F98E19CCAEB9C6ED1095F70C4739AEBA6200E83926EA3DA42DA4A391AC08B";//"2925D99C3A7520D84D64A80AAFB20BF63B22B6A8017B7438598BE36419B71174";
public static void main(String[] args) {
byte[] myIV = getIV(msg);
byte[] myMSG = getMSG(msg);
String my_msg = myMSG.toString();
decrypt(msg, myIV);
System.out.println("Second Try ");
System.out.println(key);
System.out.println(msg);
System.out.println("____________________________________");
//System.out.println(Base64.getDecoder().decode(msg));
//System.out.println(myDeHex(msg));
//msg = myDeHex(msg);
int extra = msg.length()%16;
System.out.println(extra+" ok "+msg.length());
for(int i = 0; i<extra;i++) {
System.out.println("ANOTHER");
msg +=" ";
}
System.out.println(extra+" ok "+msg.length());
}
public static String decrypt(String msg, byte[] iv) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
//Cipher cipher = Cipher.getInstance("AES/CBC/nopadding");
SecretKeySpec the_key = new SecretKeySpec(key.getBytes(), "AES");// get / create symmetric encryption key
//SecretKeySpec the_key = new SecretKeySpec(Base64.getDecoder().decode(key), "AES");
// byte[] decoded = Base64.getDecoder().decode(msg);
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, the_key, ivspec);
byte[] input = Base64.getEncoder().encode(msg.getBytes());
if(input.length%16 > 0 ) {
System.out.println(input.length%16);
input = Arrays.copyOf(input, (input.length)+(16-(input.length%16)));
System.out.println(input.length+ " my size");
}
String res = new String(cipher.doFinal( input));
//String res = Base64.getEncoder().encodeToString(cipher.doFinal(msg.getBytes("UTF-8")));
//String res = new String(Base64.getDecoder().decode(cipher.doFinal(msg.getBytes("UTF-8"))));
System.out.println("Results: "+res);
return res;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
}
There is a good technical write-up here: https://www.rfc-editor.org/rfc/rfc3602#section-2
You need an Initialization Vector:
https://crypto.stackexchange.com/questions/29134/precisely-how-does-cbc-mode-use-the-initialization-vector
The IV's purpose is to ensure same plaintexts encrypt to different
ciphertexts. When an adversary learns the IV after the plaintext has
been encrypted, no harm is done, since it has already served its
purpose.
The IV can be made public after encryption, without impacting the
security of the system. Usually, it is prefixed to the ciphertext.
Source / More info
i am trying to decrypt using AES/CFB mode by using below code,
final static public String ENCRYPT_KEY = "4EBB854BC67649A99376A7B90089CFF1";
final static public String IVKEY = "ECE7D4111337A511F81CBF2E3E42D105";
private static String deCrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skSpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
int maxKeyLen = Cipher.getMaxAllowedKeyLength("AES");
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skSpec, iv);
byte[] original = cipher.doFinal(encrypted.getBytes());
return new String(original);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
and throw below error,
Wrong IV length: must be 16 bytes long.
Above ENCRYPT_KEY and IVKEY are valid one. can any one help in that ?
You're calling "ECE7D4111337A511F81CBF2E3E42D105".getBytes("UTF-8"); which will result in byte[] of size 32, not to mention a completely wrong IV.
You need to parse the String into a byte[] instead, for example by borrowing the DatatypeConverter from javax.xml.bind.
IvParameterSpec iv = new IvParameterSpec(
javax.xml.bind.DatatypeConverter.parseHexBinary(initVector));
I have my application's UI built in Meteor and it gets and send the data from REST API (Spring CXF). I would like to encrypt the data in Meteor, and decrypt the same in REST API code. I am using AES for encryption and Decryption. In Meteor i am using https://atmospherejs.com/jparker/crypto-aes package for encryption. I have written the below code in java for decryption the encryption key send by Meteor.
public class AESTest {
private static String AESStr = "<Encrypted KEY>";
public static void main(String[] args) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
System.out.println(decrypt(AESStr, "Test"));
}
public static String decrypt(String responseStr, String passPhrase) throws GeneralSecurityException {
String decryptedStr = "";
try {
Cipher cipher = getCipher(Cipher.DECRYPT_MODE, passPhrase);
byte[] decoded = Base64.decodeBase64(responseStr.getBytes());
byte[] decryptedWithKey = cipher.doFinal(decoded);
byte[] decrypted = Arrays.copyOfRange(decryptedWithKey, 16, decryptedWithKey.length);
decryptedStr = new String(decrypted, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
return decryptedStr;
}
private static Cipher getCipher(int mode, String passPhrase) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(passPhrase.getBytes(), "AES");
byte[] IV = new byte[16];
new Random().nextBytes(IV);
AlgorithmParameterSpec paramSpec = new IvParameterSpec(IV);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(mode, secretKeySpec, paramSpec);
return cipher;
}
}
When I run the code i am getting below exception
javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.tph.r3.EncodeTest.decrypt(EncodeTest.java:37)
at com.tph.r3.EncodeTest.main(EncodeTest.java:26)
Can anyone guide me with the issue?
There is a problem with the decryption logic w.r.t IV. You are selecting an IV randomly to initialize decryption cipher which is wrong. You need to use the same IV that was used to encrypt the responseStr which forms its first 16 bytes usually.
In the current form your getCipher() can be used only for encryption where IV is selected randomly but not for decryption. Better write another method.
Psuedocode for decryption:
decCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(securityKey , "AES");
//IV + Cipher
byte [] cipherWithIV = Base64.decodeBase64(responseStr.getBytes()));
//Extract IV
byte [] iv = new byte [16];
byte [] cipherWithoutIV = new byte [cipherWithIV.length - 16 ];
//First 16 bytes
for(i < 16; i++) {
iv [i] = cipherWithIV [i];
}
//Rest of the cipher ie 16 -> cipherWithIV.length
for(i < cipherWithIV.length; i++) {
cipherWithoutIV [j] = cipherWithIV[i];
j++;
}
//
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
//
decCipher.init(Cipher.DECRYPT_MODE, keySpec, ivParamSpec);
//Decrypt cipher without IV
decText = decCipher.doFinal(cipherWithoutIV);
//Convert to string
decString = new String(decText,"UTF8");
I'm trying to encrypt something, and decrypt it. I'm failing on the decryption - I get the exception above. I tried changing ctLength and ptLength, but to no avail. What am I doing wrong?
I'm trying to encrypt: 0 0 0 0 0 0 0 0
private Cipher encrypt(byte[] input)
{
try
{
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
FileOutputStream fs = new FileOutputStream(savedScoresFileName);
fs.write(cipherText);
return cipher;
}
catch (Exception e)
{
Log.e("encrtypt", "Exception", e);
}
return null;
}
private String decrypt()
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
byte[] cipherText = new byte[32];
FileInputStream fl = new FileInputStream(savedScoresFileName);
fl.read(cipherText);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(32)];
int ptLength = cipher.update(cipherText, 0, 32, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
return new String(plainText).substring(0, ptLength);
}
catch (Exception e)
{
Log.e("decrypt", "Exception", e);
}
return null;
}
This code was copied from this, which worked.
Your code has a number of issues, but your problem is caused by your file reading code and your strange method of performing the encryption and decryption.
Don't use the update() method, just use doFinal() and correct your file writing/reading code. E.g. your decryption method should look something like:
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
// Here you need to accurately and correctly read your file into a byte
// array. Either Google for a decent solution (there are many out there)
// or use an existing implementation, such as Apache Commons commons-io.
// Your existing effort is buggy and doesn't close its resources.
byte[] cipherText = FileUtils.readFileToByteArray(new File(savedScoresFileName));
cipher.init(Cipher.DECRYPT_MODE, key);
// Just one call to doFinal
byte[] plainText = cipher.doFinal(cipherText);
// Note: don't do this. If you create a string from a byte array,
// PLEASE pass a charset otherwise your result is platform dependent.
return new String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
I'm a newbie here in need of some help. I have a code here that is use to decrypt data. It is working meaning it can decrypt the data, but the problem is; it can only show 1 value of the decrypted data(line 29) instead of 3 or more depend on how I want it (how do i get it to also decrypt the data on line 30 and line 31?). Below i posted the related code to my problem, hope anyone here can help me with this problem.
public class CipherUtils
{
static Log log = LogFactory.getLog(CipherUtils.class);
private static byte[] key = "xxxxxx".getBytes();
private static byte[] iv = "xxxxxx".getBytes();
public static String decrypt(String strToDecrypt)
{
try
{
//Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
Cipher cipher = Cipher.getInstance("aes/cbc/nopadding");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
IvParameterSpec ips = new IvParameterSpec(iv);
//cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipher.init(Cipher.DECRYPT_MODE, secretKey,ips);
final String decryptedString = new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt)));
return decryptedString.trim();
}
catch (Exception e)
{
log.error("Error while decrypting : " + strToDecrypt , e);
}
return null;
}
public static void main(String args[]) throws Exception
{
String a = CipherUtils.decrypt("yXTVA6oG4kWOlvfKN/qXwa3VgEyiBu4kkgKh9WHt0s8="
,"yX7JI7IaExK3eBC6BU5RdCvkCrAAcyV3YTmHqYH5nG0="
,"yj56tfZEh3405yEwladp+ml/nk/h8Cx56XnP5Ycdeio=");
System.out.println(">>>"+a.trim());
}
}
Thanks in advance.
Your method decrypt only takes a single parameter (named strToDecrypt), yet you are passing three.
You could do several things here, the easiest would be to simly call decrypt 3 times, each with a different string.
You could also rewrite list to iterate over a list instead.
http://www.tutorialspoint.com/java/java_using_iterator.htm
public class CipherUtils
{
static Log log = LogFactory.getLog(CipherUtils.class);
private static byte[] key = "xxxxxx".getBytes();
private static byte[] iv = "xxxxxx".getBytes();
public static String[] decrypt(String[] strToDecrypt){
try{
String[] strDecrypted;
//Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
Cipher cipher = Cipher.getInstance("aes/cbc/nopadding");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
IvParameterSpec ips = new IvParameterSpec(iv);
//cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipher.init(Cipher.DECRYPT_MODE, secretKey,ips);
for(int i =0;i<strToDecrypt.length ; i++){
final String decryptedString = new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt [i])));
strDecrypted[i] = decryptedString ;
}
return strDecrypted;
}catch (Exception e){
log.error("Error while decrypting : " + strToDecrypt , e);
}
return null;
}
public static void main(String args[]) throws Exception
{
String array[] = {"yXTVA6oG4kWOlvfKN/qXwa3VgEyiBu4kkgKh9WHt0s8=","yX7JI7IaExK3eBC6BU5RdCvkCrAAcyV3YTmHqYH5nG0=","yj56tfZEh3405yEwladp+ml/nk/h8Cx56XnP5Ycdeio="};
String a = CipherUtils.decrypt(array);
System.out.println(">>>"+a.trim());
}
}
What I have done is I have taken all your strings to decrypt inside a String array and passed it to the method. Then inside the method, i decrypt the string and add it to another array. And then when done, I return the array containing all the decrypted lines. You can then fetch it from the array.
public static String[] decrypt(String[] strToDecrypt)
{
String decryptedString[] = new String[strToDecrypt.length];
for(int i = 0;i<strToDecrypt.length;i++) {
try
{
//Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
Cipher cipher = Cipher.getInstance("aes/cbc/nopadding");
final SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
IvParameterSpec ips = new IvParameterSpec(iv);
//cipher.init(Cipher.DECRYPT_MODE, secretKey);
cipher.init(Cipher.DECRYPT_MODE, secretKey,ips);
decryptedString[i] = new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt[i])));
}
catch (Exception e)
{
log.error("Error while decrypting : " + strToDecrypt[i] , e);
}
}return decryptedString;
}