java 的 Rfc2898DeriveBytes?
Rfc2898DeriveBytes for java?
我的后端服务器是基于 .NET 的。
在服务器上使用 Rfc2898DeriveBytes 加密
这是.Net的代码
public static string Encrypt(string clearText)
{
string EncryptionKey = "abc123";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
我在JAVA写客户端。这是代码
try {
String encryptKey = "abc123";
byte[] salt = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(encryptKey.toCharArray(), salt, 1024, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "AES");
System.out.println("Key:" + Base64.encodeToString(secret.getEncoded(), Base64.DEFAULT));
String cleartext = "12345";
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(cleartext.getBytes("UTF-8"));
System.out.println("IV:" + Base64.encodeToString(iv, Base64.DEFAULT));
System.out.println("Cipher text:" + Base64.encodeToString(ciphertext, Base64.DEFAULT));;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
我在 java 中没有得到与 .Net 相同的结果。
12345
的加密值在服务器上是 dAQWIrbtHv/eDbu+4oJD0g==
。
当我得到 tcvGLK5r99jt6PFLALpRfQ==
我需要应用什么修复程序?
Rfc2898DeriveBytes
的默认迭代次数是 1000,而不是 1024(根据 the source)。
而且我不知道 PBEKeySpec
的 keyLength
值是以字节为单位还是以位为单位,但如果它是位,你在 Java 中要求 128 和 256 C# 中的(32 字节)。
嗯,实际上,您在 C# 中要求 384 位。因为前 256 个成为你的密钥,接下来的 128 个成为你的 IV(你似乎让它在 Java 中随机生成)。
因此,您可能需要请求 384 位,调用 getEncoded()
,将答案拆分为 32 字节的密钥和 16 字节的 IV,然后从那里继续。
我还对 .Net 代码进行了一些调整,从而解决了这个问题。
Android代码如下
public class AES256Cipher {
private static byte[] encrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = null;
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
private static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
final static String key = "0123456789abcdefghijklmnopqrstuv";
final static byte[] ivBytes = new byte[]{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
public static String encryptData(String plainText) {
String base64Text = "";
try {
byte[] keyBytes = key.getBytes("UTF-8");
byte[] x = plainText.getBytes("UTF-8");
byte[] cipherData = encrypt(ivBytes, keyBytes, plainText.getBytes("UTF-8"));
base64Text = Base64.encodeToString(cipherData, Base64.DEFAULT);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return base64Text;
}
//############## Response(decrypt) ##############
public static String decryptData(String base64Text) {
String plainText = "";
try {
byte[] keyBytes = key.getBytes("UTF-8");
try {
byte[] cipherData = decrypt(ivBytes, keyBytes, Base64.decode(base64Text.getBytes("UTF-8"), Base64.DEFAULT));
plainText = new String(cipherData, "UTF-8");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return plainText;
}
}
简单调用如下
String en = AES256Cipher.encryptData("1234");
Log.e("enc length", en.length() + "");
Log.e("enc", en);
String de = AES256Cipher.decryptData(en);
Log.e("dec", de);
对于在 java 中使用的人,可以使用软件包 java.util 中的 Base64
将加密方法替换为this
base64Text =Base64.getEncoder().encodeToString(cipherData);
在解密方法中替换为这个
byte[] cipherData = decrypt(ivBytes, keyBytes,Base64.getDecoder().decode(base64Text.getBytes("UTF-8")));
我的后端服务器是基于 .NET 的。 在服务器上使用 Rfc2898DeriveBytes 加密
这是.Net的代码
public static string Encrypt(string clearText)
{
string EncryptionKey = "abc123";
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
return clearText;
}
我在JAVA写客户端。这是代码
try {
String encryptKey = "abc123";
byte[] salt = new byte[]{0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(encryptKey.toCharArray(), salt, 1024, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(tmp.getEncoded(), "AES");
System.out.println("Key:" + Base64.encodeToString(secret.getEncoded(), Base64.DEFAULT));
String cleartext = "12345";
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(cleartext.getBytes("UTF-8"));
System.out.println("IV:" + Base64.encodeToString(iv, Base64.DEFAULT));
System.out.println("Cipher text:" + Base64.encodeToString(ciphertext, Base64.DEFAULT));;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidParameterSpecException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
我在 java 中没有得到与 .Net 相同的结果。
12345
的加密值在服务器上是 dAQWIrbtHv/eDbu+4oJD0g==
。
当我得到 tcvGLK5r99jt6PFLALpRfQ==
我需要应用什么修复程序?
Rfc2898DeriveBytes
的默认迭代次数是 1000,而不是 1024(根据 the source)。
而且我不知道 PBEKeySpec
的 keyLength
值是以字节为单位还是以位为单位,但如果它是位,你在 Java 中要求 128 和 256 C# 中的(32 字节)。
嗯,实际上,您在 C# 中要求 384 位。因为前 256 个成为你的密钥,接下来的 128 个成为你的 IV(你似乎让它在 Java 中随机生成)。
因此,您可能需要请求 384 位,调用 getEncoded()
,将答案拆分为 32 字节的密钥和 16 字节的 IV,然后从那里继续。
我还对 .Net 代码进行了一些调整,从而解决了这个问题。 Android代码如下
public class AES256Cipher {
private static byte[] encrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = null;
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
private static byte[] decrypt(byte[] ivBytes, byte[] keyBytes, byte[] textBytes)
throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeyException,
InvalidAlgorithmParameterException,
IllegalBlockSizeException,
BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return cipher.doFinal(textBytes);
}
final static String key = "0123456789abcdefghijklmnopqrstuv";
final static byte[] ivBytes = new byte[]{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
public static String encryptData(String plainText) {
String base64Text = "";
try {
byte[] keyBytes = key.getBytes("UTF-8");
byte[] x = plainText.getBytes("UTF-8");
byte[] cipherData = encrypt(ivBytes, keyBytes, plainText.getBytes("UTF-8"));
base64Text = Base64.encodeToString(cipherData, Base64.DEFAULT);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return base64Text;
}
//############## Response(decrypt) ##############
public static String decryptData(String base64Text) {
String plainText = "";
try {
byte[] keyBytes = key.getBytes("UTF-8");
try {
byte[] cipherData = decrypt(ivBytes, keyBytes, Base64.decode(base64Text.getBytes("UTF-8"), Base64.DEFAULT));
plainText = new String(cipherData, "UTF-8");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return plainText;
}
}
简单调用如下
String en = AES256Cipher.encryptData("1234");
Log.e("enc length", en.length() + "");
Log.e("enc", en);
String de = AES256Cipher.decryptData(en);
Log.e("dec", de);
对于在 java 中使用的人,可以使用软件包 java.util 中的 Base64 将加密方法替换为this
base64Text =Base64.getEncoder().encodeToString(cipherData);
在解密方法中替换为这个
byte[] cipherData = decrypt(ivBytes, keyBytes,Base64.getDecoder().decode(base64Text.getBytes("UTF-8")));