【问题标题】:Triple DES Encrypt C# - Decrypt in Java三重 DES 加密 C# - 用 Ja​​va 解密
【发布时间】:2015-04-16 15:25:42
【问题描述】:

我从客户端服务器获得了一个三重 DES 解密字符串,它已经用 c# 编码(见下文):

using System.IO;
using System;
using System.Security.Cryptography;
using System.Collections;
using System.Text;

class Program
{
    static void Main()
    {
        Console.WriteLine("Hello, World!");

    var encryption = TripleDESEncrypt("12345678901234", "C9AF269DF8A78A06D1216BFFF8F0536A");
      Console.WriteLine(encryption);

    }

      public static string TripleDESEncrypt(string strClearText, string strKey)
        {
            byte[] bytClearText;
            byte[] bytClearTextChunk = new byte[8];
            byte[] bytEncryptedChunk = new byte[8];
            int BytesCount = 0;
            int nArrayPosition = 0;
            string strEncryptedChar;
            string strEncryptedText = "";

            ArrayList Input = new ArrayList();
            ArrayList Output = new ArrayList();

            TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();

            tdes.Key = HexToByteArray(strKey);
            tdes.Mode = CipherMode.ECB;

            ICryptoTransform tdesEncrypt = tdes.CreateEncryptor();

            bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);
            BytesCount = bytClearText.Length;

            for (int i = 0; i < BytesCount; i++)
            {
                if (nArrayPosition == 8)
                {
                    Input.Add(bytClearTextChunk);
                    bytClearTextChunk = new byte[8];
                    nArrayPosition = 0;
                }
                bytClearTextChunk[nArrayPosition] = bytClearText[i];
                nArrayPosition++;
            }

            if (nArrayPosition != 0)
                Input.Add(bytClearTextChunk);


            foreach (byte[] Cbyte in Input)
            {
                tdesEncrypt.TransformBlock(Cbyte, 0, 8, bytEncryptedChunk, 0);
                Output.Add(bytEncryptedChunk);
                bytEncryptedChunk = null;
                bytEncryptedChunk = new byte[8];
            }


            foreach (byte[] Cbyte in Output)
            {
                foreach (byte BByte in Cbyte)
                {
                    strEncryptedChar = BByte.ToString("X");
                    strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));
                    strEncryptedText += strEncryptedChar;
                }
            }

            return strEncryptedText;
        }
        private static byte[] HexToByteArray(string strHex)
        {
            byte[] bytArray = new byte[strHex.Length / 2];
            int positionCount = 0;

            for (int i = 0; i < strHex.Length; i += 2)
            {
                bytArray[positionCount] = byte.Parse(strHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
                positionCount++;
            }
            return bytArray;
        }
}

然后我尝试使用此密钥在 Java 中对它进行三重 DES 解密:C9AF269DF8A78A06D1216BFFF8F0536A

这是我要解密的代码:

public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {

        String UNICODE_FORMAT = "UTF8";
        String decryptedPinText = null;

        byte[] hexConvert = hexStringtoByteArray(encryptKey);

        SecretKey desKey = null;
        byte[] tdesKey = new byte[24];
        System.arraycopy(hexConvert, 0, tdesKey, 0,16);
        System.arraycopy(hexConvert, 0, tdesKey, 0,8);

        byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);

        KeySpec desKeySpec = new DESedeKeySpec(tdesKey);
        Cipher desCipher;
        SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
        desCipher = Cipher.getInstance("DESede/ECB/NoPadding");
        try {
            desKey = skf.generateSecret(desKeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }

        desCipher.init(Cipher.DECRYPT_MODE, desKey);

       byte[] decryptPin = desCipher.doFinal(pin.getBytes());
        decryptedPinText = new String(decryptPin, "UTF-8");
        return decryptedPinText;
    }

输出的样本将是输入/输出将是 "12345678901234" 但是,我得到的是杂乱无章的废话,例如 ��0�8��/0��

所以在 c# 和 java 之间有些东西会丢失...... 这是我之前问过here的问题的后续@

