.NET密码术编程基础

 

 

      保证网络中信息安全的主要技术是数据的加密与解密。在密码学中,将源信息称为明文;对明文进行某种变换后生成的隐藏了其真实内容的信息称为密文;将明文变换为密文的过程称为加密;将密文经过逆变换恢复成明文的过程称为解密。其中加密和解密操作通常都是在一组密钥控制下进行的,密钥有加密密钥,解密密钥,加密后的信息为密文,解密后的信息为明文。通常,加密算法可以公开,而密钥只能由通信双方来管理。

      对于同一种加密算法,密钥的位数越长,破译的困难就越大,安全性也就越好。但是密钥越长,进行加密和解密过程所需要的计算时间也将越长。因此,密钥的长度往往根据应用的实际需要来确定。

根据加密和解密过程中所使用的密钥是否相同可以将加密算法分为对称加密算法和非对称加密算法。

对称加密算法,是指对信息的加密和解密都使用相同的密钥,因此也称为密钥密码算法。目前,典型的对称加密算法主要包括DES算法、Triple-DES算法、RC2、RC4、RC5算法和Rijndael算法等。       

非对称加密算法,对信息的加密与解密使用不同的密钥,用来加密的密钥是可以公开的,用来解密的密钥需要保密。因此又被称为公钥加密算法。目前,典型的非对称加密算法主要包括RSA算法和DSA算法等。

数字信封技术,对称加密算法运行效率高,但是密钥不适合在网络上传递;而非对称加密算法的密钥传递简单,但运行效率较低。数字信封技术则通过将对称加密算法和非对称加密算法结合起来,充分利用对称加密算法的高效性和非对称加密算法的灵活性,以保证信息在传输过程中的安全性。在数字信封技术中,加密过程主要包括两个步骤,即首先使用对称加密算法对明文进行加密,然后利用非对称加密算法对对称密钥进行加密,并一起将加密结果发往接收方。同样,其解密过程也可以分为两个主要步骤:首先利用非对称解密算法对对称密钥密文进行解密获取对称密钥,然后用所获取的对称密钥对密文进行解密恢复成明文。

数字签名技术,数据加密虽然可以防止信息在传输过程中遇到的若干问题,但是没办法确定发送人的身份,也不能解决信息被篡改和假冒。于是,数字签名技术结合散列算法和非对称加密技术来进行篡改检测和解决相关的身份验证问题。这就像在现实生活中用亲笔签名来保证文件或资料的真实性一样。

.NET中的密码编程

     .NET框架的System.Security.Cryptography 命名空间提供了对各种加密服务的编程访问,包括安全的数据加密与解密、确保数据的完整性,以及处理数字签名和证书等。

      System.Security.Cryptography中的核心加密类分为三层。

  • 第一层是一组抽象类,用于表示加密算法的类型,主要包括散列算法类HashAlgorithm、对称加密类SymmetricAlgorithm和非对称加密类AsymmetricAlgorithm。
  • 第二层表示特定加密算法类,虽然是由相应的加密基类派生而来,但它们也是抽象类,例如System.Security.Cryptography.DES。
  • 第三层是一组具体的加密实现方案类,每种实现类都由算法类派生而来,例如System.Security.Cryptography.DESCryptoServiceProvider等。

这样,每种特定算法类可以派生多个实现类,甚至允许第三方创建其他更好的实现方案类。

散列函数

      散列函数是现代密码系统的基础。这些函数将任意长度的二进制字符串映射为固定长度的二进制字符串(称为散列值)。加密散列函数有这样一个属性:在计算时不可能将两个不同的输入通过散列算法获取相同的值。散列函数通常用于数字签名和保持数据完整性等。在System.Security.Cryptography 命名空间中,所有的散列算法类都继承自HashAlgorithm抽象类。该类将根据指定的散列算法简单名称创建相应的散列算法实例,在此基础上将字符串数据传入Encrypt函数,便可以得到其散列值。该方法可以用于对口令的加密存储。由于ComputeHash方法的参数是字节数组,因此程序中引入了ASCIIEncoding. ASCII.GetBytes方法来将字符串转换为字节数组,同时引入Convert.ToBase64String方法将字节数组转换为字符串。

具体算法名称和实现类

 简 单 名 称

算法实现类

描    述

SHA

SHA1CryptoServiceProvider

计算输入数据的 SHA1散列值,160位

SHA1

SHA1CryptoServiceProvider

计算输入数据的 SHA1散列值,160位

MD5

MD5CryptoServiceProvider

计算输入数据的MD5散列值,128位

