zoukankan      html  css  js  c++  java
  • Java和.NET使用DES对称加密的区别

    Java和.NET的系统类库里都有封装DES对称加密的实现方式,但是对外暴露的接口却各不相同,甚至有时会让自己难以解决其中的问题,比如Java加密后的结果在.NET中解密不出来等,由于最近项目有跨Java和.NET的加解密,经过我的分析调试,终于让它们可以互相加密解密了。

      DES加密

      DES是一种对称加密(Data Encryption Standard)算法,以前我写过一篇文章:.NET中加密解密相关知识,有过简单描述。

      DES算法一般有两个关键点,第一个是加密算法,第二个是数据补位。

      加密算法常见的有ECB模式和CBC模式:

      ECB模式:电子密本方式,这是JAVA封装的DES算法的默认模式,就是将数据按照8个字节一段进行DES加密或解密得到一段8个字节的密文或者明文,最后一段不足8个字节,则补足8个字节(注意:这里就涉及到数据补位了)进行计算,之后按照顺序将计算所得的数据连在一起即可,各段数据之间互不影响。

      CBC模式:密文分组链接方式,这是.NET封装的DES算法的默认模式,它比较麻烦,加密步骤如下:

      1、首先将数据按照8个字节一组进行分组得到D1D2......Dn(若数据不是8的整数倍,就涉及到数据补位了)

      2、第一组数据D1与向量I异或后的结果进行DES加密得到第一组密文C1(注意:这里有向量I的说法,ECB模式下没有使用向量I)

      3、第二组数据D2与第一组的加密结果C1异或以后的结果进行DES加密,得到第二组密文C2

      4、之后的数据以此类推,得到Cn

      5、按顺序连为C1C2C3......Cn即为加密结果。

      数据补位一般有NoPadding和PKCS7Padding(JAVA中是PKCS5Padding)填充方式,PKCS7Padding和PKCS5Padding实际只是协议不一样,根据相关资料说明:PKCS5Padding明确定义了加密块是8字节,PKCS7Padding加密快可以是1-255之间。但是封装的DES算法默认都是8字节,所以可以认为他们一样。数据补位实际是在数据不满8字节的倍数,才补充到8字节的倍数的填充过程。

      NoPadding填充方式:算法本身不填充,比如.NET的padding提供了有None,Zeros方式,分别为不填充和填充0的方式。

      PKCS7Padding(PKCS5Padding)填充方式:为.NET和JAVA的默认填充方式,对加密数据字节长度对8取余为r,如r大于0,则补8-r个字节,字节为8-r的值;如果r等于0,则补8个字节8。比如:

      加密字符串为为AAA,则补位为AAA55555;加密字符串为BBBBBB,则补位为BBBBBB22;加密字符串为CCCCCCCC,则补位为CCCCCCCC88888888。

      .NET中的DES加密

      对于.NET,框架在System.Security.Cryptography命名空间下提供了DESCryptoServiceProvider作为System.Security.Cryptography.DES加密解密的包装接口,它提供了如下的4个方法:

    1. public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV)  
    2. public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV)  
    3. public override void GenerateIV()  
    4. public override void GenerateKey()

      从.NET类库封装情况,加解密需要传入一个Key和IV向量。而且Key必须为8字节的数据,否则会直接抛异常出来,当使用ECB模式下,不管传入什么IV向量,加密结果都一样。示例代码如下:

    1. public static string EncryptWithJava(string key, string str)  
    2. {  
    3.     if (key.Length < 8 || string.IsNullOrEmpty(str))  
    4.     {  
    5.         throw new Exception("加密key小于8或者加密字符串为空!");  
    6.     }  
    7.     byte[] bKey = Encoding.UTF8.GetBytes(key.Substring(0, 8));  
    8.     byte[] bIV = IV;  
    9.     byte[] bStr = Encoding.UTF8.GetBytes(str);  
    10.     try 
    11.     {  
    12.         DESCryptoServiceProvider desc = new DESCryptoServiceProvider();  
    13.         desc.Padding = PaddingMode.PKCS7;//补位 
    14.         desc.Mode = CipherMode.ECB;//CipherMode.CBC 
    15.         using (MemoryStream mStream = new MemoryStream())  
    16.         {  
    17.             using (CryptoStream cStream = new CryptoStream(mStream, desc.CreateEncryptor(bKey, bIV), CryptoStreamMode.Write))  
    18.             {  
    19.                 cStream.Write(bStr, 0, bStr.Length);  
    20.                 cStream.FlushFinalBlock();  
    21.                 StringBuilder ret = new StringBuilder();  
    22.                 byte[] res = mStream.ToArray();  
    23.                 foreach (byte b in res)  
    24.                 {  
    25.                     ret.AppendFormat("{0:x2}", b);  
    26.                 }  
    27.                 return ret.ToString();  
    28.             }  
    29.         }  
    30.     }  
    31.     catch 
    32.     {  
    33.         return string.Empty;  
    34.     }  
    35. }





     由于为ECB模式,因此IV这里设置什么值都是可以的,当为CBC模式下,则需要设置为其他值,比如:public static byte[] IV = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 },才能正常加密解密。

      JAVA中的DES加密

      JAVA的javax.crypto.Cipher包下,提供了加密解密的功能,它的静态getInstance方法,可以返回一个Cipher对象,一般有public static final Cipher getInstance(String transformation)方法,transformation为:algorithm/mode/padding,分别表示算法名称,比如DES,也可以在后面包含算法模式和填充方式,但也可以只是算法名称,如为:"DES/CBC/PKCS5Padding","DES"等。JAVA中默认的算法为ECB,默认填充方式为PKCS5Padding。Cipher的Init方法用来初始化加密对象,常见的有:

    1. public final void init(int opmode, Key key, AlgorithmParameterSpec params)  
    2. public final void init(int opmode,Key key, SecureRandom random)

      用SecureRandom时,一般用于不需要IV的算法模式,示例代码如下:

    1. public static String encrypt2(String src) throws Exception {  
    2.        SecureRandom sr = new SecureRandom();  
    3.        DESKeySpec ks = new DESKeySpec(KEY.getBytes("UTF-8"));  
    4.        SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");  
    5.        SecretKey sk = skf.generateSecret(ks);  
    6.        Cipher cip = Cipher.getInstance("DES/CBC/PKCS5Padding");//Cipher.getInstance("DES");  
    7.        IvParameterSpec iv2 = new IvParameterSpec(IV);  
    8.        cip.init(Cipher.ENCRYPT_MODE, sk, iv2);//IV的方式  
    9.        //cip.init(Cipher.ENCRYPT_MODE, sk, sr);//没有传递IV  
    10.        String dest = byteToHex(cip.doFinal(src.getBytes("UTF-8")));  
    11.        return dest;  
    12.     }

      当默认用DES,JAVA会用ECB模式,因此这里IV向量没有作用,这里,但当用CBC模式下,如果还是用SecureRandom,则每次加密的结果都会不一样,因为JAVA内部会用随机的IV来初始化Cipher对象,如示例代码,由于Cipher.getInstance("DES/CBC/PKCS5Padding")使用了CBC,因此我这里用的javax.crypto.spec.IvParameterSpec包下的IvParameterSpec来初始化向量IV:

    Private final static byte[] IV = new byte[] {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01};

      总结

      对于.NET和JAVA在使用DES对称加密时,需要大家指定一样的算法和填充模式,并且JAVA在写DES加解密算法时,还需要根据创建Cipher对象的不同,正确使用IV向量。在不同系统需要互相数据时,必须要明确的是加密算法,Key和算法模式,再根据不同模式是否需要IV向量,最后是填充模式。

      本文是经过自己翻阅资料和反复调试代码而出来的,如有问题,请指正。

    转载自 :http://www.blogjava.net/qileilove/archive/2012/05/23/378898.html

  • 相关阅读:
    升级windows 11小工具
    windows 10更新升级方法
    您需要了解的有关 Oracle 数据库修补的所有信息
    Step by Step Apply Rolling PSU Patch In Oracle Database 12c RAC Environment
    Upgrade Oracle Database Manually from 12.2.0.1 to 19c
    如何应用版本更新 12.2.0.1.210420(补丁 32507738 – 2021 年 4 月 RU)
    xtrabackup 安装、备份和恢复
    Centos_Lvm expand capacity without restarting CentOS
    Centos_Lvm_Create pv vg lv and mount
    通过全备+relaylog同步恢复被drop的库或表
  • 原文地址:https://www.cnblogs.com/LinQianXun/p/5016991.html
Copyright © 2011-2022 走看看