我很感激这方面的帮助

代码更改

   public String DesDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {

        String UNICODE_FORMAT = "UTF8";
        String decryptedPinText = null;



        SecretKey desKey = null;
        byte[] encryptKeyBytes = EncodingUtils.getAsciiBytes(encryptKey);
        byte[] tdesKey = new byte[24];
        System.arraycopy(encryptKeyBytes, 8, tdesKey, 0, 8);
        System.arraycopy(encryptKeyBytes, 0, tdesKey, 8, 16);
        KeySpec desKeySpec = new DESedeKeySpec(tdesKey);
        Cipher desCipher;
        SecretKeyFactory skf = SecretKeyFactory.getInstance("DESede");
        desCipher = Cipher.getInstance("DESede/ECB/NoPadding");
        try {
            desKey = skf.generateSecret(desKeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        desCipher.init(Cipher.DECRYPT_MODE, desKey);

        byte[] decryptPin = desCipher.doFinal(EncodingUtils.getAsciiBytes(pin));

        decryptedPinText = new String(decryptPin, "ASCII");
        return decryptedPinText;
    }

c#解密代码

using System.IO;
using System;
using System.Security.Cryptography;
using System.Collections;
using System.Text;

class Program
{
    static void Main()
    {
        Console.WriteLine("Hello, World!");

        var encryption = TripleDESDecrypt("1D30CC3DE1641D7F5E821D13FC1200C3", "C9AF269DF8A78A06D1216BFFF8F0536A");
        Console.WriteLine(encryption);

    }

      public static string TripleDESDecrypt(string strEncryptedText, string strKey)
        {
            string errorMessage = "";
            int errorCode = 0;
            string strDecryptedText = "";

            try
            {
                byte[] bytEncryptedChunk = new byte[8];
                byte[] bytClearTextChunk = new byte[8];
                byte[] _bytesEmpty = new byte[8];
                int BytesCount = 0;
                int positionCount = 0;


                ArrayList Input = new ArrayList();
                ArrayList Output = new ArrayList();

                TripleDESCryptoServiceProvider tdes = (TripleDESCryptoServiceProvider)TripleDESCryptoServiceProvider.Create();

                tdes.Key = HexToByteArray(strKey);
                tdes.Mode = CipherMode.ECB;

                ICryptoTransform tdesDecrypt = tdes.CreateDecryptor();

                BytesCount = strEncryptedText.Length;

                for (int i = 0; i < BytesCount; i += 2)
                {
                    if (positionCount == 8)
                    {
                        positionCount = 0;
                        Input.Add(bytEncryptedChunk);
                        bytEncryptedChunk = new byte[8];
                    }

                    bytEncryptedChunk[positionCount] = byte.Parse(strEncryptedText.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
                    positionCount++;
                }

                if (positionCount != 0)
                {
                    Input.Add(bytEncryptedChunk);
                }

                foreach (byte[] Cbyte in Input)
                {
                    tdesDecrypt.TransformBlock(Cbyte, 0, 8, _bytesEmpty, 0);
                    tdesDecrypt.TransformBlock(Cbyte, 0, 8, bytClearTextChunk, 0);
                    Output.Add(bytClearTextChunk);
                    bytClearTextChunk = null;
                    bytClearTextChunk = new byte[8];
                }

                foreach (byte[] Cbyte in Output)
                {
                    strDecryptedText += ASCIIEncoding.ASCII.GetString(Cbyte);
                }
            }
            catch (Exception ex)
            {
                errorCode = 1;
                errorMessage = ex.Message;


            }
Console.WriteLine(strDecryptedText);
            return strDecryptedText;
        }

        private static byte[] HexToByteArray(string strHex)
        {
            byte[] bytArray = new byte[strHex.Length / 2];
            int positionCount = 0;

            for (int i = 0; i < strHex.Length; i += 2)
            {
                bytArray[positionCount] = byte.Parse(strHex.Substring(i, 2), System.Globalization.NumberStyles.HexNumber);
                positionCount++;
            }
            return bytArray;
        }
}

这将返回输入到加密 12345678901234 中的内容

【问题讨论】:

  • 您是否尝试过使用 PKCS5Padding 填充进行解密,就像您的其他问题的回答者建议的那样???
  • @Barett 加密中没有添加填充,我不是很熟悉,但是如果加密中没有填充,我认为我不应该在解密中添加填充
  • 您是否独立测试过每个部分?尝试 C# 端产生了一个加密字符串 1D30CC3DE1641D7F5E821D13FC1200C3 在线工具说它应该是 c8 2b 53 b6 c1 ef bb 23 84 12 dd 6d 2f de 6a 4a
  • 我也尝试过这些工具 tools4noobs.com/online_tools/encrypt 给了我 xTRqxlMmkakJZBrHF8dPHw== 所以我不确定发生了什么。我确实知道这可行,因为它也是一个 Windows 应用程序,并且 c# 中的解密是正确的。还要注意的是不同的十六进制类型

标签: java c# encryption tripledes


【解决方案1】:

在您的 C# 代码中,您使用 ASCII:

bytClearText = ASCIIEncoding.ASCII.GetBytes(strClearText);

在 Java 中使用 UNICODE:

byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);

尝试将您的 C# 更改为使用 UNICODE 或将您的 java 代码更改为使用 ASCII。

此外,由于 C# 正在填充输出:

strEncryptedChar = strEncryptedChar.PadLeft(2, Convert.ToChar("0"));

您可能必须检查以删除加密字符串中的所有“00”,因此 1D30CC3DE1641D7F5E821D13FC1200C3 将变为 1D30CC3DE1641D7F5E821D13FC12C3

(您必须检查它是否在十六进制表达式的边界内:1C01A1 可能应该被修改,因为它在第二个 Hexa 1C 01 A1: 1C1A1

上有一个填充

【讨论】:

  • 感谢您的回复...c# 代码不在我的控制范围内,但是,我实际上并没有使用 encryptedBytes 字节 []
  • 所以我将 `byte[] encryptKeyBytes = encryptKey.getBytes(UNICODE_FORMAT);` 换成了 EncodingUtils.getAsciiBytes(encryptKey); 并使用了 encryptedKeyBytes,不幸的是它仍然是乱七八糟的垃圾
  • 你是否也改变了decryptedPinText = new String(decryptPin, "UTF-8"); to decryptedPinText = new String(decryptPin, "ASCII");
  • 如果有帮助,我可以提供 c# 解密吗?
  • 什么是 C# 加密字符串?是 1D30CC3DE1641D7F5E821D13FC1200C3 吗?
【解决方案2】:

根据https://stackoverflow.com/a/33768305/1140304,您可以使用 java代码中的unicode而不是UTF-8

在 C# 中加密:

public static string Encrypt2(string clearText,string key)
{
    try
    {
        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());
        }
        return encryptedText;
    }
    catch (Exception exception)
    {
        return "";
    }
}

在c#中解码你可以使用:

public static string Decrypt2(string cipher,string key)
{
    try
    {
        byte[] clearBytes = Convert.FromBase64String(cipher);
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] md5Bytes = md5.ComputeHash(Encoding.Unicode.GetBytes(key));
        string encryptedText = "";
        TripleDES des = new TripleDESCryptoServiceProvider();
        des.KeySize = 128;
        des.Mode = CipherMode.CBC;
        des.Padding = PaddingMode.PKCS7;
        byte[] ivBytes = new byte[8];
        des.Key = md5Bytes;
        des.IV = ivBytes;
        ICryptoTransform ct = des.CreateDecryptor();
        byte[] resultArray = ct.TransformFinalBlock(clearBytes, 0, clearBytes.Length);
        encryptedText = Encoding.Unicode.GetString(resultArray);
        return encryptedText;
    }
    catch (Exception exception)
    {
        return "";
    }
}

