Microsoft NET 中的简化加密.docx

上传人:b****8 文档编号:30466229 上传时间:2023-08-15 格式:DOCX 页数:23 大小:26.02KB
下载 相关 举报
Microsoft NET 中的简化加密.docx_第1页
第1页 / 共23页
Microsoft NET 中的简化加密.docx_第2页
第2页 / 共23页
Microsoft NET 中的简化加密.docx_第3页
第3页 / 共23页
Microsoft NET 中的简化加密.docx_第4页
第4页 / 共23页
Microsoft NET 中的简化加密.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

Microsoft NET 中的简化加密.docx

《Microsoft NET 中的简化加密.docx》由会员分享,可在线阅读,更多相关《Microsoft NET 中的简化加密.docx(23页珍藏版)》请在冰豆网上搜索。

Microsoft NET 中的简化加密.docx

MicrosoftNET中的简化加密

Microsoft.NET中的简化加密

PaulD.Sheriff

PDSA.com

2003年10月

适用于:

Microsoft?

.NET

安全

Microsoft?

VisualBasic?

.NET

C#

摘要:

学习如何利用.NETFramework的加密功能创建类似本文所述的包装程序来保护您的数据。

下载与本文相关的CryptoSampleCSSample.msi和CryptoSampleVBSample.msi代码示例。

