C#解密(DES)Java的加密结果

2 篇文章 0 订阅

工作需要,要工C#实现Java的加密解密功能。

资料有

1.Java代码

package com.sitech.crmpd.security;
/**
 *  两级界面集成 加解密   
 *  meixy  2013-03-14 
 */
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;

public class IntegrationDESPlus {

	private static final String ALGORITHM = "DES";
	private static SecretKey secretKey = null;
	//初始化 密钥存放的相对路径(视具体情况修改)
	private static String KeyFilePath =  "secretekey351.dat";
	
	//加载密钥文件
	public IntegrationDESPlus(){
		loadSecretKey(true,KeyFilePath);
	}
	//加载密钥文件
	public IntegrationDESPlus(String kf){
		setKeyFile(kf);
		loadSecretKey(true,KeyFilePath);
	}
	
	public String getKeyFile() {
		return KeyFilePath;
	}

	public void setKeyFile(String kf) {
		if("".equals(kf) || kf == null)
			return;
		KeyFilePath = kf;
		
	}
	
	//加解密 测试
	public static void main(String args[]){
		
		IntegrationDESPlus sd = new IntegrationDESPlus();
		//加密
		String enc_result=sd.encrypt("111111");    	 
    	System.out.println("351 encrypt result="+enc_result);
    	//解密
    	String dec_result=sd.decrypt(enc_result);
    	System.out.println("351 decrypt result="+dec_result);    
    	
    	
	}
	
	/**
     * 加密
     * @return original plain text
     */
	 public String encrypt(String source) {
	        String result = null;
	        //loadSecretKey(local,SERVERKEY);
	        try {
	            Cipher cipher = Cipher.getInstance(ALGORITHM);
	            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
	            byte[] cipherByte = cipher.doFinal(source.getBytes());

	            result = byte2hex(cipherByte);
	        } catch (Exception e) {
	            e.printStackTrace();
	        }

	        return result;
	    }
	 
	 	/**
	     * 解密
	     * @return original plain text
	     */
	  public String decrypt(String source) {
	      String result = null;
	        //loadSecretKey(local,SERVERKEY);

	       try {
	           Cipher cipher = Cipher.getInstance(ALGORITHM);
	           cipher.init(Cipher.DECRYPT_MODE, secretKey);

	           byte[] clearByte = cipher.doFinal(hex2byte(source));
	           result = new String(clearByte);
	       } catch (Exception e) {
	            e.printStackTrace();
	       }

	       return result;
	 }
	    
	    /**
	     * 加载密钥文件
	     */
	  
	    private void loadSecretKey(boolean local,String SERVERKEY) {

	        /**
	         * if this program is not execute in container,
	         * i.e. local is true, we should confirm weather
	         * secretekey file exist or not,  it doesn't
	         * exist, we should generate it.
	         */
	        //if (local) {
	            //generateKey("secretekey.dat");
	        //}
	    	
	        try {
	        	SERVERKEY = this.getClass().getResource("").getPath()+SERVERKEY;
	        	System.out.println("SERVERKEY="+SERVERKEY);
	        	InputStream inStream = new FileInputStream(SERVERKEY);
	            ObjectInputStream is = new ObjectInputStream(inStream);
	            secretKey = (SecretKey)is.readObject();
	            is.close();
	        } catch (NullPointerException e) {
	            StringBuffer msg = new StringBuffer();
	            msg.append("Secret Key file can not be found, so: \r\n");
	            msg.append("1: find and install the corresponding");
	            msg.append(" keyFile.\r\n");
	            msg.append("2: generate a new key file, encrypt the ");
	            msg.append("password and set the configuration file ");
	            msg.append("again. \r\n");
	            System.out.println(msg.toString());
	        } catch (Exception e) {
	            e.printStackTrace();
	        }
	    }
	    
	    /**
	     * convert bytes to hex,
	     * the result is ideal to store and transfer.
	     * @param bytes byte array
	     * @return hex string
	     */
	    private String byte2hex(byte[] bytes) {
	        String result = "";
	        String temp = "";
	        for (int i = 0; i < bytes.length; i++) {
	            temp = (Integer.toHexString(bytes[i] & 0XFF));
	            if (temp.length() == 1) {
	                result += "0" + temp; 
	            } else {
	                result += temp;
	            }
	        }

	        return result.toUpperCase();
	    }
	    
