Duwamish密码分析篇, Part 3
Duwamish密码分析篇, Part 3
Written by: Rickie Lee
Nov. 07, 2004
通过前面关于《Duwamish密码分析篇, Part 1-2》的POST,可以了解到Duwamish中关于Password的处理方式。Duwamish 7.0范例中的帐户密码通过SHA1散列运算和对散列执行Salt运算后,然后以byte形式存放在Database中,避免明文的方式,以提高系统的安全性。
但是,由于散列是单向操作,使用散列算法对原始密码加密后将无法再恢复。因此,在实际的应用系统中,上述的加密过程有一个小问题:就是当有大量的用户忘记了自己的Password,如何帮助他们恢复自己的Password呢?这个问题地球人都不知道。
因此,对于一般的商业应用,通过.Net的加密/解密类库来同时实现上述目的,既加密Password等重要信息,同时也可以在必要的时候解密这些信息。
加密算法使可以将数据掩盖起来,除了特定人员能够对其解密外,其他人员不大可能通过数学方法读取该数据。但如果希望读取该数据,则可以为其提供一个特定的“密钥”,使其能够解密并读取数据。.NET Framework 中有多种可用的加密/解密算法。
目前有两种加密方法:
对称算法(或密钥算法)的速度非常快,非常适于加密大型的数据流。这些算法可以加密数据,也可以解密数据。对称加密技术的数据交换两边(即加密方和解密方)必须使用一个保密的私有密钥。
不对称算法(或公钥算法)没有对称算法快,但其代码较难破密。这些算法取决于两个密钥,一个是私钥,另一个是公钥。公钥用来加密消息,私钥是可以解密该消息的唯一密钥。公钥和私钥通过数学方法链接在一起,因此要成功进行加密交换,必须获得这两个密钥。由于可能会影响到计算机性能,因此不对称算法不太适用于加密大量数据。不对称算法的常见用法是将对称密钥和初始化向量加密并传输给对方。然后在双方之间来回发送的消息中使用对称算法加密和解密数据。不对称算法主要有RSA、DSA等,主要用于网络数据的加密。保护HTTP传输安全的SSL就是使用非对称技术。
本文先主要学习.Net中如下对称算法(或密钥算法)类库,包括以下几种:
DES(Data Encryption Standard),TripleDES,RC2,Rijndael
对称算法(或密钥算法)使用一个密钥和一个初始化向量 (Initialization Vector,IV) 来保证数据的安全。加密的功效取决于所用密钥的大小,密钥越长,保密性越强。典型的密钥长度有64位、128位、192位、256位和512位。使用该数据的双方都必须知道这个密钥和初始化向量才能够加密和解密数据。必须确保该密钥的安全,否则其他人将有可能解密该数据并读取该消息。初始化向量只是一个随机生成的字符集,使用它可以确保任何两个文本都不会生成相同的加密数据。然后,在此基础上学习开发一套标准的加密/解密通用类库,供今后开发应用系统时使用。
.Net Framework内置加密/解密算法类库
.NET Framework 为各种最广泛使用的对称加密算法提供了支持。.NET构架从基本的SymmetricAlgorithm类扩展出来四种算法:
·System.Security.Cryptography.DES
·System.Security.Cryptography.TripleDES
·System.Security.Cryptography.RC2
·System.Security.Cryptography.Rijndael
.NET的对称加密和解密通过CryptoStream类来处理的,它继承自System.IO.Stream,使用 CryptoStream 对象的 Write 方法将数据写入到内存数据流(Memory Stream),这就是进行实际加密/解密的方法。
先以DES算法为例,了解.Net为我们提供的简单加密/解密过程:
(1)DES加密
上图Encrypt实例代码:
private void btnEncrypt_Click(object sender, System.EventArgs e)
{
SymmetricAlgorithm mCSP = new DESCryptoServiceProvider();
ICryptoTransform ct;
MemoryStream ms;
CryptoStream cs;
byte[] byt;
byte [] key, iv;
// If this property is a null reference (Nothing in Visual Basic) when it is used,
// GenerateKey is called to create a new random value.
key = mCSP.Key;
// If this property is a null reference (Nothing in Visual Basic) when it is used,
// GenerateIV is called to create a new random value.
iv = mCSP.IV;
// Creates a symmetric Data Encryption Standard (DES) encryptor object.
ct = mCSP.CreateEncryptor(key, iv);
// Refresh textboxes
txtKey.Text = Convert.ToBase64String(key);
txtIV.Text = Convert.ToBase64String(iv);
byt = Encoding.Unicode.GetBytes(txtOriginal.Text.Trim());
ms = new MemoryStream();
cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(byt, 0, byt.Length);
cs.FlushFinalBlock();
cs.Close();
txtResults.Text = Convert.ToBase64String(ms.ToArray());
}
首先创建 DESCryptoServiceProvider 对象,要使用对称算法,必须提供要使用的密钥。每个 CryptoSymmetricAlgorithm 实现都提供一种 GenerateKey 方法。它们实际上使用的是公共语言运行时 (CLR) 类中内置的随机数生成器类。在首次调用DESCryptoServiceProvider 对象的Key属性时,因为该属性为Null,则自动调用GenerateKey 方法来生成随机Key。密钥的大小取决于用来加密的特定提供程序。例如,DES 密钥的大小为 64 位,而 TripleDES 密钥的大小为 192 位。每个 SymmetricAlgorithm 类上都有一个 KeySize 属性,它将返回用于生成密钥的密钥大小。
然后是需要生成初始化向量 (IV),如果IV属性为Null,也是自动调用GenerateIV方法,生成IV。只要使用的 IV 不同,即使密钥相同,同一个数据也会被加密成完全不同的值。当然,你可以自己指定特定的Key和IV,但要注意的不同的加密算法,可能采用不同的Key长度和IV长度。
ICryptoTransform 是一个接口。需要此接口才能在任何服务提供程序上调用 CreateEncryptor 方法,服务提供程序将返回定义该接口的实际 encryptor 对象。
Encoding.Unicode.GetBytes()方法负责将原始字符串转换成字节数组。大多数 .NET 加密算法处理的是字节数组而不是字符串。
现在可以执行实际的加密了。此进程需要创建一个数据流,用于将加密的字节写入到其中。要使用名为 ms 的 MemoryStream 对象、ICryptoTransform 对象(提供给 CryptoStream 类的构造函数)以及说明您希望在何种模式(读、写等)下创建该类的枚举常数。创建 CryptoStream 对象 cs 后,现在使用 CryptoStream 对象的 Write 方法将数据写入到内存数据流。这就是进行实际加密的方法,加密每个数据块时,数据将被写入 MemoryStream 对象。
创建 MemoryStream 后,该代码将在 CryptoStream 对象上执行 FlushFinalBlock 方法,以确保所有数据均被写入 MemoryStream 对象。并调用CryptoStream 对象的Close方法关闭 CryptoStream 对象。
最后,调用 Convert.ToBase64String() 方法,该方法接受字节数组输入并使用 Base64 编码方法将加密结果编码为可读内容,输出到TextBox显示。
(2)DES解密
上图Decrypt实例代码:
private void btnDecrypt_Click(object sender, System.EventArgs e)
{
SymmetricAlgorithm mCSP = new DESCryptoServiceProvider();
ICryptoTransform ct;
MemoryStream ms;
CryptoStream cs;
byte[] byt;
// Sets the key for the symmetric algorithm.
mCSP.Key = Convert.FromBase64String(txtKey.Text.Trim());
// Sets the initialization vector (IV) for the symmetric algorithm.
mCSP.IV = Convert.FromBase64String(txtIV.Text.Trim());
// Creates a symmetric Data Encryption Standard (DES) decryptor object.
ct = mCSP.CreateDecryptor(mCSP.Key, mCSP.IV);
byt = Convert.FromBase64String(txtOriginal.Text.Trim());
ms = new MemoryStream();
cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
cs.Write(byt, 0, byt.Length);
cs.FlushFinalBlock();
cs.Close();
txtResults.Text = Encoding.Unicode.GetString(ms.ToArray());
}
Decrypt过程代码与Encrypt过程很相似,只有细微的差别。首先,Decrypt过程不需要重新生成随机的Key和IV,必须使用与上述Encrypt过程中相同的Key和IV,否则无法解密。
另外,ICryptoTransform 是一个接口,这里是在DESCryptoServiceProvider服务提供程序上调用 CreateDecryptor方法,服务提供程序将返回定义该接口的实际decryptor对象。
.Net Framework也支持其他加密/解密算法,如TripleDES,RC2,Rijndael,并且只要简单替换上述代码的DESCryptoServiceProvider服务提供程序对象,就可以切换到对应的加密算法。正是基于这一点,我们可以非常方便地构建一套标准的加密/解密通用类库,请参考Microsoft的《如何创建加密库》,这里不重复了。
根据Microsoft的《如何创建加密库》编写的一个DEMO:
知识点:Base64编码
前面的加密/解密过程中,使用到.Net Framework提供的关于Base64编码的方法:
(1)Convert.ToBase64String() 方法,该方法接受字节数组输入并使用 Base64 编码方法将加密结果编码为可读内容
(2)Convert.FromBase64String()方法,该方法接受Base64 编码的字符串,输出字节数组。
Base64是MIME邮件中常用的编码方式之一。它的主要思想是将输入的字符串或数据编码成只含有{'A'-'Z', 'a'-'z', '0'-'9', '+', '/'}这64个可打印字符的串,故称为“Base64”。
Base64编码的方法是,将输入数据流每次取6 bit,不足6bit的补0,用此6 bit的值(0-63)作为索引去查表,输出相应字符。这样,每3个字节将编码为4个字符(3×8 → 4×6)(之后在6位的前面补两个0,形成8位一个字节的形式),不满4个字符的以'='填充。转换后的字符串理论上将要比原来的长1/3。
现在回到前面的DES算法中Key或者IV,Key长度为64位(8个字节),为了让Base64编码是4的倍数,就要补1个等号。
References:
1, MSDN, Duwamish 7.0
2, Rickie, Duwamish密码分析篇, Part 1
3, Rickie, Duwamish密码分析篇, Part 2
4, Paul D. Sheriff, Microsoft .NET 中的简化加密, http://www.microsoft.com/china/MSDN/library/archives/library/dnnetsec/html/cryptosimplified.asp
5, Microsoft, 如何创建加密库, http://www.microsoft.com/china/technet/security/guidance/secmod24.mspx