(请注意,在示例文件中,程序员的注释使用的是英文,本文中将其译为中文是为了便于读者理解。

目录

散列简介

创建示例散列项目

在散列中添加“盐”值

小结

您希望在计算机上保存一些机密信息吗?

如果是,本文就为您介绍如何进行加密!

加密技术就是将有意义的字符编码成无意义的字符,使不应该访问这些数据的人员无法读取它们。

加密技术已经存在很多年了,甚至远在计算机诞生之前就已经存在了。

随着计算机的出现,在计算机领域应用加密技术可以生成几乎牢不可破的代码。

Microsoft在Windows95中开发并分发了加密API。

使用Microsoft.NET,新创建的类可以将这些复杂的算法打包到非常易于使用的属性和方法中。

散列简介

如果您只是不想让别人窃取您的密码,那么可以为密码数据创建一个散列。

散列是一种单向算法,一旦数据被转换,将无法再获得其原始值。

大多数开发人员使用数据库存储密码。

但是,在数据库中查找用户数据的人员也能够看到这些密码。

不过,您可以使用散列算法对密码进行加密,然后再将其存储在数据库中。

用户输入密码后,您可以再次使用散列算法对其进行解密,然后将其与存储在数据库中的散列进行比较。

散列的缺点之一是,即使原始数据只发生一个小小的改动,数据的散列也会发生非常大的变化。

Pork和Porky这两个单词非常相似,但使用散列算法加密后的结果却相去甚远。

您可能根本看不出二者之间有什么相似之处。

.NET开发人员可以使用多种散列算法类。

最常用的是SHA1和MD5。

下面我们看一下如何为“Paul”这样的普通字符串生成散列,使任何人都无法识别它。

使用SHA1生成散列

我们创建一个新例程,然后使用它为字符串“Paul”生成散列。

在VisualStudio?

.NET中打开一个新的Windows应用程序,在窗体上放置一个命令按钮。

当该命令按钮上发生Click事件时,将调用名为HashText()的方法。

您可以将以下代码添加到该窗体中,看一下此散列算法的实际效果。

编写下列代码之前,需要导入命名空间System.Security.Cryptography。

PrivateSubHashText(ByValTextToHashAsString)

DimSHA1AsSHA1CryptoServiceProvider

DimbytValue()AsByte

DimbytHash()AsByte

'创建新的加密服务提供程序对象

SHA1=NewSHA1CryptoServiceProvider

'将原始字符串转换成字节数组

bytValue=_

System.Text.Encoding.UTF8.GetBytes(TextToHash)

'计算散列,并返回一个字节数组

bytHash=SHA1.ComputeHash(bytValue)

SHA1.Clear()

'返回散列值的Base64编码字符串

Debug.WriteLine(Convert.ToBase64String(bytHash))

EndSub

您可以传递不同的字符串值来调用该例程,查看散列值的变化。

例如,如果将字符串“Paul”传递给该例程,Debug(调试)窗口将显示以下文本:

w2h6uYgMJt/nq5ZqihcBteAXwv8=

现在,将此过程中的输入值更改为“Pauly”。

您将看到以下输出结果:

proywxJ0znMpGF5sbB18+7GSAsM=

如您所见,输入字符串的一个小小变化就会产生完全不同的字符组合。

这正是散列算法之所以有效的原因,它使我们很难找到输入字符串的规律,也很难根据加密后的字符弄清楚字符串原来的模样。

使用MD5也可以生成散列

了解一种散列类的使用方法后,基本上就了解了所有的散列类。

下面的方法用于MD5散列算法。

注意,除了CryptoServiceProvider类不同外,代码是完全相同的。

PrivateSubHashTextMD5(ByValTextToHashAsString)

Dimmd5AsMD5CryptoServiceProvider

DimbytValue()AsByte

DimbytHash()AsByte

'创建新的加密服务提供程序对象

md5=NewMD5CryptoServiceProvider

'将原始字符串转换成字节数组

bytValue=System.Text.Encoding._

UTF8.GetBytes(TextToHash)

'计算散列,并返回一个字节数组

bytHash=md5.ComputeHash(bytValue)

md5.Clear()

'返回散列值的Base64编码字符串

Debug.WriteLine(Convert.ToBase64String(bytHash))

EndSub

输入“Paul”之后,MD5散列算法的输出结果如下所示:

nVWBsHh1MKNctPioSyqyTQ==

同样,加密后的字符串看起来也与原始输入相去甚远。

这些散列算法对于创建没有任何意义的密码来说非常有用,也使黑客很难猜出这些密码。

之所以使用散列算法,是因为可以用这种算法对密码进行加密并将其存储在数据库中。

然后,当用户输入真实密码时,您先对密码进行解密,然后通过网络发送到数据库中,比较它与数据库中的密码是否匹配。

请记住,散列是单向操作。

使用散列算法对原始密码加密后将无法再恢复。

如何选择算法

本文介绍的两种散列算法都执行同一种操作。

不同之处只在于生成散列的密钥大小以及使用的算法。

使用的密钥越大,加密就越安全。

例如,MD5使用的加密密钥比SHA1使用的密钥大,因此MD5散列较难破解。

对于散列算法要考虑的另外一点是,从实践或理论的角度上看是否存在冲突的可能性。

冲突是我们所不希望的,因为两个不同的单词可能会生成相同的散列。

例如,SHA1从实践或理论上来讲没有发生冲突的可能性。

MD5从理论上讲有发生冲突的可能性,但从实践上讲没有发生冲突的可能性。

因此,选择哪种算法归根结底取决于您所需要的安全级别。

创建示例散列项目

本文包含两个示例散列项目,以更普通的方式说明如何使用不同的散列算法加密任意字符串。

这两个示例项目的名称分别为CryptoSampleVB.sln和CryptoSampleCS.sln。

前者是VisualBasic.NET解决方案,后者是C#解决方案。

两个解决方案都包括一个类似图1的窗体,该窗体允许您输入要通过散列算法为其加密的原始字符串,还提供一个用来选择散列算法的选项按钮和一个显示散列结果的文本框。

 

图1:

创建一个通用散列屏幕来尝试两种散列算法。

单击此屏幕上的Hash(散列)按钮时,将运行该按钮的Click事件过程。

此事件过程将调用一个名为HashString()的例程。

'VisualBasic.NET

PrivateSubbtnHash_Click(ByValsenderAsSystem.Object,_

ByValeAsSystem.EventArgs)HandlesbtnHash.Click

txtHashed.Text=HashString(txtOriginal.Text)

EndSub

//C#

privatevoidcmdHash_Click(objectsender,

System.EventArgse)

{

txtHashed.Text=HashString(txtOriginal.Text);

}

HashString()方法接受输入的值并调用SetHash()方法。

此方法将根据窗体上选项按钮的设置来决定使用哪个加密服务提供程序创建该方法的实例并返回该方法。

将为该窗体创建一个名为mHash的HashAlgorithm类型的成员变量。

HashAlgorithm类型是创建所有散列加密服务提供程序的基类。

'VisualBasic.NET

PrivatemhashAsHashAlgorithm

//C#

privateHashAlgorithmmhash;

SetHash()方法如下所示:

'VisualBasic.NET

PrivateFunctionSetHash()AsHashAlgorithm

IfoptSHA1.CheckedThen

ReturnNewSHA1CryptoServiceProvider

Else

IfoptMD5.CheckedThen

ReturnNewMD5CryptoServiceProvider

EndIf

EndIf

EndFunction

//C#

privateHashAlgorithmSetHash()

{

if(this.optSHA1.Checked)

returnnewSHA1CryptoServiceProvider();

else

returnnewMD5CryptoServiceProvider();

}

根据您在窗体上选择的选项按钮,此方法将创建并返回一个不同的HashAlgorithm类型。

HashString()方法在该窗体上执行实际的数据加密:

'VisualBasic.NET

PrivateFunctionHashString(ByValValueAsString)_

AsString

DimbytValue()AsByte

DimbytHash()AsByte

'创建新的加密服务提供程序对象

mhash=SetHash()

'将原始字符串转换成字节数组

bytValue=System.Text.Encoding.UTF8.GetBytes(Value)

'计算散列,并返回一个字节数组

bytHash=mhash.ComputeHash(bytValue)

mhash.Clear()

'返回散列值的Base64编码字符串

ReturnConvert.ToBase64String(bytHash)

EndFunction

 

//C#

privatestringHashString(stringValue)

{

mhash=SetHash();

//将原始字符串转换成字节数组

byte[]bytValue=System.Text.Encoding.UTF8.GetBytes(Value);

//计算散列,并返回一个字节数组

byte[]bytHash=mhash.ComputeHash(bytValue);

mhash.Clear();

//返回散列值的Base64编码字符串

returnConvert.ToBase64String(bytHash);

}

在HashString方法中,我们创建了两个字节数组。

第一个数组用来保存用户的原始字符串输入。

我们使用System.Text.Encoding.UTF8.GetBytes()方法将该字符串转换成字节数组。

将原始字符串转换成字节数组后,现在使用服务提供程序的ComputeHash()方法计算该字符串的散列值。

此方法接受字节数组作为输入,然后返回该字符串加密格式的字节数组。

注意:

完成之后清除散列变量是一个好的做法。

因此,您看到计算该字符串的散列后,我们调用了Clear方法。

现在我们已经获得了加密的字节数组,这正是要从该方法返回的数组。

因为我们要将原始值和加密值都作为字符串数据类型而不是字节数组进行处理,所以要通过使用Convert.ToBase64String方法返回加密的字节。

此方法负责将字节数组转换成Base64编码的字符串。

Base64编码的使用非常重要,因为有可能需要将此字符串推到Web页上或将其存储到数据库中。

如果不进行转换,加密字符串中的某些高阶ASCII字符将无法正确显示或存储。

在散列中添加一些“盐”值

到目前为止,散列算法暴露出来的问题之一是,如果两个用户碰巧使用相同的密码,那么散列值将完全相同。

如果黑客看到您存储密码的表格,会从中找到规律并明白您很可能使用了常见的词语,然后黑客会开始词典攻击以确定这些密码。

要确保任何两个用户密码的散列值都不相同,一种方法是在加密密码之前,在每个用户的密码中添加一个唯一的值。

这个唯一值称为“盐”值。

在进行此操作时,需要确保将使用的盐值存储为用户记录的一部分。

如果您使用表格存储用户ID和密码,我建议您使用不同的表格来存储盐值。

这样,即使数据库泄漏,盐值也可以为您提供一层额外的安全保护。

在用户密码中添加盐值的方法有多种。

最简单的方法是摘取用户的某些信息(例如姓、名、电子邮件地址或员工ID)并将其添加到用户密码中,然后再进行加密。

这种方法的缺点是,因为您需要存储盐值,所以如果黑客找到该值,将会对您所做的一切操作了如指掌。

当然,黑客需要花费额外的时间来破解盐值,但这对黑客来说简直是易如反掌。

另外一种方法是使用.NETFramework类RNGCryptoServiceProvider创建一个随机的数字字符串。

RNG表示随机数生成器。

该类可以创建一个任意长度的随机字节数组,长度由您指定。

您可以使用此随机字节数组作为散列算法的盐值。

要采用这种方法,必须安全地存储该盐值。

在图2所示的示例中,您需要在文本框中输入一个字符串,选择特定的散列类型,然后生成盐值以及包含该盐值和原始字符串的散列值。

 

图2:

在散列值中添加盐值以创建更安全的密码散列

(需要存储盐值以便再次创建相同的散列。

该示例与本文中的上一个示例基本相同,不同之处在于创建盐值的例程。

在此屏幕上的按钮的Click事件下,首先调用一个名为CreateSalt()的方法来生成一个唯一的盐值,然后将该值存储到txtSalt文本框中。

获得唯一的盐值后,再调用HashString()方法,将这两个值结合起来。

'VisualBasic.NET

PrivateSubbtnHash_Click(ByValsenderAsSystem.Object,_

ByValeAsSystem.EventArgs)HandlesbtnHash.Click

txtSalt.Text=CreateSalt()

txtHashed.Text=HashString(txtSalt.Text&_

txtOriginal.Text)

EndSub

//C#

privatevoidcmdHash_Click(objectsender,System.EventArgse)

{

txtSalt.Text=CreateSalt();

txtHashed.Text=HashString(txtOriginal.Text);

}

CreateSalt()方法的代码非常简单。

它首先创建一个长度为8个字节的字节数组,然后您创建一个新的RNGCryptoServiceProvider类实例。

使用该对象的GetBytes()方法,将生成的随机字符集填充到字节数组中。

然后将此字节数组转换成Base64编码字符串并从该函数返回。

'VisualBasic.NET

PrivateFunctionCreateSalt()AsString

DimbytSalt(8)AsByte

DimrngAsNewRNGCryptoServiceProvider

rng.GetBytes(bytSalt)

ReturnConvert.ToBase64String(bytSalt)

EndFunction

//C#

privatestringCreateSalt()

{

byte[]bytSalt=newbyte[8];

RNGCryptoServiceProviderrng;

rng=newRNGCryptoServiceProvider();

rng.GetBytes(bytSalt);

returnConvert.ToBase64String(bytSalt);

}

数据加密是一个双行道

如果需要在两个或多个人员或计算机之间来回发送信息,并希望对方能够读取数据,而其他人不可以读取,那么加密则是最好的方式!

加密算法使您可以将数据掩盖起来,除了特定人员能够对其解密外,其他人员不大可能通过数学方法读取该数据。

但如果您希望某个人能够读取该数据,您可以为其提供一个特定的“密钥”,使其能够解密并读取数据。

.NETFramework中有多种可用的加密/解密算法。

本文主要介绍对称算法,包括以下几种:

DES

RC2

Rijndael

TripleDES

对称算法(或密钥算法)使用一个密钥和一个初始化向量(IV)来保证数据的安全。

使用该数据的双方都必须知道这个密钥和初始化向量才能够加密和解密数据。

必须确保该密钥的安全,否则其他人将有可能解密该数据并读取该消息。

初始化向量只是一个随机生成的字符集,使用它可以确保任何两个文本都不会生成相同的加密数据。

使用.NET中不同的加密类的内置方法可以导出密钥,至于如何导出密钥,则不属于本文要讨论的内容。

其他类型的加密算法称为不对称算法。

不对称算法使用公钥/私钥对来创建加密数据。

不对称算法将在下文进行讨论。

如何在不同的情况下选择不同的加密方法

对称算法(或密钥算法)的速度非常快,非常适于加密大型的数据流。

这些算法可以加密数据,也可以解密数据。

它们都相当安全,但如果有足够的时间,也可能会被破密,因为有人可能会搜索每个已知的密钥值组合。

由于每种算法都使用固定的密钥长度或ASCII字符,因此计算机程序可以尝试每个可能的密钥组合并最终找到正确的那个组合。

这些类型的算法一般用于存储和检索数据库的连接字符串。

不对称算法(或公钥算法)没有对称算法快,但其代码较难破密。

这些算法取决于两个密钥,一个是私钥,另一个是公钥。

公钥用来加密消息,私钥是可以解密该消息的唯一密钥。

公钥和私钥通过数学方法链接在一起,因此要成功进行加密交换,必须获得这两个密钥。

由于可能会影响到计算机性能,因此不对称算法不太适用于加密大量数据。

不对称算法的常见用法是将对称密钥和初始化向量加密并传输给对方。

然后在双方之间来回发送的消息中使用对称算法加密和解密数据。

如果您不打算再恢复原始值,尤其不希望别人发现原始值,那么请使用散列值。

散列可以将任意长度的字符串加密为固定的字节集。

此操作是单向的,因此通常用于密码这样的少量数据。

当用户在安全的输入屏幕上输入用户密码后,程序将对此密码进行加密并将散列值存储到数据库中。

即使数据库泄漏,也没有人能够读取密码,因为密码已被加密。

当用户登录到该系统进行输入时,将使用相同的算法解密用户键入的密码,如果两个散列值相匹配,系统则可以确定用户输入的值与以前存储的值相同。

加密练习

示例应用程序中包括一个窗体,允许您使用DES和TripleDES加密服务提供程序进行加密练习。

该窗体名为frmEncrypt,如图3所示。

 

图3:

加密算法允许您加密并解密值。

在该屏幕上,首先需要单击GenKey(生成密钥)按钮,然后单击GenIV(生成IV)按钮。

然后在OriginalString(原始字符串)文本框中输入一些数据并单击Encrypt(加密)按钮。

单击Encrypt(加密)按钮后,加密后的文本将显示在EncryptedString(加密字符串)文本框中。

如果您希望在自己的应用程序中使用这个加密的字符串,则需要记下生成的密钥和IV,因为要解密连接字符串以便再次使用,您需要提供这两个值。

如果丢失了密钥和IV,将再也无法恢复连接字符串。

现在看一下其源代码,了解如何实现加密和解密例程。

首先看一下该类的成员变量,它用于保存相应加密服务提供程序的引用。

该成员变量的类型为SymmetricAlgorithm。

所有的对称算法类都是从这个基类继承而来的。

'VisualBasic.NET

PrivatemCSPAsSymmetricAlgorithm

//C#

privateSymmetricAlgorithmmCSP;

根据您在此窗体上选择的选项按钮,此mCSP变量将被指定给特定的对称算法类。

SetEnc()方法将负责创建适当的类型并将其返回到不同的方法。

'VisualBasic.NET

PrivateFunctionSetEnc()AsSymmetricAlgorithm

IfoptDES.CheckedThen

ReturnNewDESCryptoServiceProvider

Else

IfoptTripleDES.CheckedThen

ReturnNewTripleDESCryptoServiceProvider

EndIf

EndIf

EndFunction

//C#

privateSymmetricAlgorithmSetEnc()

{

if(optDES.Checked)

returnnewDESCryptoServiceProvider();

else

returnnewTripleDESCryptoServiceProvider();

}

如您所见,根据您在该窗体上选择的选项按钮,将创建DESCryptoServiceProvider对象或TripleDESCryptoServiceProvider对象。

实现加密和解密的密钥

要使用对称算法,必须提供要使用的密钥。

每个CryptoSymmetricAlgorithm实现都提供一种GenerateKey方法。

它们实际上使用的是公共语言运行时(CLR)类中内置的随机数生成器类。

我们来看一下GenKey(生成密钥)按钮的Click事件处理程序,看它如何生成要使用的随机密钥值。

'VisualBasic.NET

PrivateSubbtnKeyGen_Click(ByValsenderAs_

System.Object,ByValeAsSystem.EventArgs)_

HandlesbtnKeyGen.Click

mCSP=SetEnc()

mCSP.GenerateKey()

txtKey.Text

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1