	    /**
	     * convert hex to byte array,
	     * result byte array ready for calculation
	     * @param bytes byte array
	     * @return hex string
	     */
	    private byte[] hex2byte(String hex) {
	        char[] arr = hex.toCharArray();
	        byte[] b = new byte[hex.length() / 2];
	        for (int i = 0, j = 0, l = hex.length(); i < l; i++, j++) {
	            String swap = "" + arr[i++] + arr[i];
	            int byteint = Integer.parseInt(swap, 16) & 0xFF;
	            b[j] = new Integer(byteint).byteValue();
	        }
	        return b;
	    }
	    
	    /**
		 * in DES arithmetic, we must store secret key
		 * we store the key in a dat file for following usage,
		 * in addition, we should use certain secret key!
		 */
		public  void generateKey(String fileName) {
			try {
				File keyFile = new File(fileName);
				if (!keyFile.exists()) {
					KeyGenerator keygen = KeyGenerator.getInstance(ALGORITHM);
					SecretKey secretKey = keygen.generateKey();
					ObjectOutputStream os = new ObjectOutputStream(
						new BufferedOutputStream(
						new java.io.FileOutputStream(keyFile)));
					os.writeObject(secretKey);
					os.flush(); os.close();
				} else {
					System.out.println("Secret Key file has exist.");
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
}

2. 一个编码样例

String type="01";
String user="admin";
String sn="123456";
String orisn="123456789dgdfgdg";
String cust_id="123143324324324";

admin <=> 4500A125845A2CF0
 
http://10.210.42.8/idcBusiness.do?
type=7E54F48557F4C326&user=4500A125845A2CF0&sn=A988E19289AAE29D&orisn=AD97DA31EB80205CDE6250D2CE4C50A9120ABD5247750190&;cust_id=92087F4E9D696F1FBBE2B543B858A462 
						01		admin			123456				123456789dgdfgdg					123143324324324

type=7E54F48557F4C326

user=4500A125845A2CF0

sn=A988E19289AAE29D

orisn=AD97DA31EB80205CDE6250D2CE4C50A9120ABD5247750190

cust_id=92087F4E9D696F1FBBE2B543B858A462


3. 一个secretekey351.dat文件

目标:在ASP.Net后台实现解密工作。


方案有两个,一个是理解Java并用c#实现,或者寻找别人写好的实现代码;一个是用C#加载Java,这个有可能,估计会需要安装Java的运行环境。


先理解一下前面的Java代码:

    1.从文件中加载SecretKey,这个文件说白了是SecretKey的序列化。

	        	InputStream inStream = new FileInputStream(SERVERKEY);
	            ObjectInputStream is = new ObjectInputStream(inStream);
	            secretKey = (SecretKey)is.readObject();

    2.用key解密字符串

	 	/**
	     * 解密
	     * @return original plain text
	     */
	  public String decrypt(String source) {
	      String result = null;
	        //loadSecretKey(local,SERVERKEY);

	       try {
	           Cipher cipher = Cipher.getInstance(ALGORITHM);
	           cipher.init(Cipher.DECRYPT_MODE, secretKey);

	           byte[] clearByte = cipher.doFinal(hex2byte(source));
	           result = new String(clearByte);
	       } catch (Exception e) {
	            e.printStackTrace();
	       }

	       return result;
	 }

关键的类是SecretKey和Cipher,如果要加密还需要KeyGenerator类,都在javax.crypto里面。

ALGORITHM = "DES"说明是EDS算法。


搜索“C#调用javax.crypto”找到和我有相同需求的帖子:

资料1:http://bbs.csdn.net/topics/390569120?page=1 (大家好,我这里有个java加密方法,我想写成C#的,本人能力有限,希望大神们帮帮吗)

资料2:http://www.cnblogs.com/-lzb/articles/4942031.html (Java aes加密C#解密的取巧方法)

参考资料:

资料3:https://www.cnblogs.com/liluping860122/p/4026015.html()

核心知识:

Java与C#的Byte类型值范围不同,Java的Byte范围为-128至127,c#的Byte范围是0-255。


如果能转换的话,关键还是要从文件中获取转换用的参数,从文件读取SecretKey并获取参数。这个需要c#能实现ReadObject类似的功能


搭建Java环境(Java7+Eclipse),创建项目运行,查看SecretKey


-113 13 38 -26 88 -48 -74 -98

查看secretekey351.dat文件,通过比较另外生成的多个生成的.dat文件,发现只有一部分是有差异的


8F0D26E658D0B69E

HexConvert():

    private static byte[] HexConvert(string hex)
    {
        hex = hex.ToUpper();
        int len = (hex.Length / 2);
        byte[] result = new byte[len];
        char[] achar = hex.ToCharArray();
        for (int i = 0; i < len; i++)
        {
            int pos = i * 2;
            string by = new string(new char[] { achar[pos], achar[pos + 1] });
            result[i] = Convert.ToByte(by, 16);
        }
        return result;
    }

转换成byte:143 13 38 230 88 208 182 158 (C#)

跟前面的比较:-113 13 38 -26 88 -48 -74 -98 (Java)

加上知识:Java的Byte范围为-128至127,c#的Byte范围是0-255

写一个函数模拟转换成Jave的byte

    private static int[] HexConvertJava(string hex)
    {
        hex = hex.ToUpper();
        int len = (hex.Length / 2);
        int[] result = new int[len];
        char[] achar = hex.ToCharArray();
        for (int i = 0; i < len; i++)
        {
            int pos = i * 2;
            string by = new string(new char[] { achar[pos], achar[pos + 1] });
            result[i] = Convert.ToByte(by, 16);
            if (result[i] > 127)
            {
                result[i] -= 256;
            }
        }
        return result;
    }

确实转换为:-113 13 38 -26 88 -48 -74 -98。

第一步,解析secretekey351.dat得到8F0D26E658D0B69E,手动完成。

第二步,尝试解密。

明文:admin,密文:4500A125845A2CF0,秘钥 :8F0D26E658D0B69E


一般的C#DES加密解密过程

参考资料:http://blog.csdn.net/kebi007/article/details/70158945

加密解密核心方法:

    /// <summary>
    /// C# DES加密方法
    /// </summary>
    /// <param name="by">要加密的字符串</param>
    /// <param name="key">密钥</param>
    /// <param name="iv">向量</param>
    /// <returns>加密后的字符串</returns>
    public static byte[] DESEncrypt(byte[] by, byte[] key, byte[] iv)
    {
        using (DESCryptoServiceProvider sa
            = new DESCryptoServiceProvider { Key = key, IV = iv })
        {
            using (ICryptoTransform ct = sa.CreateEncryptor())
            {
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
                    {
                        cs.Write(by, 0, by.Length);
                        cs.FlushFinalBlock();
                    }
                    return ms.ToArray();
                }
            }
        }
    }

    /// <summary>
    /// C# DES解密方法
    /// </summary>
    /// <param name="byt">待解密的字符串</param>
    /// <param name="key">密钥</param>
    /// <param name="iv">向量</param>
    /// <returns>解密后的字符串</returns>
    public static byte[] DESDecrypt(byte[] byt, byte[] key, byte[] iv)
    {
        using (DESCryptoServiceProvider sa =
            new DESCryptoServiceProvider
            { Key = key, IV = iv })
        {
            using (ICryptoTransform ct = sa.CreateDecryptor())
            {
                using (var ms = new MemoryStream())
                {
                    using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
                    {
                        cs.Write(byt, 0, byt.Length);
                        cs.FlushFinalBlock();
                    }
                    return ms.ToArray();
                }
            }
        }
    }

参数和结果都是byte,但是实际上byte是从string得到,并转换成string结果的,如:

    /// <summary>
    /// C# DES加密方法
    /// </summary>
    /// <param name="encryptedValue">要加密的字符串</param>
    /// <param name="key">密钥</param>
    /// <param name="iv">向量</param>
    /// <returns>加密后的字符串</returns>
    public static string DESEncryptByUTF8Base64(string originalValue, string key, string iv)
    {
        return Convert.ToBase64String(DESEncrypt(Encoding.UTF8.GetBytes(originalValue),Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(iv)));
    }

    /// <summary>
    /// C# DES解密方法
    /// </summary>
    /// <param name="encryptedValueBase64">待解密的字符串</param>
    /// <param name="key">密钥</param>
    /// <param name="iv">向量</param>
    /// <returns>解密后的字符串</returns>
    public static string DESDecryptByUTF8Base64(string encryptedValueBase64, string key, string iv)
    {
        return Encoding.UTF8.GetString(DESDecrypt(Convert.FromBase64String(encryptedValueBase64), Encoding.UTF8.GetBytes(key), Encoding.UTF8.GetBytes(iv)));
    }

    /// <summary>
    /// C# DES加密方法
    /// </summary>
    /// <param name="encryptedValue">要加密的字符串</param>
    /// <param name="key">密钥</param>
    /// <param name="iv">向量</param>
    /// <returns>加密后的字符串</returns>
    public static string DESEncryptByGBKHex(string originalValue, string key, string iv)
    {
        return BytesToHex(DESEncrypt(Encoding.GetEncoding("GBK").GetBytes(originalValue), Encoding.GetEncoding("GBK").GetBytes(key), Encoding.GetEncoding("GBK").GetBytes(iv)));
    }

    /// <summary>
    /// C# DES解密方法
    /// </summary>
    /// <param name="encryptedValueHex">待解密的字符串</param>
    /// <param name="key">密钥</param>
    /// <param name="iv">向量</param>
    /// <returns>解密后的字符串</returns>
    public static string DESDecryptByByGBKHex(string encryptedValueHex, string key, string iv)
    {
        return Encoding.GetEncoding("GBK").GetString(DESDecrypt(HexToBytes(encryptedValueHex), Encoding.GetEncoding("GBK").GetBytes(key), Encoding.GetEncoding("GBK").GetBytes(iv)));
    }

这里的转换有各种方式,明文的转换可以是UTF8,可以是GBK;密文的转换可以是Base64,可以是Hex。

其中转换函数

    private static byte[] HexToBytes(string hex)
    {
        hex = hex.ToUpper();
        int len = (hex.Length / 2);
        byte[] result = new byte[len];
        char[] achar = hex.ToCharArray();
        for (int i = 0; i < len; i++)
        {
            int pos = i * 2;
            string by = new string(new char[] { achar[pos], achar[pos + 1] });
            result[i] = Convert.ToByte(by, 16);
        }
        return result;
    }


    private static string BytesToHex(byte[] bytes)
    {
        StringBuilder ret = new StringBuilder();
        foreach (byte b in bytes)
        {
            ret.AppendFormat("{0:X2}", b); //{0:X2} 大写
        }
        var hex = ret.ToString();
        return hex;
    }

使用时要用相同的转换方式:

        string content = "admin";
        Console.WriteLine("原文:" + content);

        string keyText = "12345678";
        string ivText = "87654321";
        
        string resultEncrypt = DESEncryptByUTF8Base64(content, keyText, ivText);
        string resultDecrypt = DESDecryptByUTF8Base64(resultEncrypt, keyText, ivText);
        Console.WriteLine("加密结果1:" + resultEncrypt);
        Console.WriteLine("解密结果1:" + resultDecrypt);

        string resultEncrypt2 = DESEncryptByGBKHex(content, keyText, ivText);
        string resultDecrypt2 = DESDecryptByByGBKHex(resultEncrypt2, keyText, ivText);
        Console.WriteLine("加密结果2:" + resultEncrypt2);
        Console.WriteLine("解密结果2:" + resultDecrypt2);

尝试用现有资料界面,参考前面资料1用GBK编码。

        string keyHex = "8F0D26E658D0B69E";
        byte[] keyBytes = HexToBytes(keyHex);

        byte[] ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };

        string user = "admin";
        byte[] userBytes= Encoding.GetEncoding("GBK").GetBytes(user);
        
        byte[] encryptResultBytes = DESEncrypt(userBytes, keyBytes, ivBytes);
        string encryptResult = BytesToHex(encryptResultBytes);
        
        byte[] decryptResultBytes = DESDecrypt(encryptResultBytes, keyBytes, ivBytes);
        string decryptResult = Encoding.GetEncoding("GBK").GetString(decryptResultBytes);
        Console.WriteLine("原文:" + user);
        Console.WriteLine("加密结果:" + encryptResult);
        Console.WriteLine("解密结果:" + decryptResult);

结果:


成功了!

再测试其他的

    private static void TestEncryptDecrypt()
    {
        TestEncryptDecrypt("01", "7E54F48557F4C326");
        TestEncryptDecrypt("admin", "4500A125845A2CF0");
        TestEncryptDecrypt("123456", "A988E19289AAE29D");
        TestEncryptDecrypt("123456789dgdfgdg", "AD97DA31EB80205CDE6250D2CE4C50A9120ABD5247750190");
        TestEncryptDecrypt("123143324324324", "92087F4E9D696F1FBBE2B543B858A462");
    }

    /// <param name="text">明文</param>
    /// <param name="result">预期密文</param>
    private static void TestEncryptDecrypt(string text,string result)
    {
        string keyHex = "8F0D26E658D0B69E";
        byte[] keyBytes = HexToBytes(keyHex);

        byte[] ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };

        //string user = "admin";
        byte[] userBytes = Encoding.GetEncoding("GBK").GetBytes(text);

        byte[] encryptResultBytes = DESEncrypt(userBytes, keyBytes, ivBytes);
        string encryptResult = BytesToHex(encryptResultBytes);

        byte[] decryptResultBytes = DESDecrypt(encryptResultBytes, keyBytes, ivBytes);
        string decryptResult = Encoding.GetEncoding("GBK").GetString(decryptResultBytes);

        Console.WriteLine("原文:{0,-20}加密结果:{1,-50}解密结果:{2}", text, encryptResult,decryptResult);
        Console.WriteLine("原文:{0,-20}预期结果:{1,-50}是否相同:{2}\n", text, result, encryptResult == result);
    }

结果:


字符长度少时没问题,长度多了后就不行了,只有最前面部分是相同的。

另外,用预期密文解密会出现异常。


怎么回事呢?

秘钥和解密的过程应该是没问题的。

观察,应该是8个字符明文对应生成16个字符密文,8个一组,

尝试将12314332 4324324分成2组加密,结果:


12314332加密结果是32位的字符串,但是前半部分和预期结果的前半部分相同。

4324324加密结果是和预期结果的后半部分相同。

有搞头

考虑分组加密、解密。

是对string分组还是对byte分组?

两种都试试

