DES加密的强化(二次DES叠加)

来源:互联网 发布:js中拼接html代码 编辑:程序博客网 时间:2024/05/13 19:57

在.NET 2.0 框架中,微软提供了一个DESCryptoServiceProvider 类。这个类定义了一个访问数据加密标准 (DES) 算法的加密服务提供程序 (CSP) 版本的包装对象。

其主要的属性为
   IV   获取或设置对称算法的初始化向量 (IV)。(从 SymmetricAlgorithm 继承。)
   Key   获取或设置数据加密标准 (DES) 算法的机密密钥。(从 DES 继承。)
等等

其主要的方法有
   Create   已重载。 创建加密对象的实例以执行数据加密标准(DES)算法。 (从 DES 继承。)
   CreateDecryptor  已重载。 创建对称数据加密标准 (DES) 解密器对象。 
   CreateEncryptor  已重载。 创建对称数据加密标准 (DES) 加密器对象。 
   GenerateIV  已重写。 生成用于该算法的随机初始化向量 (IV)。 
   GenerateKey  已重写。 生成用于该算法的随机密钥 (Key)。 
等等。
我们可以使用如下的方式对一个字符串进行加密。

        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="encryptString">要加密的内容</param>
        /// <param name="key">8位长对称密钥</param>
        /// <returns></returns>
        private static string _DesEncrypt(string encryptString, string key)
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 8));
            byte[] keyIV = keyBytes;
            byte[] inputByteArray = Encoding.UTF8.GetBytes(encryptString);
            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, provider.CreateEncryptor(keyBytes, keyIV), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Convert.ToBase64String(mStream.ToArray());
        }

其中encryptString 为待加密的串,key 为密钥,此处可以注意到我们使用了与密钥一致的向量IV。由于向量必须在加解密两端都提前获知,所以采用与密钥不一致的向量意义不大。
同样我们可以使用如下的方式对比一个加密的字符串进行解密

        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="decryptString">要解密的内容</param>
        /// <param name="key">8位长对称密钥</param>
        /// <returns></returns>
        private static string _DesDecrypt(string decryptString, string key)
        {
            byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 8));
            byte[] keyIV = keyBytes;
            byte[] inputByteArray = Convert.FromBase64String(decryptString);
            DESCryptoServiceProvider provider = new DESCryptoServiceProvider();
            MemoryStream mStream = new MemoryStream();
            CryptoStream cStream = new CryptoStream(mStream, provider.CreateDecryptor(keyBytes, keyIV), CryptoStreamMode.Write);
            cStream.Write(inputByteArray, 0, inputByteArray.Length);
            cStream.FlushFinalBlock();
            return Encoding.UTF8.GetString(mStream.ToArray());
        }
其中decryptString为待解密的串,key 为密钥。
DES算法是安全性比较高的一种算法,目前只有一种方法可以破解该算法,那就是穷举法。DES采用64位密钥技术,实际只有56位有效,8位用来校验的。譬如,有这样的一台PC机器,它能每秒计算一百万次,那么256位空间它要穷举的时间为2285年。所以这种算法还是比较安全的一种算法。
到此一个完整的对称密钥加解密程序就已经完成了,但是在实际使用中我们发现了两个问题。首先,向量IV只能使同一个文档中的相同字符产生不同的加密结果,防止猜测方式的解密。但当我们使用一个密钥多次对同一个字符串进行加密时就会发现,其加密结果是一样的。
如:我们使用此算法对字符串“abc”进行加密,结果为“qmFD8BLHmuQ=”。
反复使用同一密钥进行加密可发现结果均为“qmFD8BLHmuQ=”。
由此,我们可以发现当用户反复发送同样的操作字符串到发布服务器端时,加密数据很有可以被猜测破译。
第二个问题是,当我们发送了一次命令,如“stop server”执行停止服务后。加密的密文被复制并可能在不确定的时间被也可能被复制后伪造http请求头进行攻击发送,并被服务器接受且信任。可能造成命令被伪造。
二、针对需求实现对DES算法进行强化
对这上述问题我们考虑可以采用两种方式进行强化。
首先我们在传输时加入当前发送时间,我们的网站与内容发布服务位于同一台机器上,从发送到接收的时间可以设定一个时间长度,比如3秒,一但超出3秒,则不信任发送来的数据。这种方式,也可以在异机布署的时候使用,只要同步两台服务器的时间,并且适度加大时间允许长度就可以了。
而另一个问题则比较复杂。考虑到DES的密钥必须被提前获知,而做动态密钥的同步非常困难,甚至对这一功能的实现可能会影响项目的成本计划,所以不与考虑。
我们采取的方法是二次加密。
其主要原理时生成一个随机密钥对明文进行加密,然后将随机密钥附于密文头部,对随机密钥和密文使用约定密钥进行二次加密。
对应的其解密的实现算法是,首先使用约定密钥对二次加密密文进行解密,将解密的结果,分解成随机密钥和密文。再次使用随机密钥对密文进行解密就可以得到明文了。
相应的代码如下

        /// <summary>
        /// DES加密
        /// </summary>
        /// <param name="encryptString">要加密的内容</param>
        /// <param name="key">8位长对称密钥</param>
        /// <returns></returns>
        public static string DesEncrypt(string encryptString, string key)
        {
            string tempKey = GetDESKey();
            string tempStr = _DesEncrypt(encryptString, tempKey);
            tempStr = tempKey + tempStr;
            return _DesEncrypt(tempStr, key);
        }


        /// <summary>
        /// DES解密
        /// </summary>
        /// <param name="decryptString">要解密的内容</param>
        /// <param name="key">8位长对称密钥</param>
        /// <returns></returns>
        public static string DesDecrypt(string decryptString, string key)
        {
            string tempStr = _DesDecrypt(decryptString, key);
            string tempKey = tempStr.Substring(0, 8);
            tempStr = tempStr.Substring(8, tempStr.Length - 8);
            return _DesDecrypt(tempStr, tempKey);
        }

文中GetDESKey(); 方法返回一个八字节长的时间字符串。
此时我们在发送串中再加入发送时间
            string ordTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fffffff");
            string ordStr += “\r\n” + ordTime;

得到要发送的串后进行加密就可以进行发送了,此时我们可以看到发送的结果,完全相同的字符串在加密后产生了不一样的密文并携带了发送时间。有效的防止伪造请求。

原创粉丝点击