SHA256

SHA256Managed

计算输入数据的 256散列值,256位

SHA-256

SHA256Managed

计算输入数据的 256散列值,256位

SHA384

SHA384Managed

计算输入数据的 SHA384散列值,384位

SHA-384

SHA384Managed

计算输入数据的 SHA384散列值,384位

SHA512

SHA512Managed

计算输入数据的 SHA512散列值,512位

SHA-512

SHA512Managed

计算输入数据的 SHA512散列值,512位

散列函数加密

 

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

namespace 散列算法
{
//散列函数类
public class Hash
{
private HashAlgorithm myCryptoService = null;//HashAlgorithm:表示所有加密哈希算法实现均必须从中派生的基类。
public Hash()
{
myCryptoService = new SHA1Managed();//SHA1Managed:使用托管库计算输入数据的 SHA1 哈希值
}
public Hash(string serviceProviderName)//名称列表:http://msdn.microsoft.com/zh-cn/library/system.security.cryptography.cryptoconfig.aspx
{
//根据算法名称创建散列对象
myCryptoService = (HashAlgorithm)CryptoConfig.CreateFromName(serviceProviderName.ToUpper());//CryptoConfig:访问加密配置信息。
}

/// <summary>
/// 加密
/// </summary>
/// <param name="plainText"></param>
/// <returns></returns>
public virtual string Encrypt(string plainText)
{
byte[] cryptoByte = myCryptoService.ComputeHash(ASCIIEncoding.ASCII.GetBytes(plainText));
return Convert.ToBase64String(cryptoByte, 0, cryptoByte.Length);//将 8 位无符号整数数组的值转换为其用 Base64 数字编码的等效字符串表示形式。
}

}
class Program
{
static void Main(string[] args)
{
string m_ServiceProviderName = "";
string m_Txt = "";
bool flag = false;
Hash myHash = null;

Console.WriteLine("您现在使用的是散列算法");
Console.WriteLine("请输入散列算法名");//SHA等名称
m_ServiceProviderName = Console.ReadLine();
Console.WriteLine("请输入加密字符串");
m_Txt = Console.ReadLine();
flag = true;
if(flag)//加密
{
myHash = new Hash(m_ServiceProviderName);
if (myHash != null)
{
Console.WriteLine("加密数据:{0}", myHash.Encrypt(m_Txt));
}
else
{
Console.WriteLine("参数错误,加密失败!");
}
}
Console.ReadKey();
}
}
}

对称算法

System.Security.Cryptography命名空间支持DES、Triple-DES、RC2和Rijndael等对称加密算法。 

具体算法名称和实现类

 简 单 名 称

算法实现类

DES

DESCryptoServiceProvider

3DES

TripleDESCryptoServiceProvider

TripleDES

TripleDESCryptoServiceProvider

RC2

RC2CryptoServiceProvider

Rijndael

RijndaelManaged

     对称加密算法实现类使用一种称为密码块链接(Cipher Block Chaining,CBC)的链接模式,该模式需要密钥(Key)和初始化向量(IV)才能执行数据的加密运算。若要解密密文数据,必须将Key属性和IV属性设置为用于加密的相同值。

      当对称加密算法实现类被实例化时,将会自动生成强壮的密钥和初始化向量,并且设置默认填充模式(PKCS7)和默认密码模式(CBC)。在实际加密过程中,为了减少被破解的可能性,密钥必须有足够的随机性。实例化时生成的密钥都具有足够的随机性,使其难于记忆。因此,在实际加密过程中,往往采用比较易记的口令作为密码,并使用PasswordDriveBytes类生成强密钥,以提高抗破解能力。在解密时只要使用相同的方法生成密钥即可。另外,为了确保生成的是强密钥,还引入了salt随机值,使用它可以确保相同口令生成不同的密钥,这样便可以防止攻击者进行预运算。salt值和初始化向量IV不需要保密。

具体过程:

1.加密步骤

基于对称加密算法的加密步骤如下。

(1)创建对称加密算法实例,例如:

m_CryptoService = new RijndaelManaged( );

m_CryptoService.Mode = CipherMode.CBC;//设置链接模式

(2)设置初始化参数,包括密钥和初始化向量等。在实际使用过程中,初始化参数可以由加密算法实例自动产生,也可以由用户显式设置,但是初始向量和密钥的长度必须满足加密算法的需要。例如:

m_CryptoService.Key = GetLegalKey( );//设置密钥

m_CryptoService.IV = GetLegalIV( );//设置初始向量

(3)使用CreateEncryptor方法创建加密实例。例如:

ICryptoTransform cryptoTransform = m_CryptoService.CreateEncryptor( );

(4)创建加密流。由于对称加密往往用于加密大量数据信息,因此采用了流式加密方法,以便支持对内存流和文件流等数据的加密和解密。例如:

//创建内存流

MemoryStream ms = new MemoryStream( );

//利用内存流创建加密流

CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write);

(5)利用加密流进行数据加密,即直接通过流的写操作实现对数据的加密。例如:

//通过加密流加密数据

cs.Write(plainByte, 0, plainByte.Length);

cs.FlushFinalBlock( );

//返回密文

byte[] cryptoByte = ms.ToArray( );

return Convert.ToBase64String(cryptoByte, 0, cryptoByte.GetLength(0));

2.解密步骤

基于对称加密算法的解密步骤如下:

(1)创建对称加密算法实例。

m_CryptoService = new RijndaelManaged( );

m_CryptoService.Mode = CipherMode.CBC;//设置链接模式

(2)设置初始化参数,包括密钥和初始化向量等。

m_CryptoService.Key = GetLegalKey( );//设置密钥

m_CryptoService.IV = GetLegalIV( );//设置初始向量

(3)创建解密实例。例如:

ICryptoTransform cryptoTransform = m_CryptoService.CreateDecryptor( );

(4)创建解密流。

//创建内存流

MemoryStream ms = new MemoryStream(cryptoByte, 0, cryptoByte.Length);

//创建密文流

CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Read);

(5)利用解密流进行数据解密。

//解密并返回明文

StreamReader sr = new StreamReader(cs);

return sr.ReadToEnd( );

对称算法加密

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

namespace 对称加密算法
{
public class SymCryptography
{
private string m_Key = string.Empty;
private string m_Salt = string.Empty;
private string m_IV = string.Empty;
private SymmetricAlgorithm m_CryptoService;//SymmetricAlgorithm:表示所有对称算法的实现都必须从中继承的抽象基类。

#region 构造函数
public SymCryptography()
{
m_CryptoService = new RijndaelManaged();//访问 Rijndael 算法的托管版本

m_CryptoService.Mode = CipherMode.CBC;//指定用于加密的块密码模式。
}

public SymCryptography(string serviceProviderName)//根据算法名称创建加密对象
{
switch (serviceProviderName.ToLower( ))
{
case "rijndael":
serviceProviderName = "Rijndael";
break;
case "rc2":
serviceProviderName = "RC2";
break;
case "des":
serviceProviderName = "DES";
break;
case "tripledes":
serviceProviderName = "TripleDES";
break;
default:
serviceProviderName = "Rijndael";
break;
}
m_CryptoService= (SymmetricAlgorithm)CryptoConfig.CreateFromName(serviceProviderName);
m_CryptoService.Mode = CipherMode.CBC;
}
#endregion

private byte[] GetLegalIV() //获取合法初始向量
{
string m_iv = m_IV.Substring(0, m_IV.Length);
int n = m_CryptoService.BlockSize / 8;//获取或设置加密操作的块大小(以位为单位)。

if (m_iv.Length < n)
{
m_iv = m_iv.PadRight(n, '0');//返回一个新字符串,该字符串通过在此字符串中的字符右侧填充指定的 Unicode 字符来达到指定的总长度,从而使这些字符左对齐。
}
return ASCIIEncoding.ASCII.GetBytes(m_iv);
}

private byte[] GetLegalKey()//获取合法密钥
{
//获取合法的密码(长度)
if (m_CryptoService.LegalKeySizes.Length > 0)//获取对称算法支持的密钥大小(以位为单位)。
{
int keySize = m_Key.Length * 8;
int minSize = m_CryptoService.LegalKeySizes[0].MinSize;
int maxSize = m_CryptoService.LegalKeySizes[0].MaxSize;
int skipSize = m_CryptoService.LegalKeySizes[0].SkipSize;
if (keySize > maxSize)
{
m_Key = m_Key.Substring(0, maxSize / 8);
}
else if (keySize < maxSize)
{
int validSize = (keySize <= minSize) ? minSize : (keySize - keySize % skipSize) + skipSize;
if (keySize < validSize)
{
m_Key = m_Key.PadRight(validSize / 8, '*');
}
}
}
//使用 PBKDF1 算法的扩展从密码派生密钥
PasswordDeriveBytes key = new PasswordDeriveBytes(m_Key,
ASCIIEncoding.ASCII.GetBytes(m_Salt));
return key.GetBytes(m_Key.Length);//返回密钥
}


public string Encrypt(string plainText)//加密
{
byte[] plainByte = ASCIIEncoding.ASCII.GetBytes(plainText);

//初始化参数
m_CryptoService.Key = GetLegalKey();
m_CryptoService.IV = GetLegalIV();
//创建加密实例
ICryptoTransform cryptoTransform = m_CryptoService.CreateEncryptor();//定义基本的加密转换运算。
//创建内存流
MemoryStream ms = new MemoryStream();
//创建加密流
CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write);
//通过加密流加密数据
cs.Write(plainByte, 0, plainByte.Length);
cs.FlushFinalBlock();
//返回密文
byte[] cryptoByte = ms.ToArray();
return Convert.ToBase64String(cryptoByte, 0, cryptoByte.GetLength(0));
}

public string Decrypt(string cryptoText)//解密
{
byte[] cryptoByte = Convert.FromBase64String(cryptoText);
// 设置密钥和初始向量
m_CryptoService.Key = GetLegalKey();
m_CryptoService.IV = GetLegalIV();
// 创建解密对象
ICryptoTransform cryptoTransform = m_CryptoService.CreateDecryptor();
try
{
//创建内存流
MemoryStream ms = new MemoryStream(cryptoByte, 0, cryptoByte.Length);
//创建密文流
CryptoStream cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Read);
//解密并返回明文
StreamReader sr = new StreamReader(cs);
return sr.ReadToEnd();
}
catch
{
return null;
}
}

