We have code开发者_Go百科 for AES-128 encryption in Java and we want some equivalent code in WP7.
However, we run into a problem: The two implementations yield different encrypted texts
Here is the code we're using:
Java Code
package com.emap.services;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
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;
public class AESEcrypt1 {
static byte[] ibv = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
public String encryptData() {
String message = "Testing AES encryption-decryption amlgorithm for WP7.";
String encryptedStr = "";
try {
SecretKeySpec skeySpec = new SecretKeySpec("Passkey".getBytes(), "AES");
IvParameterSpec iv = new IvParameterSpec(ibv);
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = cipher.doFinal(message.getBytes());
encryptedStr = Base64.encode(encrypted);
} catch (BadPaddingException ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
} catch (IllegalBlockSizeException ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
} catch (InvalidAlgorithmParameterException ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
} catch (InvalidKeyException ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
} catch (NoSuchAlgorithmException ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
} catch (NoSuchPaddingException ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
} catch (Exception ex) {
System.out.println("Error: " + ex.getMessage());
encryptedStr = "error";
}
System.out.println("Encrypted: " + encryptedStr);
return encryptedStr;
}
}
WP7 Code
static byte[] ibv = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
public string Encrypt(string dataToEncrypt, string password)
//public string Encrypt(string dataToEncrypt)
{
AesManaged aes = null;
MemoryStream memStream = null;
CryptoStream crStream = null;
try
{
//Generate a Key based on a Password and Salt
//Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, Encoding.UTF8.GetBytes(salt));
Rfc2898DeriveBytes rfc2898 = new Rfc2898DeriveBytes(password, ibv);
aes = new AesManaged();
aes.Key = rfc2898.GetBytes(aes.KeySize / 8);
aes.IV = rfc2898.GetBytes(aes.BlockSize / 8);
memStream = new MemoryStream();
crStream = new CryptoStream(memStream, aes.CreateEncryptor(), CryptoStreamMode.Write);
byte[] data = Encoding.UTF8.GetBytes(dataToEncrypt);
crStream.Write(data, 0, data.Length);
crStream.FlushFinalBlock();
//Return Base 64 String
return Convert.ToBase64String(memStream.ToArray());
}
finally
{
//cleanup
if (crStream != null)
crStream.Close();
if (memStream != null)
memStream.Close();
if (aes != null)
aes.Clear();
}
}
Any help would be greatly appreciated.
Note that in Java, you have three parts in the cypher designation - algorithm, mode (CBC vs. ECB, etc) and padding. You must match all three, not just the algorithm. If the WP7 won't let you specify mode and padding explicitly, figure them out and match on the Java side.
Oh, and do make sure that the key is the same. It's not obvious from the example.
EDIT: for debugging padding issues, a trivial key is a great help. That is, a key which makes the algorithm emit a copy of its plaintext as a cyphertext. For RSA, for example, it's the one with public exponent 1. Not sure what would be a trivial key for AES - try all zeros.
It doesn't look like you are using the same key. In the Windows Phone 7 implementation, you appear to be properly deriving a key from a password, while the Java code is improperly using some encoding of a password directly.
See my previous answer for a general overview of password-based encryption in Java. It will show you how to derive a key (according to PBKDF2 in RFC 2898), and describes the proper generation and exchange of an per-message initialization vector.
JB Nizet's comment on the post made me look more closely at how you are using the ibv
data, and he's right: you aren't using the same IV in both operations. It's used as the IV in the Java code, but in the Windows code, it is used as "salt" for the key derivation process. These are two different purposes, and should use two distinct values.
Because ibv
is a fixed value, it's more suitable for key derivation (each password should have one unique salt). Each message should have a new IV randomly chosen and sent with the cipher text. You could use ibv
as the salt
in the Java example I linked to above.
精彩评论