    /// <param name="text">明文</param>
    /// <param name="result">预期密文</param>
    private static void TestEncryptDecrypt_StringList(string text, string result)
    {
        string keyHex = "8F0D26E658D0B69E";
        byte[] keyBytes = HexToBytes(keyHex);
        byte[] ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
        var stringList = GetStringList(text);//每8个字符串为一组
        Console.WriteLine("原文:{0}", text);
        for (int i = 0; i < stringList.Count; i++)
        {
            string item = stringList[i];
            byte[] userBytes = Encoding.GetEncoding("GBK").GetBytes(item);
            byte[] encryptResultBytes = DESEncrypt(userBytes, keyBytes, ivBytes);
            string encryptResult = BytesToHex(encryptResultBytes);
            Console.WriteLine("加密结果[{0}]:{1,-50}", i, encryptResult);
        }
        Console.WriteLine();
    }

    private static List<string> GetStringList(string text)
    {
        List<string> stringList = new List<string>();
        string temp = null;
        for (int i = 0; i < text.Length; i++)
        {
            int j = i%8;
            if (j == 0)
            {
                if (temp != null)
                {
                    stringList.Add(temp);
                }
                temp = "";
            }
            if (temp != null)
                temp += text[i];
        }
        if (temp != null)
        {
            stringList.Add(temp);
        }
        return stringList;
    }