#region 属性
public string Key
{
get { return m_Key; }
set { m_Key = value; }
}
public string IV
{
get { return m_IV; }
set { m_IV = value; }
}
public string Salt
{
get { return m_Salt; }
set { m_Salt = value; }
}
#endregion
}


class Program
{
static void Main(string[] args)
{
string m_ServiceProviderName = "";
string m_Txt = "";
string m_Key = "";
string m_IV = "";
string m_Salt = "";
string m_CryptoTxt = "";
string m_DecrytoTxt = "";
bool rt = false;
SymCryptography m_SymCryptography = null;
//从命令行参数提取散列算法名和需要加密的字符串
if (args.Length < 5)
{
Console.WriteLine(@"Usage: SymCrypt 对称加密算法名[Rijndael|RC2|DES|TripleDES]
密钥 IV值 salt值 加密字符串
");
}
else
{
m_ServiceProviderName = args[0].ToString( );
m_Key = args[1].ToString( );
m_IV = args[2].ToString( );
m_Salt = args[3].ToString( );
m_Txt = args[4].ToString( );
rt = true;
}
if (rt)
{
m_SymCryptography = new SymCryptography(m_ServiceProviderName);
if (m_SymCryptography != null)
{
//初始化参数
m_SymCryptography.Key = m_Key;
m_SymCryptography.Salt = m_Salt;
m_SymCryptography.IV = m_IV;
//加密
m_CryptoTxt = m_SymCryptography.Encrypt(m_Txt);
//解密
m_DecrytoTxt = m_SymCryptography.Decrypt(m_CryptoTxt);
//显示结果
Console.WriteLine("源文:{0}", m_Txt);
Console.WriteLine("密文:{0}", m_CryptoTxt);
Console.WriteLine("明文:{0}", m_DecrytoTxt);
}
}
}
}
}

非对称算法

      与对称加密类似,System.Security.Cryptography命名空间支持RSA和DSAl两种不对称加密算法。这些算法类都是从抽象基类AsymmetricAlgorithm派生而来。 

具体算法名称和实现类

简 单 名 称

算法实现类

RSA

RSACryptoServiceProvider

DSA

DSACryptoServiceProvider

      在AsymmetricAlgorithm类的基础上,System.Security.Cryptography命名空间给出了抽象算法实现类RSA和DSA,并在此基础上给出了具体加密方案实现类。

      RSACryptoServiceProvider类是公钥算法的一个实现类,通常用于数据的加密;DSACryptoServiceProvider类是数字签名算法的一个实现类。当然,也可以使用 RSACryptoServiceProvider创建和验证数字签名。

      创建和管理密钥是加密过程的一个重要部分。不对称算法要求创建一个公钥和一个私钥。公钥可以对任何人公开,而私钥只有对用公钥加密的数据进行解密的一方知道。RSACryptoServiceProvider和DSACryptoServiceProvider类在创建新实例时将创建一个公钥/私钥对。并且可以用以下两种方法之一提取密钥信息。

(1)ToXMLString方法,它返回密钥信息的XML表示形式,其中参数为false时只返回公钥,而参数为true时则返回公钥/私钥对。

