【问题标题】:C# to Java TripleDES , different resultsC# 到 Java TripleDES,不同的结果
【发布时间】:2016-02-19 08:07:08
【问题描述】:

我正在尝试将此 C# 加密算法转换为 Java;但是,我一直在检索略有不同的加密结果(尚未尝试解密)。指出我无法更改 C# 代码可能也很重要。

但是,当我在 C# 中对字符串“test”调用加密函数时,它将返回 nmj8MjjO52y928Syqf0J+g== 但是在 Java 中,它将返回 C6xyQjJCqVo=

C#

private static String key = "012345678901234567890123";

public static string encrypt(String stringToEncrypt)
{
    TripleDES des = CreateDES(key);
    ICryptoTransform ct = des.CreateEncryptor();
    byte[] input = Encoding.Unicode.GetBytes(stringToEncrypt);
    byte[] output = ct.TransformFinalBlock(input, 0, input.Length);
    //return output;
    return Convert.ToBase64String(output);
}


public static String decrypt(string encryptedString)
{
    byte[] input = Convert.FromBase64String(encryptedString);
    TripleDES des = CreateDES(key);
    ICryptoTransform ct = des.CreateDecryptor();
    byte[] output = ct.TransformFinalBlock(input, 0, input.Length);
    return Encoding.Unicode.GetString(output);
}


public static TripleDES CreateDES(string key)
{
    MD5 md5 = new MD5CryptoServiceProvider();
    TripleDES des = new TripleDESCryptoServiceProvider();
    des.Key = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
    des.IV = new byte[des.BlockSize / 8];
    return des;
}

我尝试转换为 Java

private static String key = "012345678901234567890123";

public static void main(String[] args) throws Exception {
    String text = "test";
    String codedtext = encrypt(text);
    //String decodedtext = decrypt(codedtext);

    System.out.println(new String(codedtext));
    //System.out.println(decodedtext); 
}

public static String encrypt(String message) throws Exception {
    MessageDigest md = MessageDigest.getInstance("md5");
    byte[] digestOfPassword = md.digest(key.getBytes("unicode"));
    byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
    //for (int j = 0, k = 16; j < 8;) {
    //  keyBytes[k++] = keyBytes[j++];
    //}

    SecretKey key = new SecretKeySpec(keyBytes, "DESede");
    IvParameterSpec iv = new IvParameterSpec(new byte[8]);
    Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, key, iv);

    byte[] plainTextBytes = message.getBytes();
    byte[] cipherText = cipher.doFinal(plainTextBytes);

    String output = Base64.encode(cipherText);

    return output;
}

public static String decrypt(String message) throws Exception {
    byte[] messageBytes = Base64.decode(message);

    MessageDigest md = MessageDigest.getInstance("md5");
    byte[] digestOfPassword = md.digest(key.getBytes());
    byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
    for (int j = 0, k = 16; j < 8;) {
        keyBytes[k++] = keyBytes[j++];
    }

    SecretKey key = new SecretKeySpec(keyBytes, "DESede");
    IvParameterSpec iv = new IvParameterSpec(new byte[8]);
    Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
    decipher.init(Cipher.DECRYPT_MODE, key, iv);

    byte[] plainText = decipher.doFinal(messageBytes);

    return new String(plainText);
}

有人看到我在监督什么吗?

【问题讨论】:

  • 您是否尝试过Google Search on Java TripleDes 这是一个进行搜索的链接stackoverflow.com/questions/20227/… 将您所拥有的与此处接受的答案进行比较...祝您好运
  • Java 代码在散列之前使用不同的编码将密钥转换为字节并没有帮助。 (而且我怀疑两者都与 C# 中的不同 - 这是您应该检查的第一件事。)
  • @JonSkeet 两种编码都是 Unicode(除非您在解密方法中注意到一种,但两个加密字符串不同)
  • @Jujunol:Encoding.Unicode 是小端 UTF-16。 Java 中的"unicode" 不是指定的编码之一,但您可能会发现并非如此。当然在我的机器上,这两个不会给出相同的结果。您应该在 Java 中使用 StandardCharsets.UTF_16LE 以获得相同的结果。
  • @JonSkeet 谢谢,我不知道这两个 unicode 是不同的。你是对的,它确实改变了结果,但它现在是3P6itCSdfWs=

标签: java c# encryption character-encoding


【解决方案1】:

你错过了两件事。您在 c# 端使用 16 长度的密钥,因为它不像 Java 版本那样填充。默认情况下,如果密钥长度为 16 字节,它将用密钥的前 8 个字节填充。

要在 Java 端进行此匹配,您必须取消注释将填充添加到键的行:

for (int j = 0, k = 16; j < 8;) {
  keyBytes[k++] = keyBytes[j++];
}

SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, "DESede");

此外,在 java 方面,有人建议确保对文本使用 UTF-LE。确保将它用于一切。所以这些行:

byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));

byte[] plainTextBytes = clearText.getBytes("UTF-16LE");

一般来说,我会确保设置所有三元组对象的 c# 参数,而不是依赖于默认值。

这里有两个在c#和java中匹配的版本

Java

String key = "012345678901234567890123";
String clearText = "test";

MessageDigest md = MessageDigest.getInstance("md5");
byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));

byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
String byteText = Arrays.toString(keyBytes);

for (int j = 0, k = 16; j < 8;) {
  keyBytes[k++] = keyBytes[j++];
}

SecretKey secretKey = new SecretKeySpec(keyBytes, 0, 24, "DESede");

IvParameterSpec iv = new IvParameterSpec(new byte[8]);
Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");

cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);

byte[] plainTextBytes = clearText.getBytes("UTF-16LE");
byte[] cipherText = cipher.doFinal(plainTextBytes);

String output = Base64.encode(cipherText);

c#

string clearText = "test";
string key = "012345678901234567890123";
string encryptedText = "";

MD5 md5 = new MD5CryptoServiceProvider();
TripleDES des = new TripleDESCryptoServiceProvider();
des.KeySize = 128;
des.Mode = CipherMode.CBC;
des.Padding = PaddingMode.PKCS7;

byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));

byte[] ivBytes = new byte[8];


des.Key = md5Bytes;

des.IV = ivBytes;

byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);

ICryptoTransform ct = des.CreateEncryptor();
using (MemoryStream ms = new MemoryStream())
{
    using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
    {
        cs.Write(clearBytes, 0, clearBytes.Length);
        cs.Close();
    }
    encryptedText = Convert.ToBase64String(ms.ToArray());
}

已编辑:两个版本现在都返回测试用例结果“nmj8MjjO52y928Syqf0J+g=="

【讨论】:

  • 不幸的是,正如原始问题所述,我无法修改现有的 C# 代码。有没有办法让你的答案更接近 Java 方面?
  • 只需要在c#端编辑参数即可。在 java 端,您应该恢复用前 8 个字节填充数组末尾的循环
  • @Jujunol - 你能发布你的最终代码吗?拜托了!!...我需要使用 Java DESede 并将其转换为 C#。您的帮助将不胜感激..它使用的是DESede(我认为它有2个键和每字节7位)......在C#中我的理解是它使用3个键和每字节8位......但我有点扔...提前谢谢!!!
  • @OG。我需要采用 Java DESede 并将其转换为 C#。您的帮助将不胜感激..它使用的是DESede(我认为它有2个键和每字节7位)......在C#中我的理解是它使用3个键和每字节8位......但我有点扔...提前谢谢!!!
猜你喜欢
  • 1970-01-01
  • 2015-01-23
  • 2014-07-07
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 2014-09-18
相关资源
最近更新 更多