    /// <param name="text">明文</param>
    /// <param name="result">预期密文</param>
    private static void TestEncryptDecrypt_ByteList(string text, string result)
    {
        string keyHex = "8F0D26E658D0B69E";
        byte[] keyBytes = HexToBytes(keyHex);
        byte[] ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] userBytes = Encoding.GetEncoding("GBK").GetBytes(text);
        //var bytesList = GetBytesArray(userBytes);//每8个byte为一组,不能用这个
        var bytesList = GetBytesList(userBytes);//每8个byte为一组
        Console.WriteLine("原文:{0}", text);
        for (int i = 0; i < bytesList.Count; i++)
        {
            byte[] encryptResultBytes = DESEncrypt(bytesList[i].ToArray(), keyBytes, ivBytes);
            string encryptResult = BytesToHex(encryptResultBytes);
            Console.WriteLine("加密结果[{0}]:{1,-50}", i, encryptResult);
        }
        Console.WriteLine();
    }

    private static List<List<byte>> GetBytesList(byte[] userBytes)
    {
        List<List<byte>> bytesList = new List<List<byte>>();
        List<byte> temp = null;
        for (int i = 0; i < userBytes.Length; i++)
        {
            int j = i % 8;
            if (j == 0)
            {
                if (temp != null)
                {
                    bytesList.Add(temp);
                }
                temp =new List<byte>();
            }
            if (temp != null)
            {
                temp.Add(userBytes[i]);
            }
        }
        if (temp != null)
        {
            bytesList.Add(temp);
        }
        return bytesList;
    }

    private static List<byte[]> GetBytesArray(byte[] userBytes)
    {
        List<byte[]> bytesList = new List<byte[]>();
        byte[] temp = null;
        for (int i = 0; i < userBytes.Length; i++)
        {
            int j = i % 8;
            if (j == 0)
            {
                if (temp != null)
                {
                    bytesList.Add(temp);
                }
                temp = new byte[8];
            }
            if (temp != null)
                temp[j] = userBytes[i];
        }
        if (temp != null)
        {
            bytesList.Add(temp);
        }
        return bytesList;
    }

