I have code in Javascript and code in Java that does AES encryption and works together. That is, the Javascript code and the Java code both encrypt a given string to the same value, and can then decrypt that value to the original string.
However, I cannot get my C# code to work the same way. Given the same string, it will encrypt it to a different value than the others.
Can anyone help me with this?
I'm mainly concerned right now with getting the Java, Javascript and C# code to all encrypt a given string to the same value.
Here is the Javascript code. Notice that it uses CryptoJS. The pass phrase, salt and IV I'm using are the same across all languages.
AesUtil.prototype.encrypt = function(salt, iv, passPhrase, plainText) {
var key = this.generateKey(salt, passPhrase);
var encrypted = CryptoJS.AES.encrypt(
plainText,
key,
{ iv: CryptoJS.enc.Hex.parse(iv) });
return encrypted.ciphertext.toString(CryptoJS.enc.Base64);
}
The Javascript code above will encrypt the string "guest" to "WsH/YEUqqrWDxD15zxsUPg==".
Here is the Java code:
public String encrypt(String plainText, String salt, String passphrase, String iv) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException{
byte[] plainTextbytes = plainText.getBytes(characterEncoding);
//byte[] keyBytes = getKeyBytes(salt);
SecretKey key = generateKey(salt, passphrase);
byte[] ivBytes = hex(iv);
return Base64.getEncoder().encodeToString(encrypt(plainTextbytes,key, ivBytes));//, Base64.DEFAULT);
}
private static SecretKey generateKey(String salt, String passphrase) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new javax.crypto.spec.PBEKeySpec(passphrase.toCharArray(), hex(salt), 10000, 128);
SecretKey key = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "Rijndael");
return key;
}
catch (NoSuchAlgorithmException e) {
throw fail(e);
}
catch (InvalidKeySpecException e) {
throw fail(e);
}
}
public static String hex(byte[] bytes) {
return Hex.encodeHexString(bytes);
}
The above Java code works great with the Javascript code, and will also encrypt "guest" to "WsH/YEUqqrWDxD15zxsUPg=="
Here is the C# code:
public String Encrypt(String plainText, String passphrase, String salt, String iv, int iterations) {
var plainBytes = Encoding.UTF8.GetBytes(plainText);
return Convert.ToBase64String(Encrypt(plainBytes, GetSymmetricAlgorithm(passphrase, salt, iv, iterations)));
}
public byte[] Encrypt(byte[] plainBytes, SymmetricAlgorithm sa) {
return sa.CreateEncryptor().TransformFinalBlock(plainBytes, 0, plainBytes.Length);
}
public SymmetricAlgorithm GetSymmetricAlgorithm(String passphrase, String salt, String iv, int iterations) {
var saltBytes = new byte[16];
var ivBytes = new byte[16];
//var tempBytes = Encoding.UTF8.GetBytes(salt);
//Array.Copy(tempBytes, saltBytes, Math.Min(saltBytes.Length, tempBytes.Length));
Rfc2898DeriveBytes rfcdb = new System.Security.Cryptography.Rfc2898DeriveBytes(passphrase, Encoding.UTF8.GetBytes(salt), iterations);
saltBytes = rfcdb.GetBytes(16);
var tempBytes = Encoding.UTF8.GetBytes(iv);
Array.Copy(tempBytes, ivBytes, Math.Min(ivBytes.Length, tempBytes.Length));
var rij = new RijndaelManaged(); //SymmetricAlgorithm.Create();
rij.Mode = CipherMode.CBC;
rij.Padding = PaddingMode.PKCS7;
rij.FeedbackSize = 128;
rij.KeySize = 128;
rij.BlockSize = 128;
rij.Key = saltBytes;
rij.IV = ivBytes;
return rij;
}
Given the string "guest", it encrypts it to "F8t0D0vA2rxU3Ez1O5artA==", which is the same length as the Java and Javascript results, but not the same value, as you can see. Also, it is not decryptable by the Java code.