社区
.NET技术其他语言
帖子详情
为什么我调用托管的RSA加密类,每次出来的加密结果不一样?
101monster
2003-09-09 09:52:40
另外解密怎么做,MSDN里的例子写的太简单了,看了没有什么大用
...全文
87
6
打赏
收藏
为什么我调用托管的RSA加密类,每次出来的加密结果不一样?
另外解密怎么做,MSDN里的例子写的太简单了,看了没有什么大用
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
6 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
101monster
2003-10-14
打赏
举报
回复
问题已经解决,是我太粗心了,谢谢各位!
101monster
2003-09-18
打赏
举报
回复
我用crypto的RSA加密都一样啊
101monster
2003-09-18
打赏
举报
回复
为什么会不同呢?
yuzaichun
2003-09-16
打赏
举报
回复
RSA就是这个样子的,针对同样的内容,生成的密文不会相同。
101monster
2003-09-10
打赏
举报
回复
MD5,SHA1那些都是唯一的,不过RSA不是,用RSACryptoServiceProvider 类
速马
2003-09-09
打赏
举报
回复
你用的哪个类?
我只试过MD5的,绝对是一样的...
vb6
调用
vc++写的
加密
DLL也支持其它程序
调用
vb6
调用
vc++写的
加密
DLL。也支持vc,vb.net,c#等程序
调用
,具体
调用
方法参照vb6例程。
c#
加密
和解密相关代码
数据的
加密
与解密 文件的
加密
与解密 第 章
加密
与解密技术 第19章
加密
与解密技术 829 19.1 数据的
加密
与解密 实例571 异或算法对数字进行
加密
与解密 光盘位置:光盘\MR\19\571 中级 趣味指数: 实 例说明 在实现本实例之前先来简要了解一下
加密
的概念,
加密
是指通过 某种特殊的方法,更改已有信息的内容,使得未授权的用户即使得到 了
加密
信息,如果没有正确解密的方法,也无法得到信息的内容。谈 到
加密
的话题,一些读者一定非常感兴趣,而且会联想到复杂的
加密
算法,本实例主要使用异或“^”运算符简单地实现了对数字
加密
的 功能。实例运行效果如图19.1 所示。 关 键技术 本实例实现时主要使用了“异或”运算符对数字进行“异或”运 算,以达到简单
加密
数字的目的,下面对其进行详细讲解。 “异或”运算符“^”用于比较两个二进制数的相应位。在执行按位“异或”运算时,如果两个二进制数的 相应位都为1 或两个二进制数的相应位都为0,则返回0;如果两个二进制数的相应位其中一个为1 一个为0, 则返回1。 现在来了解一下使用“异或”
加密
或解密的执行过程,数值23 转换为二进制为10111,
加密
数字的数值15 转换为二进制为1111。对比两个二进制的值,从右向左按位对比,如果两个二进制数的相应位都为1 或两个二 进制数的相应位都为0,则返回0;如果两个二进制数的相应位中一个为1 一个为0,则返回1,最后得到的结 果为二进制值11000,该值转换为十进制为24,所以得到的
加密
结果为24。而解密过程也很简单,只是将
加密
结果24与
加密
数字15 进行“异或”运算,将24 转换为二进制值11000,将15 转换为二进制值1111,进行“异 或”运算后,得到结果为23,这样又还原了
加密
的数据。 说明:本实例只是简单地使用了“异或”运算符计算两个整型数值以达到
加密
的目的,所以本实例只可以 对整型数值进行
加密
运算,并不适合其他数据的
加密
。 设 计过程 (1)打开Visual Studio 2008 开发环境,新建一个Windows窗体应用程序,并将其命名为Encrypt。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加两个GroupBox 容器控件,其中, 在第一个GroupBox 中放入3 个TextBox 控件和一个Button 按钮,分别用于输入数字、输入
加密
数字、显示加 密后的数字和计算
加密
信息;在第二个GroupBox 中放入一个TextBox 控件和一个Button 按钮,分别用于显示 解密后的信息和计算解密信息。 (3)程序主要代码如下: private void btn_Encrypt_Click(object sender, EventArgs e) { int P_int_Num, P_int_Key; //定义两个值
类
型变量 if (int.TryParse(txt_Num.Text, out P_int_Num) //判断输入是否是数值 && int.TryParse(txt_Key.Text, out P_int_Key)) { txt_Encrypt.Text = (P_int_Num ^ P_int_Key).ToString(); //
加密
数值 } else 图19.1 异或算法对数字进行
加密
与解密 C#开发实战1200 例(第II卷) 830 { MessageBox.Show("请输入数值", "出现错误!"); //提示输入信息不正确 } } private void btn_Revert_Click(object sender, EventArgs e) { int P_int_Key, P_int_Encrypt; //定义两个值
类
型变量 if (int.TryParse(txt_Encrypt.Text, out P_int_Key) //判断输入是否是数值 && int.TryParse(txt_Key.Text, out P_int_Encrypt)) { txt_Revert.Text = (P_int_Encrypt ^ P_int_Key).ToString(); //解密数值 } else { MessageBox.Show("请输入数值", "出现错误!"); //提示输入信息不正确 } } 秘 笈心法 心法领悟571:简述“异或”运算符。 本实例使用了“异或”运算符,但是在使用“异或”运算符之前,有必要了解“异或”运算符所做的“异 或”运算的机制,“异或”运算符“^”用于比较两个二进制数的相应位。在执行按位“异或”运算时,如果两 个二进制数的相应位都为1 或两个二进制数的相应位都为0,则返回0;如果两个二进制数的相应位中一个为1 一个为0,则返回1。 实例572 使用MD5算法
加密
数据 光盘位置:光盘\MR\19\572 中级 趣味指数: 实 例说明 MD5(Message-Digest Algorithm 5)是一种被广泛使用的“消息-摘要 算法”。“消息-摘要算法”实际上就是一个单项散列函数,数据块通过单 向散列函数得到一个固定长度的散列值,数据块的签名就是计算数据块的散 列值,MD5 算法的散列值为128 位。本实例演示如何使用MD5 算法对用户 输入的密码进行
加密
,实例运行效果如图19.2 所示。 关 键技术 本实例在实现时主要用到了MD5
类
的ComputeHash 方法,下面对其进行详细讲解。 MD5
类
表示MD5 哈希算法的所有实现均从中继承的抽象
类
,该
类
位于System.Security.Cryptography 命名 空间下,其ComputeHash 方法有3种重载形式,分别介绍如下。 计算指定字节数组的哈希值,语法格式如下: public byte[] ComputeHash(byte[] buffer) 参数说明 buffer:要计算其哈希代码的输入。 返回值:计算所得的哈希代码。 计算指定Stream 对象的哈希值,语法格式如下: public byte[] ComputeHash(Stream inputStream) 参数说明 inputStream:要计算其哈希代码的输入。 返回值:计算所得的哈希代码。 图19.2 使用MD5 算法
加密
数据 第19章
加密
与解密技术 831 计算指定字节数组的指定区域的哈希值,语法格式如下: public byte[] ComputeHash(byte[] buffer,int offset,int count) ComputeHash 方法中的参数及说明如表19.1 所示。 表19.1 ComputeHash方法中的参数及说明 参 数 说 明 buffer 要计算其哈希代码的输入 offset 字节数组中的偏移量,从该位置开始使用数据 count 数组中用作数据的字节数 返回值 计算所得的哈希代码 说明:本实例用到了ComputeHash 方法的第一种重载形式。 设 计过程 (1)打开Visual Studio 2008 开发环境,新建一个Windows窗体应用程序,并将其命名为MD5Arithmetic。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加两个TextBox 控件,分别用来输入 要
加密
的数据和显示
加密
后的字符串;添加一个Button 控件,用来使用MD5算法对输入的数据进行
加密
。 (3)程序主要代码如下: public string Encrypt(string strPwd) { MD5 md5 = new MD5CryptoServiceProvider(); //创建MD5 对象 byte[] data = System.Text.Encoding.Default.GetBytes(strPwd); //将字符编码为一个字节序列 byte[] md5data = md5.ComputeHash(data); //计算data字节数组的哈希值 md5.Clear(); //清空MD5 对象 string str = ""; //定义一个变量,用来记录
加密
后的密码 for (int i = 0; i < md5data.Length - 1; i++) //遍历字节数组 { str += md5data[i].ToString("x").PadLeft(2, '0'); //对遍历到的字节进行
加密
} return str; //返回得到的
加密
字符串 } private void button1_Click(object sender, EventArgs e) { string P_str_Code = textBox1.Text; //记录要
加密
的密码 textBox2.Text = Encrypt(P_str_Code); //显示
加密
后的字符串 } 秘 笈心法 心法领悟572:如何判断是否为数字? 开发程序时,经常需要判断输入的字符串是否为数字,如判断输入的电话号码、货币金额和邮编等。在程 序中判断是否为数字的方法有很多种,可以使用正则表达式、int.Parse 方法和double.Parse 方法等。下面的代码 通过double.Parse 方法判断textBox1 文本框中的输入是否为数字。 double.Parse(textBox1.Text); 实例573 使用ROT13算法
加密
解密数据 光盘位置:光盘\MR\19\573 中级 趣味指数: 实 例说明 文件
加密
可以避免造成重要信息的泄漏,复杂的
加密
算法可以将信息
加密
得非常繁杂,但是对于一般的应 用,没有必要作
类
似于PGP、
RSA
或DES 等复杂的
加密
算法。本实例介绍如何使用ROT13 算法
加密
和解密数 C#开发实战1200 例(第II卷) 832 据。实例运行效果如图19.3 所示。 图19.3 使用ROT13算法
加密
解密数据 关 键技术 本实例实现时,主要是用Convert
类
的ToChar 方法来获取单个字符的Unicode 编码,然后将字母的前13 个和后13 个对调,从而实现
加密
的功能。下面对Convert
类
的ToChar 方法进行详细讲解。 ToChar 方法返回指定的Unicode字符值,并且不执行任何实际的转换,其语法格式如下: public static char ToChar (char value) 参数说明 value:一个Unicode 字符。 设 计过程 (1)打开Visual Studio 2008 开发环境,新建一个Windows窗体应用程序,并将其命名为ROT13Encrypt。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加两个TextBox 控件,分别用来显示 原始数据和解密后的数据;添加两个Button 控件,分别用来实现利用ROT13算法
加密
和解密数据的功能。 (3)程序主要代码如下: public string ROT13Encode(string InputText) { char tem_Character; //存储临时字符 int UnicodeChar; //存储临时字符的字节值 string EncodedText = ""; //存储
加密
或解密后的字符串 for (int i = 0; i = 97 && UnicodeChar = 110 && UnicodeChar = 65 && UnicodeChar = 78 && UnicodeChar <= 90) //对字符进行解密 { UnicodeChar = UnicodeChar - 13; } EncodedText = EncodedText + (char)UnicodeChar; //得到
加密
或解密字符串 } return EncodedText; //返回
加密
或解密后的字符串 } 秘 笈心法 心法领悟573:如何在字符串中查找指定字符? 在字符串中查找指定字符时,可以先将字符串显示在richTextBox 控件中,然后利用richTextBox
类
的Find 方法在该控件中查找指定字符。在字符串中查找指定字符的代码如下: 第19章
加密
与解密技术 833 M_int_index = richTextBox1.Find(textBox1.Text.Trim(), M_int_index, RichTextBoxFinds.MatchCase); if (M_int_index == -1) { MessageBox.Show("没有要查找的字符串", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); M_int_index = 0; } else M_int_index = M_int_index + textBox1.Text.Trim().Length; richTextBox1.Focus(); 实例574 使用恺撒密码算法
加密
密码 光盘位置:光盘\MR\19\574 中级 趣味指数: 实 例说明 恺撒密码据传是古罗马恺撒大帝用来保护重要军情的
加密
系统,它 是一种置换密码,通过将字母顺序推后起到
加密
作用。例如,将字母顺 序推后3 位,字母A 将被推作为字母D,字母B 将被推作字母E。本实 例使用C#实现了恺撒
加密
的算法,实例运行效果如图19.4 所示。 关 键技术 本实例实现时主要用到了string
类
的ToCharArray 方法和Convert
类
的ToChar 方法,下面分别对它们进行 详细介绍。 (1)string
类
的ToCharArray 方法 string
类
的ToCharArray 方法用来将字符串中的字符复制到Unicode 字符数组,该方法有两种重载形式,本 实例中用到的它的重载形式如下: public char[] ToCharArray() 参数说明 返回值:元素为此字符串的各字符的Unicode 字符数组。如果此字符串是空字符串,则返回的数组为空且 长度为零。 (2)Convert
类
的ToChar 方法 Convert
类
的ToChar 方法用来将指定的值转换为Unicode 字符,该方法为可重载方法,本实例中用到的它 的重载形式如下: public static char ToChar(int value) 参数说明 value:32 位有符号整数。 返回值:等效于value 的值的Unicode 字符。 设 计过程 (1)打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为CaesarArithmetic。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加两个TextBox 控件,分别用来输入 要
加密
的数据和显示
加密
后的字符串;添加一个Button 控件,用来使用恺撒密码算法对输入的数据进行
加密
。 (3)程序主要代码如下: public int AscII(string str) //获取字符的ASCII 码 { byte[] array = new byte[1]; //创建字节数组 array = System.Text.Encoding.ASCII.GetBytes(str); //为字节数组赋值 int asciicode = (short)(array[0]); //获取字节数组的第一项 return asciicode; //返回字节数组的第一项 } 图19.4 使用恺撒密码算法
加密
密码 C#开发实战1200 例(第II卷) 834 public string Caesar(string str) //凯撒
加密
算法的实现 { char[] c = str.ToCharArray(); //创建字符数组 string strCaesar = ""; //定义一个变量,用来存储
加密
后的字符串 for (int i = 0; i < str.Length; i++) //遍历字符串中的每一个字符串 { string ins = c[i].ToString(); //记录遍历到的字符 string outs = ""; //定义一个变量,用来记录
加密
后的字符串 bool isChar = "0123456789abcdefghijklmnopqrstuvwxyz".Contains(ins.ToLower()); //判断指定的字符串中是否包含遍历到的字符 bool isToUpperChar = isChar && (ins.ToUpper() == ins); //判断遍历到的字符是否是大写 ins = ins.ToLower(); //将遍历到的字符转换为小写 if (isChar) //判断指定的字符串中是否包含遍历到的字符 { int offset = (AscII(ins) + 5 - AscII("a")) % (AscII("z") - AscII("a") + 1); //获取字符的ASCII 码 outs = Convert.ToChar(offset + AscII("a")).ToString(); //转换为字符并记录 if (isToUpperChar) //判断是否大写 { outs = outs.ToUpper(); //全部转换为大写 } } else { outs = ins; //记录遍历的字符 } strCaesar += outs; //添加到
加密
字符串中 } return strCaesar; //返回
加密
后的字符串 } 秘 笈心法 心法领悟574:如何将新字符串添加到已有字符串中? 将新字符串添加到已有字符串中时,可以先声明一个StringBuilder
类
对象,以指定已有字符串的长度可变, 然后利用该对象的Append方法在字符串中添加指定字符串。将新字符串添加到已有字符串的代码如下: StringBuilder strbuilder = new StringBuilder(textBox1.Text.Trim()); strbuilder.Append(textBox2.Text.Trim()); textBox3.Text = strbuilder.ToString(); 实例575 对数据报进行
加密
保障通信安全 光盘位置:光盘\MR\19\575 高级 趣味指数: 实 例说明 网络传输数据时,有时候传输信息容易被不法分子截获而 用作其他用途。这样,如果传输的数据中包含有重要秘密,将 会造成非常严重的后果。为了防止这种情况的发生,可以对网 络中传输的数据进行
加密
,用户接收到数据后再进行解密查看, 这样可以更好地保障网络通信安全。运行本实例,首先设置端 口号,然后在窗体左下方的文本框中输入聊天信息,单击“发 送”按钮,向局域网中发送聊天信息,同时在右侧的“数据传 输信息”栏中显示数据报的发送、接收及丢失情况。实例运行 效果如图19.5 所示。 关 键技术 本实例获取数据报信息时主要用到IPGlobalProperties和UdpStatistics
类
,而在对数据报
加密
时用到DESCrypto 图19.5 对数据报进行
加密
保障通信安全 第19章
加密
与解密技术 835 ServiceProvider 和CryptoStream
类
,其中DESCryptoServiceProvider 继承于DES
类
。下面对本实例中用到的关 键技术进行详细讲解。 (1)IPGlobalProperties
类
IPGlobalProperties
类
提供有关本地计算机的网络连接的信息,本实例中用到它的GetIPGlobalProperties 和 GetUdpIPv4Statistics 方法,下面分别进行介绍。 GetIPGlobalProperties 为静态方法,主要用来获取一个对象,该对象提供有关本地计算机的网络连接和通信 统计数据的信息,其语法格式如下: public static IPGlobalProperties GetIPGlobalProperties() 参数说明 返回值:IPGlobalProperties 对象,该对象包含有关本地计算机的信息。 GetUdpIPv4Statistics 方法主要用来提供本地计算机的用户数据报协议/Internet 协议版本4 (UDP/IPv4)统 计数据,其语法格式如下: public abstract UdpStatistics GetUdpIPv4Statistics() 参数说明 返回值:UdpStatistics 对象,提供本地计算机的UDP/IPv4通信统计数据。 例如,本实例中创建IPGlobalProperties 对象,及
调用
其GetUdpIPv4Statistics 方法创建UdpStatistics 对象的 代码如下: IPGlobalProperties NetInfo = IPGlobalProperties.GetIPGlobalProperties(); UdpStatistics myUdpStat = null; myUdpStat = NetInfo.GetUdpIPv4Statistics(); (2)UdpStatistics
类
UdpStatistics
类
提供用户数据报协议(UDP)统计数据,本实例中主要用到其DatagramsSent 属性、 DatagramsReceived属性和IncomingDatagramsDiscarded 属性,其中,DatagramsSent 属性用来获取已发送的用户 数据报协议(UDP)数据报的数量,DatagramsReceived 属性用来获取已接收的用户数据报协议(UDP)数据报 的数量,IncomingDatagramsDiscarded 属性用来获取已收到但因端口错误而丢弃的用户数据报协议(UDP)数据 报的数量。 例如,本实例中初始化已发送、已接收和丢失数据报的实现代码如下: SendNum1 = Int32.Parse(myUdpStat.DatagramsSent.ToString()); //记录发送的数据报 ReceiveNum1 = Int32.Parse(myUdpStat.DatagramsReceived.ToString()); //记录接收的数据报 DisNum1 = Int32.Parse(myUdpStat.IncomingDatagramsDiscarded.ToString()); //记录丢失的数据报 说明:IPGlobalProperties
类
和UdpStatistics
类
位于System.Net.NetworkInformation 命名空间下。 (3)DES
类
DES
类
表示所有DES 实现都必须从中派生的数据
加密
标准(DES)算法的基
类
,其CreateEncryptor 方法和 CreateDecryptor 方法分别用来
加密
和解密。 CreateEncryptor 方法使用指定的Key属性和初始化向量(IV)创建对称
加密
器对象,其语法格式如下: public abstract ICryptoTransform CreateEncryptor(byte[] rgbKey,byte[] rgbIV) 参数说明 rgbKey:用于对称算法的密钥。 rgbIV:用于对称算法的初始化向量。 返回值:对称
加密
器对象。 CreateDecryptor 方法使用指定的Key属性和初始化向量(IV)创建对称解密器对象,其语法格式如下: public abstract ICryptoTransform CreateDecryptor(byte[] rgbKey,byte[] rgbIV) 参数说明 rgbKey:用于对称算法的密钥。 rgbIV:用于对称算法的初始化向量。 返回值:对称解密器对象。 C#开发实战1200 例(第II卷) 836 (4)CryptoStream
类
CryptoStream
类
定义将数据流链接到
加密
转换的流,其构造函数的语法格式如下: public CryptoStream(Stream stream,ICryptoTransform transform,CryptoStreamMode mode) 参数说明 stream:对其执行
加密
转换的流。 transform:要对流执行的
加密
转换。 mode:CryptoStreamMode 枚举值之一,CryptoStreamMode 枚举值及说明如表19.2 所示。 表19.2 CryptoStreamMode枚举值及说明 枚 举 值 说 明 Read 对
加密
流的读访问 Write 对
加密
流的写访问 另外,在向
加密
或解密流中写入数据时用到CryptoStream
类
的Write 方法,该方法将一个字节序列写入当 前CryptoStream,并将流中的当前位置提升写入的字节数,其语法格式如下: public override void Write(byte[] buffer,int offset,int count) 参数说明 buffer:字节数组,此方法将count 个字节从buffer 复制到当前流。 offset:buffer 中的字节偏移量,从此偏移量开始将字节复制到当前流。 count:要写入当前流的字节数。 说明:DES
类
和CryptoStream
类
位于System.Security.Cryptography 命名空间下。 设 计过程 (1)打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为EncryptDataReport。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加两个RichTextBox 控件,分别用来 输入聊天信息和显示聊天信息;添加4 个TextBox 控件,分别用来输入端口号和显示已发送数据报、已接收数 据报、丢失数据报;添加4 个Button 控件,分别用来执行设置端口号、发送聊天信息、清空聊天信息和关闭应 用程序操作。 (3)程序主要代码如下。 Frm_Main 窗体的后台代码中,首先创建程序所需要的.NET 对象及公共变量,代码如下: #region 定义全局对象及变量 private IPEndPoint Server; //服务器端 private IPEndPoint Client; //客户端 private Socket mySocket; //套接字 private EndPoint ClientIP; //IP地址 byte[] buffer, data; //接收缓存 bool blFlag = true; //标识是否第一次发送信息 bool ISPort = false; //判断端口打开 int SendNum1, ReceiveNum1, DisNum1; //记录窗体加载时的已发送\已接收\丢失的数据报 int SendNum2, ReceiveNum2, DisNum2; //记录当前已发送\已接收\丢失的数据报 int SendNum3, ReceiveNum3, DisNum3; //缓存已发送\已接收\丢失的数据报 int port; //端口号 #endregion Frm_Main 窗体加载时,初始化已发送、已接收和丢失的数据报,并使用全局变量记录,实现代码如下: //初始化已发送、已接收和丢失的数据报 private void Form1_Load(object sender, EventArgs e) { if (blFlag == true) { IPGlobalProperties NetInfo = IPGlobalProperties.GetIPGlobalProperties(); //创建一个IPGlobalProperties 对象 UdpStatistics myUdpStat = null; //声明UdpStatistics 对象 myUdpStat = NetInfo.GetUdpIPv4Statistics(); //创建UdpStatistics 对象 第19章
加密
与解密技术 837 SendNum1 = Int32.Parse(myUdpStat.DatagramsSent.ToString()); //记录发送的数据报 ReceiveNum1 = Int32.Parse(myUdpStat.DatagramsReceived.ToString()); //记录接收的数据报 DisNum1 = Int32.Parse(myUdpStat.IncomingDatagramsDiscarded.ToString()); //记录丢失的数据报 } } 单击“设置”按钮,使用指定的端口号连接服务器端与客户端,并开始接收消息。“设置”按钮的Click 事件的代码如下: private void button4_Click(object sender, EventArgs e) //设置端口号 { try { port = Convert.ToInt32(textBox4.Text); //记录端口号 CheckForIllegalCrossThreadCalls = false; //指定线程中可以
调用
窗体的控件对象 buffer = new byte[1024]; data = new byte[1024]; Server = new IPEndPoint(IPAddress.Any, port); //创建服务器端 Client = new IPEndPoint(IPAddress.Broadcast, port); //创建客户端 ClientIP = (EndPoint)Server; //获取服务器端IP 地址 //创建Socket 对象 mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //设置Socket 网络操作 mySocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1); mySocket.Bind(Server); //绑定服务器端 //开始接收消息 mySocket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ClientIP, new AsyncCallback(StartLister), null); ISPort = true; //打开指定端口号 } catch { } } 单击“发送”按钮,首先判断是否有打开的端口,如果没有,弹出提示信息,否则根据发送和接收的消息 计算已发送、已接收和丢失的数据报,并显示在相应的文本框中,然后使用DES对要发送的消息进行
加密
发送。 “发送”按钮的Click事件的代码如下: //发送信息 private void button2_Click(object sender, EventArgs e) { if (ISPort == true) //判断是否有打开的端口号 { IPGlobalProperties NetInfo = IPGlobalProperties.GetIPGlobalProperties(); UdpStatistics myUdpStat = null; myUdpStat = NetInfo.GetUdpIPv4Statistics(); try { if (blFlag == false) //非第一次发送 { SendNum2 = Int32.Parse(myUdpStat.DatagramsSent.ToString()); ReceiveNum2 = Int32.Parse(myUdpStat.DatagramsReceived.ToString()); DisNum2 = Int32.Parse(myUdpStat.IncomingDatagramsDiscarded.ToString()); textBox1.Text = Convert.ToString(SendNum2 - SendNum3); textBox2.Text = Convert.ToString(ReceiveNum2 - ReceiveNum3); textBox3.Text = Convert.ToString(DisNum2 - DisNum3); } SendNum2 = Int32.Parse(myUdpStat.DatagramsSent.ToString()); ReceiveNum2 = Int32.Parse(myUdpStat.DatagramsReceived.ToString()); DisNum2 = Int32.Parse(myUdpStat.IncomingDatagramsDiscarded.ToString()); SendNum3 = SendNum2; //记录本次的发送数据报 ReceiveNum3 = ReceiveNum2; //记录本次的接收数据报 DisNum3 = DisNum2; //记录本次的丢失数据报 if (blFlag == true) //第一次发送 { textBox1.Text = Convert.ToString(SendNum2 - SendNum1); textBox2.Text = Convert.ToString(ReceiveNum2 - ReceiveNum1); textBox3.Text = Convert.ToString(DisNum2 - DisNum1); blFlag = false; C#开发实战1200 例(第II卷) 838 } } catch (Exception ex) { MessageBox.Show(ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Information); } string str = EncryptDES(rtbSend.Text, "mrsoftxk"); //
加密
要发送的信息 data = Encoding.Unicode.GetBytes(str); mySocket.SendTo(data, data.Length, SocketFlags.None, Client); //发送消息 rtbSend.Text = ""; } else { MessageBox.Show("请首先打开端口!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); button4.Focus(); } } 上面的代码中用到了EncryptDES 方法,该方法为自定义的、返回值
类
型为string 的方法,主要用来使用 DES
加密
数据报,它有两个string
类
型的参数,分别用来表示待
加密
的字符串和
加密
密钥,返回值为
加密
后的 字符串。EncryptDES 方法的实现代码如下: #region DES
加密
字符串 /// ///DES
加密
字符串 /// ///待
加密
的字符串 ///
加密
密钥,要求为8 位 ///
加密
成功返回
加密
后的字符串,失败返回源字符串 public string EncryptDES(string str, string key) { try { byte[] rgbKey = Encoding.UTF8.GetBytes(key.Substring(0, 8)); //将
加密
密钥转换为字节数组 byte[] rgbIV = Keys; //记录原始密钥数组 byte[] inputByteArray = Encoding.UTF8.GetBytes(str); //将
加密
字符串转换为字节数组 DESCryptoServiceProvider myDES = new DESCryptoServiceProvider(); //创建
加密
对象 MemoryStream MStream = new MemoryStream(); //创建内存数据流 //创建
加密
流对象 CryptoStream CStream = new CryptoStream(MStream, myDES.CreateEncryptor(rgbKey, rgbIV), CryptoStreamMode.Write); CStream.Write(inputByteArray, 0, inputByteArray.Length); //向
加密
流中写入数据 CStream.FlushFinalBlock(); //释放
加密
流对象 return Convert.ToBase64String(MStream.ToArray()); //返回内存流中的数据 } catch { return str; } } #endregion 秘 笈心法 心法领悟575:如何根据标点符号分行? 根据标点符号分行时,首先要使用string
类
的Split 方法分割字符串,然后再通过“\n”回车换行符将分割 的字符串换行显示。根据标点符号分行的代码如下: string oldstr = textBox1.Text.Trim(); string[] newstr = oldstr.Split('。'); for (int i = 0; i < newstr.Length; i++) { if (richTextBox1.Text == "") richTextBox1.Text = newstr[i].ToString(); else richTextBox1.Text += "\n" + newstr[i].ToString(); } 第19章
加密
与解密技术 839 实例576 使用one-time pad算法
加密
数据 光盘位置:光盘\MR\19\576 高级 趣味指数: 实 例说明 在密码学里,有一种理想的
加密
方案,叫做一次一密乱码本,即 one-time pad 算法,该算法是最安全的
加密
算法,双方一旦安全交换 了密钥,之后交换信息的过程就可以保证绝对安全。本实例使用C# 实现了one-time pad
加密
算法,实例运行效果如图19.6 所示。 注意:程序中使用one-time pad 算法时,一定要保证密钥和密文 的长度是一样的。 关 键技术 本实例在实现one-time pad
加密
算法时,主要用到了Encoding
类
的GetBytes 方法和GetString 方法,下面 分别对它们进行详细介绍。 (1)Encoding
类
的GetBytes方法 Encoding
类
表示字符编码,其GetBytes方法主要用来将一组字符编码为一个字节序列,该方法为可重载方 法,本实例中用到的它的重载形式如下: public virtual byte[] GetBytes(string s) 参数说明 s:字符串。 返回值:一个字节数组,包含对指定的字符集进行编码的结果。 说明:Encoding
类
位于System.Text 命名空间下。 (2)Encoding
类
的GetString方法 Encoding
类
的GetString方法主要用来将一个字节序列解码为一个字符串,该方法为可重载方法,本实例中 用到的它的重载形式如下: public virtual string GetString(byte[] bytes) 参数说明 bytes:包含要解码的字节序列的字节数组。 返回值:包含指定字节序列解码结果的字符串。 设 计过程 (1) 打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为OneTimePadArithmetic。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加4 个TextBox 控件,分别用来输入 要
加密
的数据和密钥,以及显示
加密
后的数据和解密后的数据;添加两个Button控件,分别用来实现使用one-time pad 算法
加密
数据和解密数据的功能。 (3)程序主要代码如下。 在Frm_Main 窗体中输入要
加密
的数据和密钥后,单击“
加密
”按钮,使用one-time pad 算法对输入的数据 进行
加密
,实现代码如下: private void button1_Click(object sender, EventArgs e) { textBox2.Text = ""; //清空文本框 Encoding encoding = Encoding.Default; //获取字符编码 byte[] btData = encoding.GetBytes(textBox1.Text); //将要
加密
的数据转换为字节数组 byte[] btKey = encoding.GetBytes(textBox4.Text); //将密钥转换为字节数组 图19.6 使用one-time pad 算法
加密
数据 C#开发实战1200 例(第II卷) 840 if (btData.Length == btKey.Length) //判断长度是否相等 { byte[] btEncrypt = Encrypt(btData, btKey); //
加密
数据 for (int i = 0; i < btEncrypt.Length; i++) //遍历
加密
后的字节数组 { textBox2.Text += btEncrypt[i]; //显示在文本框中 } } } 上面的代码中用到了Encrypt 方法,该方法为自定义的、返回值
类
型为byte[]的方法,主要用来对指定的数 据使用one-time pad 算法进行
加密
。Encrypt方法的实现代码如下: public static byte[] Encrypt(byte[] btData, byte[] btKey) { if (btKey.Length != btData.Length) //判断长度是否相等 { MessageBox.Show("请确保要
加密
数据的长度与密钥的长度一致!"); } byte[] btResult = new byte[btData.Length]; //声明一个字节数组,用来存储
加密
数据 for (int i = 0; i < btResult.Length; ++i) //遍历字节数组 { btResult[i] = (byte)(btKey[i] ^ btData[i]); //为字节数组赋值 } return btResult; //返回得到的
加密
数据 } 单击“解密”按钮,
调用
Encrypt 方法对
加密
过的数据进行逆向
加密
,并返回一个byte[]数组,然后使用 Encoding
类
的GetString方法从该数组中获取解密字符串。“解密”按钮的Click事件的代码如下: private void button2_Click(object sender, EventArgs e) { Encoding encoding = Encoding.Default; //获取字符编码 byte[] btData = encoding.GetBytes(textBox1.Text); //将要
加密
的数据转换为字节数组 byte[] btKey = encoding.GetBytes(textBox4.Text); //将密钥转换为字节数组 if (btData.Length == btKey.Length) //判断长度是否相等 { byte[] btDecrypt = Encrypt(Encrypt(btData, btKey), btKey); //解密数据 textBox3.Text = encoding.GetString(btDecrypt); //将解密后的字节数组转换为字符串并显示 } } 秘 笈心法 心法领悟576:如何在字符串中添加多个空格? 开发程序时,有时会根据需要在字符串中添加一些空格,这时可以使用string
类
的Insert方法,该方法可以 在字符串中的指定位置插入一个新的字符串(包括空格)。在字符串中添加空格的代码如下: textBox3.Text = textBox1.Text.Insert(Convert.ToInt32(textBox2.Text.Trim()), " "); 实例577 使用伪随机数
加密
技术
加密
用户登录密码 光盘位置:光盘\MR\19\577 高级 趣味指数: 实 例说明 为了保障用户登录密码的安全,本实例使用伪随机数技术对用 户的登录密码进行
加密
,运行本实例,当用户在“登录密码”文本 框中输入登录密码时,程序会自动将使用过伪随机数
加密
技术
加密
过的登录密码显示在下面的“
加密
密码”文本框中,单击“登录” 按钮,程序对“
加密
密码”文本框中的
加密
数据进行解密,然后再 与用户输入的登录密码相比较,如果相同,则登录成功;否则,登 录失败。实例运行效果如图19.7 所示。 图19.7 使用伪随机数
加密
技术
加密
用户登录密码 第19章
加密
与解密技术 841 关 键技术 本实例对用户登录密码
加密
时用到伪随机数
加密
技术,伪随机数
加密
技术实质上就是通过伪随机数序列使 登录密码字符串的字节值发生变化而产生密文,由于相同的初值能得到相同的随机数序列,因此,可以采用同 样的伪随机数序列来对密文进行解密。产生伪随机数时主要用到Random
类
,该
类
表示伪随机数生成器,它是 一种能够产生满足某些随机性统计要求的数字序列的设备,其Next方法用来返回随机数,语法格式如下: public virtual int Next(int maxValue) 参数说明 maxValue:要生成的随机数的上界(随机数不能取该上界值),maxValue 必须大于等于零。 返回值:大于等于零且小于maxValue 的32 位带符号整数,即返回值的范围通常包括零但不包括 maxValue;不过,如果maxValue 等于零,则返回maxValue。 设 计过程 (1)打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为PRanDataEncrypt。 (2)更改默认窗体Form1 的Name属性为Frm_Main,在该窗体中添加3 个TextBox 控件,分别用来输入 登录用户、登录密码和显示
加密
密码;添加两个Button 控件,分别用来执行用户登录和清空文本框操作。 (3)程序主要代码如下。 Frm_Main 窗体的后台代码中,首先定义
加密
用户密码所用的伪随机数,代码如下: //定义
加密
用户密码所用的伪随机数 private string randStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; 当在“登录密码”文本框中输入登录密码时,实时将使用伪随机数
加密
过的登录密码显示在“
加密
密码” 文本框中,实现代码如下: private void textBox2_TextChanged(object sender, EventArgs e) { textBox3.Text = EncryptPwd(textBox2.Text); //显示
加密
后的用户登录密码 } 上面的代码中用到EncryptPwd 方法,该方法为自定义的、返回值
类
型为string 的方法,主要用来使用伪随 机数技术
加密
用户登录密码,它有一个参数,用来表示用户登录密码。EncryptPwd 方法的实现代码如下: /// /// 使用伪随机数
加密
用户登录密码 /// /// 用户登录密码 ///
加密
后的用户登录密码 private string EncryptPwd(string str) { byte[] btData = Encoding.Default.GetBytes(str); //将登录密码转换为字节数组 int j, k, m; int len = randStr.Length; //记录伪随机数长度 StringBuilder sb = new StringBuilder(); //创建StringBuilder对象 Random rand = new Random(); //创建Random 对象 for (int i = 0; i < btData.Length; i++) { j = (byte)rand.Next(6); //产生伪随机数 btData[i] = (byte)((int)btData[i] ^ j); //使用伪随机数对密码字节数组进行移位 k = (int)btData[i] % len; m = (int)btData[i] / len; m = m * 8 + j; sb.Append(randStr.Substring(k, 1) + randStr.Substring(m, 1)); //组合
加密
字符串 } return sb.ToString(); //返回生成的
加密
字符串 } 单击“登录”按钮,判断“
加密
密码”文本框是否为空。如果不为空,
调用
DecryptPwd 方法解密“
加密
密码”文本框中的字符串;然后使用解密后的字符串与“登录密码”文本框中的字符串相比较,如果相同,则 用户登录成功;否则,弹出提示信息。“登录”按钮的Click事件代码如下: C#开发实战1200 例(第II卷) 842 private void button1_Click(object sender, EventArgs e) { if (textBox3.Text != "") { if (DecryptPwd(textBox3.Text) == textBox2.Text) //对
加密
过的登录密码进行解密 MessageBox.Show("用户登录成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); else MessageBox.Show("用户密码错误!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); } } 上面的代码中用到了DecryptPwd 方法,该方法为自定义的、返回值
类
型为string 的方法,主要用来解密用 户登录密码,它有一个参数,主要用来表示经过
加密
的用户登录密码。DecryptPwd 方法的实现代码如下: /// /// 解密用户登录密码 /// /// 经过
加密
的用户登录密码 /// 解密后的用户登录密码 private string DecryptPwd(string str) { try { int j, k, m, n = 0; int len = randStr.Length; //获取伪随机数长度 byte[] btData = new byte[str.Length / 2]; //定义一个字节数组,并指定长度 for (int i = 0; i < str.Length; i += 2) //对登录密码进行解密 { k = randStr.IndexOf(str[i]); m = randStr.IndexOf(str[i + 1]); j = m / 8; m = m - j * 8; btData[n] = (byte)(j * len + k); btData[n] = (byte)((int)btData[n] ^ m); n++; } return Encoding.Default.GetString(btData); //返回解密后的登录密码 } catch { return ""; } } 秘 笈心法 心法领悟577:如何将字符串颠倒输出? 颠倒输出字符串时,可以先将要输出的字符串保存到一个char
类
型的数组中,然后使用Array
类
的Reverse 方法。将字符串颠倒输出的代码如下: string str1 = textBox1.Text.Trim(); char[] charstr = str1.ToCharArray(); Array.Reverse(charstr); string str2 = new string(charstr); textBox2.Text = str2; 实例578 以XML格式导入导出密钥 光盘位置:光盘\MR\19\578 高级 趣味指数: 实 例说明 本实例主要实现以XML 格式导入导出密钥,从而实现对数据进行
加密
和解密的功能。运行本实例,首先 在窗体中显示生成的公钥和私钥,然后输入明文数据,单击“
加密
”按钮,对输入的明文数据进行
加密
;单击 “解密”按钮,对
加密
后的数据进行解密。实例运行效果如图19.8 所示。 第19章
加密
与解密技术 843 图19.8 以XML 格式导入导出密钥 关 键技术 本实例实现时主要用到了
RSA
CryptoServiceProvider
类
的ToXmlString方法、Encrypt 方法和Decrypt 方法, 下面对本实例中用到的关键技术进行详细讲解。 (1)
RSA
CryptoServiceProvider
类
的ToXmlString方法
RSA
CryptoServiceProvider
类
用来使用
加密
服务提供程序(CSP)提供的
RSA
算法的实现执行不对称
加密
和 解密,其ToXmlString 方法主要用来创建并返回包含当前
RSA
对象的密钥的XML 字符串,该方法的语法格式 如下: public override string ToXmlString(bool includePrivateParameters) 参数说明 includePrivateParameters:true 表示同时包含
RSA
公钥和私钥,false 表示仅包含公钥。 返回值:包含当前
RSA
对象的密钥的XML字符串。 说明:
RSA
CryptoServiceProvider
类
位于System.Security.Cryptography 命名空间下。 (2)
RSA
CryptoServiceProvider
类
的Encrypt方法 该方法主要使用
RSA
算法对数据进行
加密
,其语法格式如下: public byte[] Encrypt(byte[] rgb,bool fOAEP) 参数说明 rgb:要
加密
的数据。 fOAEP:如果为true,则使用OAEP 填充(仅在运行Microsoft Windows XP 或更高版本的计算机上可用) 执行直接的
RSA
加密
;如果为false,则使用PKCS#1 1.5 版填充。 返回值:字节数组,表示已
加密
的数据。 (3)
RSA
CryptoServiceProvider
类
的Decrypt方法 该方法主要使用
RSA
算法对数据进行解密,其语法格式如下: public byte[] Decrypt(byte[] rgb,bool fOAEP) 参数说明 rgb:要解密的数据。 fOAEP:如果为true,则使用OAEP 填充(仅在运行Microsoft Windows XP 或更高版本的计算机上可用) 执行直接的
RSA
解密;如果为false,则使用PKCS#1 1.5 版填充。 返回值:字节数组,表示已解密的数据,它是
加密
前的原始纯文本。 设 计过程 (1)打开Visual Studio 2008 开发环境,新建一个Windows窗体应用程序,并将其命名为KeyToXML。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加5 个TextBox 控件,分别用来显示 C#开发实战1200 例(第II卷) 844 公钥、显示私钥、输入明文数据、显示
加密
后的数据和显示解密后的数据;添加两个Button 控件,分别用来执 行数据
加密
和解密操作。 (3)程序主要代码如下。 在Frm_Main 窗体的后台代码中,首先创建
RSA
CryptoServiceProvider 对象,并且定义一个字节数组,用来 存储临时数据,代码如下:
RSA
CryptoServiceProvider
RSA
Crypto = new
RSA
CryptoServiceProvider(); //创建
RSA
算法
加密
解密对象 byte[] M_bt_Data; //定义一个字节数组,用来存储临时数据 Frm_Main 窗体加载时,在文本框中显示程序自动生成的公钥和私钥数据,代码如下: private void Frm_Main_Load(object sender, EventArgs e) { this.textBox1.Text =
RSA
Crypto.ToXmlString(true); //显示生成的公钥 this.textBox2.Text =
RSA
Crypto.ToXmlString(false); //显示生成的私钥 } 当用户输入明文数据之后,单击“
加密
”按钮,
调用
RSA
CryptoServiceProvider
类
的Encrypt方法对数据进 行
加密
,并且使用Encoding
类
的UTF8 编码方式的GetString 方法得到
加密
后的数据,显示在文本框中。“
加密
” 按钮的Click事件代码如下: private void button1_Click(object sender, EventArgs e) { if (textBox3.Text != "") //判断是否输入了要
加密
的数据 { byte[] P_bt_Encrypt = Encoding.UTF8.GetBytes(textBox3.Text); //将要
加密
的数据转换为字节数组 M_bt_Data =
RSA
Crypto.Encrypt(P_bt_Encrypt, false); //
加密
数据 textBox4.Text = Encoding.UTF8.GetString(M_bt_Data); //显示
加密
数据 } } 单击“解密”按钮,
调用
RSA
CryptoServiceProvider
类
的Decrypt方法对
加密
过的数据进行解密,并且使用 Encoding
类
的UTF8 编码方式的GetString 方法得到解密后的数据,显示在文本框中。“解密”按钮的Click 事 件代码如下: private void button2_Click(object sender, EventArgs e) { if (textBox4.Text != "") //判断是否有
加密
过的数据 { byte[] P_bt_Decrypt =
RSA
Crypto.Decrypt(M_bt_Data, false); //对数据进行解密 textBox5.Text = Encoding.UTF8.GetString(P_bt_Decrypt); //显示解密数据 } } 秘 笈心法 心法领悟578:如何判断字符串是否为日期格式? 判断字符串是否为日期格式时,可以使用正则表达式。验证日期格式的正则表达式主要有以下3 种: \b(?\d{2,4})/(?\d{1,2})/(?\d{1,2})\b 或 \b(?\d{2,4})-(?\d{1,2})-(?\d{1,2})\b 或 \b(?\d{2,4})年(?\d{1,2})月(?\d{1,2})日\b 实例579 以参数格式导入导出密钥 光盘位置:光盘\MR\19\579 高级 趣味指数: 实 例说明 本实例主要实现以参数格式导入导出密钥,从而实现对数据进行
加密
和解密的功能。运行本实例,在窗体 第19章
加密
与解密技术 845 中输入明文数据,单击“
加密
”按钮,对输入的明文数据进行
加密
;单击“解 密”按钮,对
加密
后的数据进行解密。实例运行效果如图19.9 所示。 关 键技术 本实例实现时主要用到了
RSA
CryptoServiceProvider
类
的ExportParameters 方法、ImportParameters 方法、Encrypt 方法和Decrypt 方法,下面对本实例 中用到的关键技术进行详细讲解。 (1)
RSA
CryptoServiceProvider
类
的ExportParameters 方法 该方法主要用来导出
RSA
Parameters标准参数,其语法格式如下: public override
RSA
Parameters ExportParameters(bool includePrivateParameters) 参数说明 includePrivateParameters:如果要包括私有参数,则为true;否则为false。 返回值:
RSA
算法的标准参数。 (2)
RSA
CryptoServiceProvider
类
的ImportParameters 方法 该方法主要用来导入指定的
RSA
Parameters标准参数,其语法格式如下: public override void ImportParameters(
RSA
Parameters parameters) 参数说明 parameters:
RSA
算法的标准参数。 说明:关于
RSA
CryptoServiceProvider
类
的Encrypt 方法和Decrypt 方法的详细讲解,请参见实例578 中的 关键技术。 设 计过程 (1)打开Visual Studio 2008 开发环境,新建一个Windows窗体应用程序,并将其命名为KeyToParameter。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加3 个TextBox 控件,分别用来输入 明文数据、显示
加密
后的数据和解密后的数据;添加两个Button 控件,分别用来执行数据
加密
和解密操作。 (3)程序主要代码如下。 Frm_Main 窗体的后台代码中,首先创建
RSA
CryptoServiceProvider 对象和
RSA
Parameters 标准参数对象, 并且定义一个字节数组,用来存储临时数据,代码如下:
RSA
CryptoServiceProvider
RSA
Crypto; //声明
RSA
算法
加密
解密对象
RSA
Parameters
RSA
Parame; //声明
RSA
Parameters 参数对象 byte[] M_bt_Data; //定义一个字节数组,用来存储临时数据 在Frm_Main 窗体的构造函数中,
调用
RSA
CryptoServiceProvider
类
的ImportParameters 方法导入
RSA
Parameters标准参数,实现代码如下: public Frm_Main() { InitializeComponent();
RSA
Crypto = new
RSA
CryptoServiceProvider(); //初始化
RSA
算法
加密
解密对象
RSA
Parame =
RSA
Crypto.ExportParameters(true); //初始化
RSA
Parameters 参数
RSA
Crypto.Clear(); //清空
RSA
CryptoServiceProvider 对象
RSA
Crypto = new
RSA
CryptoServiceProvider(); //初始化
RSA
算法
加密
解密对象
RSA
Crypto.ImportParameters(
RSA
Parame); //导入密钥 } 当用户输入明文数据之后,单击“
加密
”按钮,
调用
RSA
CryptoServiceProvider
类
的Encrypt方法对数据进 行
加密
,并且使用Encoding
类
的UTF8 编码方式的GetString 方法得到
加密
后的数据,显示在文本框中。“
加密
” 按钮的Click事件代码如下: private void button1_Click(object sender, EventArgs e) { if (textBox1.Text != "") //判断是否输入了要
加密
的数据 { 图19.9 以参数格式导入导出密钥 C#开发实战1200 例(第II卷) 846 byte[] P_bt_Encrypt = Encoding.UTF8.GetBytes(textBox1.Text); //将要
加密
的数据转换为字节数组 M_bt_Data =
RSA
Crypto.Encrypt(P_bt_Encrypt, false); //
加密
数据 textBox2.Text = Encoding.UTF8.GetString(M_bt_Data); //显示
加密
数据 } } 单击“解密”按钮,
调用
RSA
CryptoServiceProvider
类
的Decrypt方法对
加密
过的数据进行解密,并且使用 Encoding
类
的UTF8 编码方式的GetString 方法得到解密后的数据,显示在文本框中。“解密”按钮的Click 事 件代码如下: private void button2_Click(object sender, EventArgs e) { if (textBox2.Text != "") //判断是否有
加密
过的数据 { byte[] P_bt_Decrypt =
RSA
Crypto.Decrypt(M_bt_Data, false); //对数据进行解密 textBox3.Text = Encoding.UTF8.GetString(P_bt_Decrypt); //显示解密数据 } } 秘 笈心法 心法领悟579:巧截字符串中的数字。 截取字符串中的数字时,可以先使用CharEnumerator 对象的MoveNext 方法循环访问字符串中的每个字符, 并将字符用System.Text.Encoding
类
中ASCII 编码方式的GetBytes 方法进行编码,然后判断经过编码之后的字符 的ASCII码值是否介于48和57之间,如果是,则将其显示在textBox文本框中。截取字符串中数字的代码如下: CharEnumerator CEnumerator = textBox1.Text.GetEnumerator(); while (CEnumerator.MoveNext()) { byte[] array = new byte[1]; array = System.Text.Encoding.ASCII.GetBytes(CEnumerator.Current.ToString()); int asciicode = (short)(array[0]); if (asciicode >= 48 && asciicode <= 57) { textBox2.Text += CEnumerator.Current.ToString(); } } 19.2 文件的
加密
与解密 实例580 文本文件
加密
与解密 光盘位置:光盘\MR\19\580 高级 趣味指数: 实 例说明 在本实例的窗体中,首先选择要
加密
或解密的文本文件,然后单击“加 密”或“解密”按钮对文本文件进行
加密
或解密。实例运行效果如图19.10 所示。 关 键技术 本实例实现时主要用到了System.Security.Cryptography命名空间下的 RijndaelManaged
类
的CreateDecryptor 方法、CreateEncryptor 方法和CryptoStream
类
的Write 方法,下面对本实 例中用到的关键技术进行详细讲解。 (1)RijndaelManaged
类
该
类
是访问System.Security.Cryptography.Rijndael 对称
加密
算法的
托管
版本,其语法格式如下: public sealed class RijndaelManaged : Rijndael 图19.10 文本文件
加密
与解密 第19章
加密
与解密技术 847 注意:此算法支持128、192或256 位的密钥长度。 (2)CreateDecryptor 方法 该方法位于RijndaelManaged
类
中,使用指定的Key和初始化向量(IV)创建对称的Rijndael 解密器对象, 其语法格式如下: public override IcryptoTransform CreateDecryptor (byte[] rgbKey,byte[] rgbIV) 参数说明 rgbKey:用于对称算法的机密密钥。 rgbIV:用于对称算法的IV。 返回值:对称的Rijndael 解密器对象。 (3)CreateEncryptor 方法 该方法位于RijndaelManaged
类
中,使用指定的Key和初始化向量(IV)创建对称的Rijndael
加密
器对象, 其语法格式如下: public override ICryptoTransform CreateEncryptor (byte[] rgbKey,byte[] rgbIV) 参数说明 rgbKey:用于对称算法的机密密钥。 rgbIV:用于对称算法的IV。 返回值:对称的Rijndael
加密
器对象。 说明:关于CryptoStream
类
的Write 方法的详细讲解,请参见实例575中的关键技术。 设 计过程 (1) 打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为EncryptTextFileOne。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加一个TextBox 控件,用来显示文本 文件路径;添加一个OpenFileDialog 控件,用来选择要
加密
或解密的文本文件;添加3 个Button 控件,用来执 行选择文本文件、
加密
和解密操作。 (3)程序主要代码如下。 单击“
加密
”按钮实现对选择的文本文件进行
加密
,“
加密
”按钮的Click事件的代码如下: private void button2_Click(object sender, EventArgs e) { if (textBox1.Text == "") //若未选择要
加密
的文本文件 { MessageBox.Show("请选择要
加密
的文件"); } //如果没有选择则弹出提示 else { try{ string strPath = textBox1.Text; //
加密
文件的路径 int intLent=strPath.LastIndexOf("\\")+1; //设置截取的起始位置 int intLong = strPath.Length; //设置截取的长度 string strName = strPath.Substring(intLent,intLong-intLent); //要
加密
的文件名称 int intTxt = strName.LastIndexOf("."); //设置截取的起始位置 int intTextLeng = strName.Length; //设置截取的长度 string strTxt = strName.Substring(intTxt,intTextLeng-intTxt); //取出文件的扩展名 strName = strName.Substring(0,intTxt); //
加密
后的文件名及路径 string strOutName = strPath.Substring(0, strPath.LastIndexOf("\\") + 1) + strName + "Out" + strTxt; //
加密
文件密钥 byte[] key = { 24, 55, 102, 24, 98, 26, 67, 29, 84, 19, 37, 118, 104, 85, 121, 27, 93, 86, 24, 55, 102, 24, 98, 26, 67, 29, 9, 2, 49, 69, 73, 92 }; byte[] IV ={ 22, 56, 82, 77, 84, 31, 74, 24, 55, 102, 24, 98, 26, 67, 29, 99 }; RijndaelManaged myRijndael = new RijndaelManaged(); FileStream fsOut = File.Open(strOutName, FileMode.Create, FileAccess.Write); FileStream fsIn = File.Open(strPath, FileMode.Open, FileAccess.Read); //写入
加密
文本文件 CryptoStream csDecrypt = new CryptoStream(fsOut, myRijndael.CreateEncryptor(key, IV), CryptoStreamMode.Write); BinaryReader br = new BinaryReader(fsIn); //创建阅读器来读
加密
文本 csDecrypt.Write(br.ReadBytes((int)fsIn.Length), 0, (int)fsIn.Length); //将数据写入
加密
文本 C#开发实战1200 例(第II卷) 848 csDecrypt.FlushFinalBlock(); csDecrypt.Close(); //关闭CryptoStream 对象 fsIn.Close(); //关闭FileStream 对象 fsOut.Close(); //关闭FileStream 对象 if (MessageBox.Show("
加密
成功!
加密
后的文件名及路径为:\n" + strOutName + ",是否删除源文件", "信息提示", MessageBoxButtons. YesNo) == DialogResult.Yes) { File.Delete(strPath); //删除指定文件 textBox1.Text = ""; //清空文本框 }else { textBox1.Text = ""; } } catch (Exception ee) //如果出现异常 { MessageBox.Show(ee.Message); //输出异常信息 } } } 单击“解密”按钮实现对
加密
的文本文件进行解密,“解密”按钮的Click事件代码如下: private void button3_Click(object sender, EventArgs e) { if (textBox1.Text == "") //若未选择要解密的文件 { MessageBox.Show("请选择要解密的文件路径"); //如果没有选择则弹出提示 } else { string strPath = textBox1.Text; //
加密
文件的路径 int intLent = strPath.LastIndexOf("\\") + 1; //设置截取字符串的起始位置 int intLong = strPath.Length; //设置截取长度 string strName = strPath.Substring(intLent, intLong - intLent); //要
加密
的文件名称 int intTxt = strName.LastIndexOf("."); //截取字符串的起始位置 int intTextLeng = strName.Length; //截取长度 strName = strName.Substring(0, intTxt); //获取扩展名 if (strName.LastIndexOf("Out") != -1) { strName = strName.Substring(0, strName.LastIndexOf("Out")); } else { strName = strName + "In"; } //
加密
后的文件名及路径 string strInName = strPath.Substring(0, strPath.LastIndexOf("\\") + 1) + strName + ".txt"; //解密文件密钥 byte[] key = { 24, 55, 102, 24, 98, 26, 67, 29, 84, 19, 37, 118, 104, 85, 121, 27, 93, 86, 24, 55, 102, 24, 98, 26, 67, 29, 9, 2, 49, 69, 73, 92 }; byte[] IV ={ 22, 56, 82, 77, 84, 31, 74, 24, 55, 102, 24, 98, 26, 67, 29, 99 }; RijndaelManaged myRijndael = new RijndaelManaged(); //创建RijndaelManaged 对象 //创建FileStream 对象 FileStream fsOut = File.Open(strPath, FileMode.Open, FileAccess.Read); CryptoStream csDecrypt = new CryptoStream(fsOut, myRijndael.CreateDecryptor(key, IV), CryptoStreamMode.Read); StreamReader sr = new StreamReader(csDecrypt); //把文件读出来 StreamWriter sw = new StreamWriter(strInName); //解密后写入一个新文件 sw.Write(sr.ReadToEnd()); sw.Flush(); sw.Close(); sr.Close(); fsOut.Close(); if (MessageBox.Show("解密成功!解密后的文件名及路径为:"+strInName+",是否删除源文件", "信息提示", MessageBoxButtons.YesNo) == DialogResult.Yes) { File.Delete(strPath); //删除指定文件 textBox1.Text = ""; //清空文本框 } else { 第19章
加密
与解密技术 849 textBox1.Text = ""; } } } 秘 笈心法 心法领悟580:如何存储变长字符串? 在程序中存储变长字符串时,需要使用StringBuilder对象。相对于string 对象来说,StringBuilder 对象是可 变的,不用生成中间对象,因此,在连接的字符串较多或字符串长度较长时,通常都使用StringBuilder 对象。 实例581 利用图片
加密
文件 光盘位置:光盘\MR\19\581 高级 趣味指数: 实 例说明 本实例在
加密
时,使用指定的图片生成
加密
密钥,然后对文本文件进 行
加密
;在解密时,使用
加密
时的图片生成解密密钥,然后对
加密
的文本 文件进行解密。运行本实例,首先打开一张图片,用来生成
加密
或解密的 密钥,然后选择要
加密
或解密的文本文件,最后单击“
加密
”或“解密” 按钮,实现对文本文件的
加密
或解密。实例运行效果如图19.11 所示。 关 键技术 本实例实现时主要用到了RC2CryptoServiceProvider
类
、BinaryWriter
类
的Write 方法、File
类
的Delete 方法和Copy 方法,下面对本实例中用到 的关键技术进行详细讲解。 (1)RC2CryptoServiceProvider
类
该
类
定义访问RC2算法的
加密
服务提供程序(CSP)实现的包装对象,无法继承此
类
。 (2)BinaryWriter
类
该
类
以二进制形式将基元
类
型写入流,并支持用特定的编码写入字符串,其构造器的语法格式如下: public BinaryWriter (Stream output) 参数说明 output:表示输出流。 (3)BinaryWriter
类
的Write 方法 该方法将一个无符号字节写入当前流,并将流的位置提升一个字节,其语法格式如下: public virtual void Write (byte value) 参数说明 value:表示要写入的无符号字节。 (4)File
类
的Delete 方法 File
类
提供用于创建、复制、删除、移动和打开文件的静态方法,并协助创建FileStream 对象,该
类
是个 静态
类
,其Delete方法用于删除指定的文件,如果指定的文件不存在,则引发异常。该方法的语法格式如下: public static void Delete (string path) 参数说明 path:表示要删除的文件的名称。 (5)File
类
的Copy 方法 该方法将现有文件复制到新文件,不允许改写同名的文件,其语法格式如下: public static void Copy (string sourceFileName,string destFileName) 图19.11 利用图片
加密
文件 C#开发实战1200 例(第II卷) 850 参数说明 sourceFileName:要复制的文件。 destFileName:目标文件的名称,不能是一个目录或现有文件。 设 计过程 (1) 打开Visual Studio 2008开发环境,新建一个Windows窗体应用程序,并将其命名为EncryptTextFileTwo。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加一个TextBox 控件,用来显示
加密
或解密文件的路径;添加一个OpenFileDialog 控件,用来选择要
加密
或解密的文件和打开密钥的图片;添加4 个Button 控件,分别用来执行
加密
、解密、打开文件和打开图片操作;添加一个PictureBox 控件,用于显示密 钥图片。 (3)程序主要代码如下。 单击“
加密
”按钮,实现利用图片对文本文件进行
加密
的功能,“
加密
”按钮的Click 事件的代码如下: private void button3_Click(object sender, EventArgs e) { try { if (pictureBox1.ImageLocation==null) //判断是否选择了图片 { MessageBox.Show("请选择一幅图片用于
加密
"); return; } //如果没有选择则弹出提示 if (textBox1.Text == "") //若未选择需要
加密
的文件 { MessageBox.Show("请选择
加密
文件路径"); return; } //如果没有选择则弹出提示 //图片流 FileStream fsPic = new FileStream(pictureBox1.ImageLocation, FileMode.Open, FileAccess.Read); //
加密
文件流 FileStream fsText = new FileStream(textBox1.Text, FileMode.Open, FileAccess.Read); //初始化对称算法的密钥和向量 byte[] bykey = new byte[16]; //定义存储密钥的字节数组 byte[] byIv = new byte[8]; //定义存储向量的字节数组 fsPic.Read(bykey, 0, 16); //把图片流写入密钥缓冲区 fsPic.Read(byIv, 0, 8); //把图片流写入向量缓冲区 //临时
加密
文件 string strPath = textBox1.Text; //
加密
文件的路径 int intLent = strPath.LastIndexOf("\\") + 1; int intLong = strPath.Length; string strName = strPath.Substring(intLent, intLong - intLent); //要
加密
的文件名称 string strLinPath = "C:\\" + strName; //临时
加密
文件路径 FileStream fsOut = File.Open(strLinPath, FileMode.Create, FileAccess.Write); //开始
加密
,首先创建RC2CryptoServiceProvider 对象 RC2CryptoServiceProvider desc = new RC2CryptoServiceProvider(); BinaryReader br = new BinaryReader(fsText); //创建BinaryReader 对象 //创建CryptoStream 对象,用于写入临时
加密
文件 CryptoStream cs = new CryptoStream(fsOut, desc.CreateEncryptor(bykey, byIv), CryptoStreamMode.Write); cs.Write(br.ReadBytes((int)fsText.Length), 0, (int)fsText.Length); //写入
加密
流 cs.FlushFinalBlock(); cs.Flush(); cs.Close(); fsPic.Close(); fsText.Close(); fsOut.Close(); File.Delete(textBox1.Text.TrimEnd()); //删除原文件 File.Copy(strLinPath, textBox1.Text); //复制
加密
文件 File.Delete(strLinPath); //删除临时文件 MessageBox.Show("
加密
成功"); pictureBox1.ImageLocation = null; textBox1.Text = ""; } catch (Exception ee) { MessageBox.Show(ee.Message); } } 第19章
加密
与解密技术 851 单击“解密”按钮,实现利用图片对
加密
的文本文件进行解密的功能,“解密”按钮的Click事件的代码如下: private void button4_Click(object sender, EventArgs e) { try { //图片流 FileStream fsPic = new FileStream(pictureBox1.ImageLocation, FileMode.Open, FileAccess.Read); //解密文件流 FileStream fsOut = File.Open(textBox1.Text, FileMode.Open, FileAccess.Read); //初始化对称算法的密钥和向量 byte[] bykey = new byte[16]; //定义存储密钥的字节数组 byte[] byIv = new byte[8]; //定义存储向量的字节数组 fsPic.Read(bykey, 0, 16); //把图片流写入密钥缓冲区 fsPic.Read(byIv, 0, 8); //把图片流写入向量缓冲区 //创建临时解密文件 string strPath = textBox1.Text; //
加密
文件的路径 int intLent = strPath.LastIndexOf("\\") + 1; //获取不含文件名的路径长度 int intLong = strPath.Length; //获取含文件名的路径长度 //获取要解密文件的名称,即
加密
文件的名称 string strName = strPath.Substring(intLent, intLong - intLent); string strLinPath = "C:\\" + strName; //临时解密文件路径 FileStream fs = new FileStream(strLinPath, FileMode.Create, FileAccess.Write); //开始解密,首先创建RC2CryptoServiceProvider 对象 RC2CryptoServiceProvider desc = new RC2CryptoServiceProvider(); //创建CryptoStream 对象,用于读取
加密
文件 CryptoStream csDecrypt = new CryptoStream(fsOut, desc.CreateDecryptor(bykey, byIv), CryptoStreamMode.Read); BinaryReader sr = new BinaryReader(csDecrypt); //创建BinaryReader 对象 BinaryWriter sw = new BinaryWriter(fs); //创建BinaryWriter 对象 sw.Write(sr.ReadBytes(Convert.ToInt32(fsOut.Length))); //写入解密流 sw.Flush(); sw.Close(); sr.Close(); fs.Close(); fsOut.Close(); fsPic.Close(); csDecrypt.Flush(); File.Delete(textBox1.Text.TrimEnd()); //删除原文件 File.Copy(strLinPath, textBox1.Text); //复制
加密
文件 File.Delete(strLinPath); //删除临时文件 MessageBox.Show("解密成功"); //弹出提示信息 pictureBox1.ImageLocation = null; //清空图片 textBox1.Text = ""; //清空文本框 } catch (Exception ee) //如果出现异常 { MessageBox.Show(ee.Message); //输出异常 } } 秘 笈心法 心法领悟581:如何去除字符串尾空格? 去除字符串尾空格需要使用string
类
的Trim 方法,该方法用来从字符串的开始和末尾处移除空白字符的所 有匹配项。例如,下面的代码用来去掉textBox1 文本框中字符串的尾空格,并将结果显示在textBox2 文本框中: textBox2.Text = textBox1.Text.Trim(); 实例582 对文件进行
加密
保护 光盘位置:光盘\MR\19\582 高级 趣味指数: 实 例说明 随着计算机的普及,文件的安全越来越重要,本实例使用C#制作了一个对文件进行
加密
保护的实例。运行 C#开发实战1200 例(第II卷) 852 本实例,选择要
加密
或解密的文件,用程序来判断是否是
加密
过的文件, 如果不是,输入
加密
密码,单击“
加密
”按钮,
加密
已选择的文件;如果 是,输入解密密码,单击“解密”按钮,解密选择的
加密
文件。实例运行 效果如图19.12 所示。 关 键技术 本实例制作对文件进行
加密
保护程序时,首先选择要
加密
或解密的文 件,并输入
加密
或解密密码,然后启动一个新的线程,使用输入的密码对 指定的文件进行
加密
或解密操作。另外,如果对文件执行的是
加密
操作,则
加密
成功后删除原文件。具体实现 过程中,主要用到了DES
类
的CreateEncryptor 和CreateDecryptor 方法、CryptoStream
类
的构造函数及其Write 方法。 说明:关于DES
类
的CreateEncryptor 方法和CreateDecryptor 方法、CryptoStream
类
的构造函数及其Write 方法的详细讲解,请参见实例575中的关键技术。 设 计过程 (1)打开Visual Studio 2008 开发环境,新建一个Windows窗体应用程序,并将其命名为ProtectFile。 (2)更改默认窗体Form1 的Name 属性为Frm_Main,在该窗体中添加一个OpenFileDialog 控件,用来显 示“打开”对话框;添加两个TextBox 控件,分别用来显示选择的文件路径和输入
加密
、解密密码;添加3 个 Button控件,分别用来执行选择
加密
或解密的文件、
加密
文件和解密文件操作;添加一个ProgressBar控件,用 来显示
加密
或解密的进度。 (3)程序主要代码如下。 Frm_Main 窗体加载时,首先将
加密
文件
新版前后端接口安全技术JWT+
RSA
加密
【课程介绍】 课程目标: - 有状态登录和无状态登录的区别 - 常见的非对称
加密
算法和非对称的
加密
方式 - 老版本只使用jwt进行
加密
的弊端 - 授权中心的授权流程 - 如何整合网关组件实现jwt安全验证 - 理解什么是公钥什么是私钥 - 深刻理解授权流程什么是有状态? 有状态服务,即服务端需要记录
每次
会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?- 服务端保存大量数据,增加服务端压力- 服务端保存用户状态,无法进行水平扩展- 客户端请求依赖服务端,多次请求必须访问同一台服务器。什么是无状态? 微服务集群中的每个服务,对外提供的都是Rest风格的接口。而Rest风格的一个最重要的规范就是:服务的无状态性,即:- 服务端不保存任何客户端请求者信息- 客户端的
每次
请求必须具备自描述信息,通过这些信息识别客户端身份带来的好处是什么呢?- 客户端请求不依赖服务端的信息,任何多次请求不需要必须访问到同一台服务- 服务端的集群和状态对客户端透明- 服务端可以任意的迁移和伸缩- 减小服务端存储压力
在基于CMPP3.0协议的互联网短信平台中非
托管
模块的
调用
方法.pdf
在基于CMPP3.0协议的互联网短信平台中非
托管
模块的
调用
方法.pdf
纯C实现的aes
加密
算法
纯C实现的aes
加密
算法,2个文件,非常容易集成!
.NET技术其他语言
1,977
社区成员
12,449
社区内容
发帖
与我相关
我的任务
.NET技术其他语言
.NET技术 其他语言讨论
复制链接
扫一扫
分享
社区描述
.NET技术 其他语言讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章