结果一样


考虑以后可能出现的中文,使用byte分组的方式继续。

    /// <param name="text">明文</param>
    /// <param name="result">预期密文</param>
    private static void TestEncryptDecrypt_ByteList(string text, string result)
    {
        string keyHex = "8F0D26E658D0B69E";
        byte[] keyBytes = HexToBytes(keyHex);
        byte[] ivBytes = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
        byte[] userBytes = Encoding.GetEncoding("GBK").GetBytes(text);
        //var bytesList = GetBytesArray(userBytes);//每8个byte为一组,不能用这个
        var bytesList = GetBytesList(userBytes);//每8个byte为一组
        Console.WriteLine("原文:{0}", text);
        string encryptResult = "";
        for (int i = 0; i < bytesList.Count; i++)
        {
            byte[] encryptResultPartBytes = DESEncrypt(bytesList[i].ToArray(), keyBytes, ivBytes);//加密
            string encryptResultPart = BytesToHex(encryptResultPartBytes);

            byte[] decryptResultPartBytes = DESDecrypt(encryptResultPartBytes, keyBytes, ivBytes);//解密
            string decryptResultPart = Encoding.GetEncoding("GBK").GetString(decryptResultPartBytes);

            string beforePart= encryptResultPart.Substring(0, 16);//取前半部分
            encryptResult += beforePart;

            string decryptResultPart2 = "";
            //byte[] encryptResultPartBytes2 = HexToBytes(beforePart);
            //byte[] decryptResultPartBytes2 = DESDecrypt(encryptResultPartBytes2, keyBytes, ivBytes);//解密
            //decryptResultPart2 = Encoding.GetEncoding("GBK").GetString(decryptResultPartBytes2);

            Console.WriteLine("加密结果[{0}]:{1,-50}解密结果[{0}]:{2}\t{3}", i, encryptResultPart, decryptResultPart, decryptResultPart2);
        }
        Console.WriteLine("加密结果:{0}", encryptResult);
        Console.WriteLine("预期结果:{0}", result);
        Console.WriteLine("是否相同:{0}", result== encryptResult);

        Console.WriteLine();
    }