(2)ExportParameters方法,它返回RSAParameters结构以保存密钥信息,其中参数为false时只返回公钥,而参数为true时则返回公钥/私钥对。

其步骤如下:

1.创建非对称密钥并将其保存在密钥容器中

(1)创建CspParameters类的一个新实例,并将您要密钥容器使用的名称传递给CspParameters.KeyContainerName字段。

(2)为非对称加密算法实现类创建一个新实例,并将先前创建的 CspParameters对象传递给其构造函数。

2.从密钥容器中删除密钥

(1)创建CspParameters类的一个新实例,并将您要密钥容器使用的名称传递给CspParameters.KeyContainerName字段。

(2)为非对称加密算法实现类创建一个新实例,并将先前创建的CspParameters对象传递给其构造函数。

(3)将非对称加密算法实现类的PersistKeyInCSP属性设置为false。

(4)调用非对称加密算法实现类的Clear方法。该方法释放该类所有的资源并清除密钥容器。

非对称算法

 

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

namespace 非对称加密算法
{
public class ASymCryptography
{
private RSACryptoServiceProvider m_CryptoService;//使用加密服务提供程序 (CSP) 提供的 RSA 算法的实现执行不对称加密和解密。此类不能被继承。
static private string m_PriKey, m_PubKey;

public ASymCryptography( )
{
m_CryptoService = new RSACryptoServiceProvider( );
}

static public void GenKeys( )
{
CspParameters m_CspParameters;//包含传递给执行加密计算的加密服务提供程序 (CSP) 的参数。此类不能被继承。
m_CspParameters = new CspParameters( );
m_CspParameters.KeyContainerName = "MyKeyContainerName";//密钥容器名称
RSACryptoServiceProvider m_cp;
m_cp = new RSACryptoServiceProvider(m_CspParameters);
m_PriKey = m_cp.ToXmlString(true);//创建并返回包含当前 RSA 对象的密钥的 XML 字符串。true 表示同时包含 RSA 公钥和私钥;false 表示仅包含公钥。

m_PubKey = m_cp.ToXmlString(false);
m_cp.PersistKeyInCsp = false;//获取或设置一个值,该值指示密钥是否应该永久驻留在加密服务提供程序 (CSP) 中。

m_cp.Clear();//释放由 AsymmetricAlgorithm 类使用的所有资源。
}
public string Encrypt(string plainText)//加密
{
byte[] plainByte = ASCIIEncoding.ASCII.GetBytes(plainText);
//初始化参数
m_CryptoService.FromXmlString(m_PubKey);//通过 XML 字符串中的密钥信息初始化 RSA 对象

byte[] cryptoByte = m_CryptoService.Encrypt(plainByte, false);//使用 RSA 算法对数据进行加密。
return Convert.ToBase64String(cryptoByte);
}
public string Decrypt(string cryptoText)//解密
{
byte[] cryptoByte = Convert.FromBase64String(cryptoText);
//初始化参数
m_CryptoService.FromXmlString(m_PriKey);
byte[] plainByte = m_CryptoService.Decrypt(cryptoByte, false);
return ASCIIEncoding.ASCII.GetString(plainByte, 0, plainByte.Length);
}

public string PubKey
{
get { return m_PubKey; }
}
public string PriKey
{
get { return m_PriKey; }
}
}
class Program
{
static void Main(string[] args)
{
string m_Txt = "";
string m_CryptoTxt = "";
string m_DecrytoTxt = "";
ASymCryptography m_cp;
bool rt = false;
//从命令行参数提取需要加密的字符串
if (args.Length < 1)
{ Console.WriteLine("Usage: ASymCrypt 加密字符串"); }
else
{
m_Txt = args[0].ToString();
rt = true;
}
if (rt)
{
ASymCryptography.GenKeys();

m_cp = new ASymCryptography();
Console.WriteLine("PubKey is : {0}" + m_cp.PubKey);
Console.WriteLine("PriKey is : {0}" + m_cp.PriKey);
m_CryptoTxt = m_cp.Encrypt(m_Txt);
m_DecrytoTxt = m_cp.Decrypt(m_CryptoTxt);
//显示结果
Console.WriteLine("源文:{0}", m_Txt);
Console.WriteLine("密文:{0}", m_CryptoTxt);
Console.WriteLine("明文:{0}", m_DecrytoTxt);
Console.Read();
}
}
}
}
posted on 2012-03-11 18:41  WaitingSky  阅读(580)  评论(0编辑  收藏  举报