三重DES加密C# - 用Java解密

时间:2015-04-16 15:25:42

标签: java c# encryption tripledes

我从客户端服务器获取一个Triple 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中对Triple 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#decrypt code

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的内容

3 个答案:

答案 0 :(得分:2)

在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"));

您可能必须检查以删除所有&#39; 00&#39;在加密的字符串中,所以1D30CC3DE1641D7F5E821D13FC12 00 C3将成为1D30CC3DE1641D7F5E821D13FC12C3

(你必须检查它是否在十六进制表达式的边界内:1C01A1应该被修改,因为它在第二个Hexa 1C上有填充 0 1 A1:1C1A1

答案 1 :(得分:0)

你可以使用的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 "";
}

答案 2 :(得分:0)

如果有人像我一样遇到相同的问题,这是具有相同.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();
    }