将分组的加密结果组织起来能够得到和Java一样的结果但是!将预期的密文分组解密还是会出现前面的“不正确的数据”的异常。

通过研究资料1中提供的代码,理解了des.Padding = PaddingMode.None的含义,在加密和解密前都加上:

            if (by.Length%8 == 0)//已经对其
            {
                //sa.Mode = CipherMode.CBC;
                sa.Padding = PaddingMode.None;//默认是PKCS7,在by没有对其时使用
            }

能够分组解密了。

测试TestEncryptDecrypt_ByteList函数


123143324324324可以了123456789dgdfgdg还是不行

怀疑是123456789dgdfgdg后面跟了一个不可见的字符串,但是空格 \n \t都不是。

不考虑加密,尝试对92087F4E9D696F1FBBE2B543B858A462和

AD97DA31EB80205CDE6250D2CE4C50A9120ABD5247750190进行解密试试。

120ABD5247750190部分解密的结果是byte[] {8,8,8,8,8,8,8,8},变为字符串的话是\b\b\b\b\b\b\b\b,不可见的。将这部分去除就是正确的解密结果了。


接下来做开始的获取秘钥的代码,前面是手动获取的,接下来要写代码。

通过代码知道.dat文件的大小是263,key的位置是169开始。

    private static string LoadKeyFromFile(string path)
    {
        byte[] bytes = LoadFile(path);
        int index = FindKeyIndex(bytes);//和手动获取的Key比较找到位置
        //index=169
        byte[] keyBytes2=new byte[8];
        Array.Copy(bytes, index, keyBytes2, 0, 8);
        string hex = BytesToHex(keyBytes2);
        return hex;
    }

    private static int FindKeyIndex(byte[] bytes)
    {
        byte[] keyBytes = HexToBytes("8F0D26E658D0B69E");
        int index = 0;
        for (int i = 0; i < bytes.Length; i++)
        {
            if (bytes[i] == keyBytes[0])
            {
                int j = 0;
                for (; j < keyBytes.Length; j++)
                {
                    if (keyBytes[j] != bytes[i + j])
                    {
                        break;
                    }
                }
                if (j == 8)
                {
                    index = i;
                }
            }
        }
        return index;
    }

    private static byte[] LoadFile(string path)
    {
        FileStream fs = new FileStream(path, FileMode.Open);
        //获取文件大小
        long size = fs.Length;
        byte[] array = new byte[size];
        //将文件读到byte数组中
        fs.Read(array, 0, array.Length);
        fs.Close();

        return array;
    }


