[英]C# encryption method to Java
我有一种方法,可以在C#中使用键和盐将String转换为编码的String,并尝试在Java中为其创建等效项。
C#方法如下:
public static string Encrypt<T>(string Value, string Key, string Salt) where T : SymmetricAlgorithm, new()
{
DeriveBytes deriveBytes = new Rfc2898DeriveBytes(Key, Encoding.Unicode.GetBytes(Salt));
SymmetricAlgorithm algorithm = new T();
byte[] keyBytes = deriveBytes.GetBytes(algorithm.KeySize >> 3);
byte[] ivBytes = deriveBytes.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateEncryptor(keyBytes, ivBytes);
using (MemoryStream buffer = new MemoryStream())
{
using (CryptoStream stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write))
{
using (StreamWriter writer = new StreamWriter(stream, Encoding.Unicode))
{
writer.Write(Value);
}
}
return Convert.ToBase64String(buffer.ToArray());
}
}
我在整个SO和整个Web上都尝试了许多不同的解决方案,但都无济于事。 我什至有一个样本:
value("YourId|YourFacId")
,
key("6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA=")
,
salt("FPSJxiSMpAavjKqyGvVe1A==")
这些都发送到上述方法,并返回以下返回字符串:
"Y5w4A3pDZwTcq+FGyqUMO/mZSr6hSst8qiac9zDbfso9FQQbdTDsKnkKDT7SHl4y"
。
我尚未在SO中找到与我的问题匹配的任何内容,因此我在这里寻求帮助。 任何线索将不胜感激。 谢谢。
尝试链接到另一个问题,没有发现我所没有的东西。 在我的示例中,没有密码要处理。 这是我为此失败的许多尝试之一:
private String encrypt(String user) throws Exception
{
Cipher deCipher;
Cipher enCipher;
SecretKeySpec key;
IvParameterSpec ivSpec;
String plainKey = "6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA=";
String salt = "FPSJxiSMpAavjKqyGvVe1A==";
String result = "";
ivSpec = new IvParameterSpec(salt.getBytes());
key = new SecretKeySpec(plainkey.getBytes(), "AES");
enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] input = convertToByteArray(user);
enCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
return new String(enCipher.doFinal(input).toString());
}
我只能为您提供部分信息,以帮助您继续前进:
使用的算法是256位AesManaged 。 模式是CBC
,填充是PKCS7
,密钥大小= 256。
通过这个小测试程序,可以显示给您的样本值是正确的
static void Main(string[] args)
{
string key = "6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA=";
string salt = "FPSJxiSMpAavjKqyGvVe1A==";
string value = "YourId|YourFacId";
string result = Encrypt<AesManaged>(value, key, salt);
Console.WriteLine(result);
string expected = "Y5w4A3pDZwTcq+FGyqUMO/mZSr6hSst8qiac9zDbfso9FQQbdTDsKnkKDT7SHl4y";
if (expected.Equals(result))
{
Console.WriteLine("strings are equal");
}
else
{
Console.WriteLine("strings are NOT equal!");
}
}
key
和salt
是纯字符串(不是base-64编码)。 对于他们来说,要获取字节,您必须在Java中使用
byte[] saltBytes = salt.getBytes("UnicodeLittleUnmarked");
byte[] keyBytes = key.getBytes("UTF-8");
PBKDF2使用SHA1摘要和1000次迭代(我使用BouncyCastle的PKCS5S2ParametersGenerator
进行了检查)
final int iterations = 1000;
PKCS5S2ParametersGenerator pbkdf = new PKCS5S2ParametersGenerator(new SHA1Digest());
pbkdf.init(keyBytes, saltBytes, iterations);
final int keySize = 32 * 8;
final int ivSize = 16 * 8;
CipherParameters cp = pbkdf.generateDerivedParameters(keySize, ivSize);
那给了我下面的ivBytes和keyBytes
// Java ivBytes
// [-33, 102, -108, 66, -46, 89, 122, 102, -63, -15, -92, 66, -88, -29, 67, -59]
// Java keyBytes:
// [-127, 125, -40, -123, 60, -70, 16, -6, -15, -116, 127, 93, 46, 80, 26, 31, -36, 47, -120, -37, 57, 21, -94, 44, 98, -119, -109, 48, -71, 15, -36, 80]
这些是我在C#代码中得到的等效签名:
// C# ivBytes:
// [223, 102, 148, 66, 210, 89, 122, 102, 193, 241, 164, 66, 168, 227, 67, 197]
// C# keyBytes:
// [129, 125, 216, 133, 60, 186, 16, 250, 241, 140, 127, 93, 46, 80, 26, 31, 220, 47, 136, 219, 57, 21, 162, 44, 98, 137, 147, 48, 185, 15, 220, 80]
当我阅读C#代码时,还必须将值字节检索为UTF-16 little-endian
byte[] valueBytes = value.getBytes("UnicodeLittleUnmarked");
从这里开始,我无法继续。 我能告诉你的最后一件事是加密的字节数组(在base-64编码之前的最后一步)是什么样的:
// C# crypted:
// [99, 156, 56, 3, 122, 67, 103, 4, 220, 171, 225, 70, 202, 165, 12, 59, 249, 153, 74, 190, 161, 74, 203, 124, 170, 38, 156, 247, 48, 219, 126, 202, 61, 21, 4, 27, 117, 48, 236, 42, 121, 10, 13, 62, 210, 30, 94, 50]
// or signed:
// [99, -100, 56, 3, 122, 67, 103, 4, -36, -85, -31, 70, -54, -91, 12, 59, -7, -103, 74, -66, -95, 74, -53, 124, -86, 38, -100, -9, 48, -37, 126, -54, 61, 21, 4, 27, 117, 48, -20, 42, 121, 10, 13, 62, -46, 30, 94, 50]
多亏了Stefan和一点点摆弄,我发现C#代码在编码消息的值时包含字节顺序标记,而在编码salt的值时不包含字节顺序标记。 等效的Java代码如下所示:
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
class SO39257791
{
private static final int KEY_LEN = 256 / 8, BLOCK_LEN = 16, ITERATIONS = 1000;
public static void main(String... argv)
throws Exception
{
String value = "YourId|YourFacId";
String key = "6JxI1HOSg7KQj4fJ1Xb3L1T6AVdLZLBAPFSqOjh2UoA=";
String salt = "FPSJxiSMpAavjKqyGvVe1A==";
String good = "Y5w4A3pDZwTcq+FGyqUMO/mZSr6hSst8qiac9zDbfso9FQQbdTDsKnkKDT7SHl4y";
String output = encrypt(value, key, salt);
if (output.equals(good))
System.out.println("strings are equal");
else
System.out.println("strings are NOT equal!");
}
static final String encrypt(String value, String key, String salt)
throws GeneralSecurityException, UnsupportedEncodingException
{
/* Derive the key, given password and salt. */
byte[] s = salt.getBytes(StandardCharsets.UTF_16LE);
int dkLen = (KEY_LEN + BLOCK_LEN) * 8;
KeySpec spec = new PBEKeySpec(key.toCharArray(), s, ITERATIONS, dkLen);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] dk = factory.generateSecret(spec).getEncoded();
SecretKey secret = new SecretKeySpec(Arrays.copyOfRange(dk, 0, KEY_LEN), "AES");
byte[] iv = Arrays.copyOfRange(dk, KEY_LEN, KEY_LEN + BLOCK_LEN);
/* Encrypt the message. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] plaintext = value.getBytes("UnicodeLittle"); /* Use Byte Order Mark */
byte[] ciphertext = cipher.doFinal(plaintext);
return Base64.getEncoder().encodeToString(ciphertext);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.