0

I have a Java AES 256 encryption code like this :

public class EncryptDecryptTwo {
static {
    try {
        Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
        field.setAccessible(true);
        field.set(null, java.lang.Boolean.FALSE);
    } catch (Exception ex) {
    }
}

private static String keyEnc = "BtDMQ7RfNVoRzJ7GYE32";

// Performs Encryption
public static String encrypt(String plainText) throws Exception {
    String passphrase = keyEnc;
    byte[] iv = DatatypeConverter.parseHexBinary("2aba86027a6f79dd463b81b0539bacb5");
    byte[] salt = DatatypeConverter.parseHexBinary("0f3d1b0d514ca313");
    IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
    SecretKeySpec sKey = (SecretKeySpec) generateKeyFromPassword(passphrase, salt);

    Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
    c.init(Cipher.ENCRYPT_MODE, sKey, ivParameterSpec);
    byte[] encryptedData = c.doFinal(plainText.getBytes());
    return DatatypeConverter.printBase64Binary(encryptedData);

}

public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes) throws GeneralSecurityException {

    KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes, 1, 256);
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    SecretKey secretKey = keyFactory.generateSecret(keySpec);

    return new SecretKeySpec(secretKey.getEncoded(), "AES");
}

public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
    }
    return data;
}
}

In this case, I hardcoded the salt bytes and iv bytes just to make sure my coding is encrypt the message right, so it can be read by cryptoJS in another server. But when I send the encrypted text by calling the encrypt method, it is always rejected by the cryptoJS, saying that my encrypted message is not correct

The CryptoJS is in another server and it is like this :

var CryptoJSAesJson = {
  stringify: function (cipherParams) {
    var j = {ct: cipherParams.cipherText.toString(CryptoJS.enc.Base64)};
    if (cipherParams.iv) j.iv = cipherParams.iv.toString();
    if (cipherParams.salt) j.s = cipherParams.salt.toString();
    return JSON.stringify(j);
  },
  parse: function (jsonStr) {
    var j = JSON.parse(jsonStr);
    var cipherParams = CryptoJS.lib.CipherParams.create({ciphertext: CryptoJS.enc.Base64.parse(j.ct)});
    if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
    if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
    return cipherParams;
  }
}
var encrypted = CryptoJS.AES.encrypt(JSON.stringify($scope.loginData.password), __ENV.AES_KEY, { format: CryptoJSAesJson}).toString();

Can anybody help me finding what's wrong in my java code? Thank you very much

Edited : According to Artjom.B's comment and advise, I tried this :

static {
    try {
        Field field = Class.forName("javax.crypto.JceSecurity").getDeclaredField("isRestricted");
        field.setAccessible(true);
        field.set(null, java.lang.Boolean.FALSE);
    } catch (Exception ex) {
    }
}

public static void main(String[] args) throws UnsupportedEncodingException, GeneralSecurityException {
    String plaintext = "someplaintext";
    String password = "BtDMQ7RfNVoRzWGjS2DK";
    int keySize = 256;
    int ivSize = 128;

    byte[] salt = DatatypeConverter.parseHexBinary("5ba2b0e0bb968f47"); // yes, for testing, I use a fixed salt

    byte[] key = new byte[keySize/8];
    byte[] iv = new byte[ivSize/8];
    EvpKDF(password.getBytes("UTF-8"), keySize, ivSize, salt, key, iv);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
    byte[] encryptedText = cipher.doFinal((plaintext).getBytes());

    System.out.println("SALT : " + DatatypeConverter.printHexBinary(salt));
    System.out.println("IV : " + DatatypeConverter.printHexBinary(iv));
    System.out.println("CT : " + DatatypeConverter.printBase64Binary(encryptedText));
// I sent salt, IV, and ciphertext to CryptoJS
}

public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    return EvpKDF(password, keySize, ivSize, salt, 1, "MD5", resultKey, resultIv);
}

public static byte[] EvpKDF(byte[] password, int keySize, int ivSize, byte[] salt, int iterations, String hashAlgorithm, byte[] resultKey, byte[] resultIv) throws NoSuchAlgorithmException {
    keySize = keySize / 32;
    ivSize = ivSize / 32;
    int targetKeySize = keySize + ivSize;
    byte[] derivedBytes = new byte[targetKeySize * 4];
    int numberOfDerivedWords = 0;
    byte[] block = null;
    MessageDigest hasher = MessageDigest.getInstance(hashAlgorithm);
    while (numberOfDerivedWords < targetKeySize) {
        if (block != null) {
            hasher.update(block);
        }
        hasher.update(password);
        block = hasher.digest(salt);
        hasher.reset();

        // Iterations
        for (int i = 1; i < iterations; i++) {
            block = hasher.digest(block);
            hasher.reset();
        }

        System.arraycopy(block, 0, derivedBytes, numberOfDerivedWords * 4,
                Math.min(block.length, (targetKeySize - numberOfDerivedWords) * 4));

        numberOfDerivedWords += block.length/4;
    }

    System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4);
    System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4);

    return derivedBytes; // key + iv
}

/**
 * Copied from http://stackoverflow.com/a/140861
 * */
public static byte[] hexStringToByteArray(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

But still no avail. The CryptoJS keep saying that I pass an incorrect password. Can anybody help? Thank you very much

xemjas
  • 115
  • 4
  • 16
  • What's `__ENV.AES_KEY`? Is it the result of `generateKeyFromPassword`? – Artjom B. Aug 29 '16 at 19:07
  • Yeah, I think it is. If we look on my java code, it should be equivalent to this statement : private static String keyEnc = "BtDMQ7RfNVoRzJ7GYE32"; – xemjas Aug 30 '16 at 03:34
  • So you don't know? Your comment is contradictory. First you're saying that `__ENV.AES_KEY` is the result of `generateKeyFromPassword`, but then you say that `__ENV.AES_KEY` is `keyEnc = "BtDMQ7RfNVoRzJ7GYE32"` which is what goes into `generateKeyFromPassword`. – Artjom B. Aug 30 '16 at 05:13
  • Oh, I'm sorry. Actually I misunderstood your question. The right thing is the second part, which is : __ENV.AES_KEY is keyEnc = "BtDMQ7RfNVoRzJ7GYE32" – xemjas Aug 30 '16 at 06:19
  • In that case, you forgot to derive the key using PBKDF2 in CryptoJS. – Artjom B. Aug 30 '16 at 21:16
  • I see. But in this case, I did not allowed to modify the CryptoJS code. I only allowed to modify the Java code to make it match with the CryptoJS Code. Can you tell me how to fix this? Thank you very much – xemjas Aug 31 '16 at 02:52
  • Possible duplicate of [How to decrypt an encrypted AES-256 string from CryptoJS using Java?](http://stackoverflow.com/questions/29151211/how-to-decrypt-an-encrypted-aes-256-string-from-cryptojs-using-java) – Artjom B. Aug 31 '16 at 05:17
  • Yes, I think it is very close to that issue. But, my needs are the opposite of that issue (my needs are encrypt using java, decrypt using CryptoJS). Can I use the very same evpKDF method for generating the key for encrypting? Thank you very much – xemjas Sep 13 '16 at 05:15
  • Yes, the key derivation is the same regardless of encryption or decryption. – Artjom B. Sep 13 '16 at 05:18
  • Edited my question. Still no avail using evpKDF for deriving the key – xemjas Sep 13 '16 at 07:39

0 Answers0