最后将现有的代码都整理一下,写成一个类

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

namespace DESTest
{
    /// <summary>
    /// DES加密解密(结果和Java的代码一致)
    /// </summary>
    public class DESCipher
    {
        private static byte[] EncryptionIV4
        {
            get
            {
                return new byte[] { 0, 0, 0, 0, 0, 0, 0, 0 };
            }
        }

        public byte[] SecretKey;

        public DESCipher(string keyFilePath)
        {
            SecretKey = LoadKeyFromFile(keyFilePath);
        }

        public DESCipher(byte[] secretKey)
        {
            SecretKey = secretKey;
        }

        private static byte[] LoadKeyFromFile(string path)
        {
            byte[] bytes = ByteHelper.LoadFile(path); //大小是263
            int index = 169; //固定位置
            byte[] keyBytes2 = new byte[8];
            Array.Copy(bytes, index, keyBytes2, 0, 8);
            return keyBytes2;
        }

        /// <summary>
        /// 解密
        /// </summary>
        public string Decrypt(string source)
        {
            byte[] bytes = ByteHelper.HexToBytes(source);
            var bytesList = ByteHelper.GetBytesList(bytes);//每8个byte为一组
            string decryptResult = "";
            for (int i = 0; i < bytesList.Count; i++)
            {
                byte[] decryptResultPartBytes = DESDecrypt(bytesList[i].ToArray(), SecretKey, EncryptionIV4);//解密
                string decryptResultPart = ByteHelper.BytesToString(decryptResultPartBytes);
                decryptResult += decryptResultPart;
            }
            return decryptResult;
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="source"></param>
        public string Encrypt(string source)
        {
            byte[] userBytes = Encoding.GetEncoding("GBK").GetBytes(source);
            var bytesList = ByteHelper.GetBytesList(userBytes);//每8个byte为一组
            if (userBytes.Length % 8 == 0)//不知道是否有必要
            {
                bytesList.Add(new List<byte>() { 8, 8, 8, 8, 8, 8, 8, 8 });
            }
            string encryptResult = "";
            for (int i = 0; i < bytesList.Count; i++)
            {
                byte[] encryptResultPartBytes = DESEncrypt(bytesList[i].ToArray(), SecretKey, EncryptionIV4);//加密
                string encryptResultPart = ByteHelper.BytesToHex(encryptResultPartBytes);
                encryptResult += encryptResultPart;
            }
            return encryptResult;
        }

        /// <summary>
        /// C# DES加密方法
        /// </summary>
        /// <param name="by">要加密的字符串</param>
        /// <param name="key">密钥</param>
        /// <param name="iv">向量</param>
        /// <returns>加密后的字符串</returns>
        public static byte[] DESEncrypt(byte[] by, byte[] key, byte[] iv)
        {
            using (DESCryptoServiceProvider sa
                = new DESCryptoServiceProvider { Key = key, IV = iv })
            {
                if (by.Length % 8 == 0)//已经对其
                {
                    //sa.Mode = CipherMode.CBC;
                    sa.Padding = PaddingMode.None;//默认是PKCS7,在by没有对其时使用
                }
                using (ICryptoTransform ct = sa.CreateEncryptor())
                {
                    using (var ms = new MemoryStream())
                    {
                        using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
                        {
                            try
                            {
                                cs.Write(by, 0, by.Length);
                                cs.FlushFinalBlock();
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex);
                            }
                        }
                        return ms.ToArray();
                    }
                }
            }
        }