现在,对于 java 中的加密,您可以使用:

private String _encrypt2(String clearText,String key )
{
    try
    {
        /**
         * create md5
         */
        MessageDigest md = MessageDigest.getInstance("md5");
        byte[] digestOfPassword = md.digest(key.getBytes("UTF-16LE"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        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.encodeToString(cipherText,Base64.DEFAULT);
        return output;
    }
    catch (Exception ex) {}
    return "";
}

在java中解密:

private String _decrypt2(String encryptText,String key)
{

    MessageDigest md = null;
    byte[] digestOfPassword = null;

    try
    {
        byte[] message = Base64.decode(encryptText.getBytes("UTF-16LE"), Base64.DEFAULT);

        /**
         * make md5
         */
        md = MessageDigest.getInstance("md5");
        digestOfPassword = md.digest(key.getBytes("UTF-16LE"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        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.DECRYPT_MODE, secretKey, iv);
        byte[] cipherText = cipher.doFinal(message);

        return new String(cipherText, "UTF-16LE");
    }
    catch (NoSuchAlgorithmException e)
    {
        e.printStackTrace();
    }
    catch (UnsupportedEncodingException e)
    {
        e.printStackTrace();
    }
    catch (InvalidKeyException e)
    {
        e.printStackTrace();
    }
    catch (InvalidAlgorithmParameterException e)
    {
        e.printStackTrace();
    }
    catch (NoSuchPaddingException e)
    {
        e.printStackTrace();
    }
    catch (BadPaddingException e)
    {
        e.printStackTrace();
    }
    catch (IllegalBlockSizeException e)
    {
        e.printStackTrace();
    }
    return "";
}

【讨论】:

    【解决方案3】:

    如果有人发现自己遇到了和我一样的问题,这里是同一个 .NET 解密函数的 java 实现(android):

     public static byte[] byteArrayConcat(byte[] array1, byte[] array2) {
            byte[] result = new byte[array1.length + array2.length];
            System.arraycopy(array1, 0, result, 0, array1.length);
            System.arraycopy(array2, 0, result, array1.length, array2.length);
            return result;
        }
    
    
     private byte[] fGPKeyTo3DESKey(byte[] GPKey) {
    
            byte[] _3DESKey = new byte[24];
            byte[] tmp = new byte[8];
    
            arraycopy(GPKey, 0, tmp, 0, 8);
    
            _3DESKey = DaPlugUtils.byteArrayConcat(GPKey, tmp);
    
            return _3DESKey;
        }
    
     private static byte[] hexStringtoByteArray(String hex) {
            int len = hex.length();
    
            byte[] data = new byte[len / 2];
            for (int i = 0; i < len; i += 2) {
                data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4) + Character.digit(hex.charAt(i + 1), 16));
            }
            return data;
        }
    
    public String desDecryptPin(String pin, String encryptKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidKeySpecException {
    
            int bytesCount = 0;
            int positionCount = 0;
    
    
            byte[] bytEncryptedChunk = new byte[8];
    
            ArrayList<byte[]> Input = new ArrayList();
            bytesCount = pin.length();
    
            for (int i = 0; i < bytesCount; i += 2) {
                if (positionCount == 8) {
                    positionCount = 0;
                    Input.add(bytEncryptedChunk);
                    bytEncryptedChunk = new byte[8];
                }
                bytEncryptedChunk[positionCount] = (byte) (Integer.parseInt(pin.substring(i, i + 2), 16));
                positionCount++;
            }
    
            if (positionCount != 0) {
                Input.add(bytEncryptedChunk);
            }
    
    
            byte[] _3DESKey = fGPKeyTo3DESKey(hexStringtoByteArray(encryptKey));
    
            DESedeKeySpec keySpec = new DESedeKeySpec(_3DESKey);
            SecretKey k = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
            Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
            cipher.init(Cipher.DECRYPT_MODE, k);
    
    
            String res = "";
    
            for (byte[] bs : Input) {
                byte[] decryptPin = cipher.doFinal(bs);
                String a = new String(decryptPin, StandardCharsets.US_ASCII);
    
                res += a;
            }
    
            return res.trim();
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-30
      • 1970-01-01
      • 1970-01-01
      • 2012-07-09
      • 2011-10-22
      • 2012-05-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多