        /// <summary>
        /// C# DES解密方法
        /// </summary>
        /// <param name="byt">待解密的字符串</param>
        /// <param name="key">密钥</param>
        /// <param name="iv">向量</param>
        /// <returns>解密后的字符串</returns>
        public static byte[] DESDecrypt(byte[] by, byte[] key, byte[] iv)
        {
            using (DESCryptoServiceProvider sa =
                new DESCryptoServiceProvider
                { Key = key, IV = iv })
            {
                if (by.Length % 8 == 0)//已经对其
                {
                    //sa.Mode = CipherMode.CBC;
                    sa.Padding = PaddingMode.None;//默认是PKCS7,在by没有对其时使用
                }
                using (ICryptoTransform ct = sa.CreateDecryptor())
                {
                    using (var ms = new MemoryStream())
                    {
                        using (var cs = new CryptoStream(ms, ct, CryptoStreamMode.Write))
                        {
                            try
                            {
                                cs.Write(by, 0, by.Length);
                                cs.FlushFinalBlock();
                            }
                            catch (Exception ex)
                            {
                                Console.WriteLine(ex);
                                return null;
                            }
                        }
                        return ms.ToArray();
                    }
                }
            }
        }
    }

    public static class ByteHelper
    {
        public static byte[] LoadFile(string path)
        {
            FileStream fs = new FileStream(path, FileMode.Open);
            //获取文件大小
            long size = fs.Length;
            byte[] array = new byte[size];
            //将文件读到byte数组中
            fs.Read(array, 0, array.Length);
            fs.Close();

            return array;
        }

        /// <summary>
        /// 每8个byte为一组
        /// </summary>
        /// <param name="userBytes"></param>
        /// <returns></returns>
        public static List<List<byte>> GetBytesList(byte[] userBytes)
        {
            List<List<byte>> bytesList = new List<List<byte>>();
            List<byte> temp = null;
            for (int i = 0; i < userBytes.Length; i++)
            {
                int j = i % 8;
                if (j == 0)
                {
                    if (temp != null)
                    {
                        bytesList.Add(temp);
                    }
                    temp = new List<byte>();
                }
                if (temp != null)
                {
                    temp.Add(userBytes[i]);
                }
            }
            if (temp != null)
            {
                bytesList.Add(temp);
            }
            return bytesList;
        }

        public static string BytesToString(byte[] bytes)
        {
            List<byte> list = new List<byte>();
            foreach (byte b in bytes)
            {
                if (b > 8)
                {
                    list.Add(b);
                }
            }
            return Encoding.GetEncoding("GBK").GetString(list.ToArray());
        }

        public static byte[] HexToBytes(string hex)
        {
            hex = hex.ToUpper();
            int len = (hex.Length/2);
            byte[] result = new byte[len];
            char[] achar = hex.ToCharArray();
            for (int i = 0; i < len; i++)
            {
                int pos = i*2;
                string by = new string(new char[] {achar[pos], achar[pos + 1]});
                result[i] = Convert.ToByte(by, 16);
            }
            return result;
        }

        public static string BytesToHex(byte[] bytes)
        {
            StringBuilder ret = new StringBuilder();
            foreach (byte b in bytes)
            {
                ret.AppendFormat("{0:X2}", b); //{0:X2} 大写
            }
            var hex = ret.ToString();
            return hex;
        }
    }
}

好了,两天的研究成果。

有空再研究一下方案二,C#调用Java。










  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DES(Data Encryption Standard)是一种对称加密算法,用于保护计算机和网络中的数据安全。DES算法使用相同的密钥进行加密解密操作。 首先,我们来讨论DES加密过程。在加密过程中,原始数据会被分成64位的数据块,并经过一系列复杂的置换、替代和混合等步骤,最终生成一个64位的密文数据块。加密过程中所使用的密钥也是64位的,通过子密钥的生成和迭代,将密钥与数据进行混合运算,从而实现加密操作。DES算法的强度在于它的迭代次数,通常会进行16轮迭代来确保数据的安全性。 接下来,我们来探讨DES解密过程。在解密过程中,密文数据块会经过与加密过程相反的步骤,通过逆向置换、逆向替代和逆向混合等步骤,最终还原为原始的64位明文数据块。与加密过程类似,解密过程中使用的密钥也是相同的。通过迭代生成的子密钥,将密钥与密文数据块进行反向混合运算,实现解密操作。解密过程同样进行16轮迭代,以确保数据的正确性和完整性。 总之,DES算法是一种使用相同密钥进行加密解密的对称加密算法。加密过程将原始数据分成64位数据块,并通过一系列复杂的步骤生成相应的密文数据块。解密过程则是将密文数据块经过相反的操作还原为原始的明文数据块。DES算法可以保护数据的机密性和安全性,广泛应用于计算机和网络领域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值