• 对称加密


    (本文系张子阳《.net之美》读书笔记,文中多处引用书本内容)

    首先简单介绍一下流的概念。

    流的最主要用途就是与应用程序外部的文件或数据源进行数据交互。考虑将一个TXT文件从D盘拷贝到C盘。

    它的拷贝过程应该是这样的:

    源文件在磁盘中,需要建立一个类似管道的东西将文件和内存中的应用程序连接起来,并且将文件按字节发送。创建一个byte[]数组用于存放字节。

    接下来,在C盘创建目标文件,同样通过一个管道一样的东西,将字节写入管道中,间接地写到文件中去。

    而流,就是这种管道,或者说起到管道的作用。

    下面简单学习一下代码:

     1 Stream source = new FileStream("D:\test.txt", FileMode.Open, FileAccess.Read);//读取“管道”
     2             int size = 10;
     3             byte[] buffer = new byte[size];//用于储存临时字节
     4             int bytesRead;
     5             Stream target = new FileStream("C:\test.txt", FileMode.Create, FileAccess.Write);//写入“管道”
     6             //因不知源文件字节长度,只能通过循环,每次读取一定数量的字节并写入流
     7             do
     8             {
     9                 bytesRead = source.Read(buffer, 0, size);
    10                 target.Write(buffer, 0, bytesRead);//第三个参数是从Buffer中读取的个数,应该是bytesRead不是size
    11             } while (bytesRead > 0);
    12 
    13             source.Dispose();
    14             target.Dispose();
    View Code

     或者使用流包装器类(不是流),StreamReader和StreamWriter,用法与上面差不多,注意已不是字节流,而是字符流

     1 StreamReader sr = new StreamReader("D:\test.txt");
     2             StreamWriter sw = new StreamWriter("C:\test2.txt");
     3             int maxSize = 10;
     4             char[] charBuffer = new char[maxSize];//注意,字符流
     5             int charRead;
     6             do
     7             {
     8                 charRead = sr.Read(charBuffer, 0, maxSize);
     9                 sw.Write(charBuffer, 0, charRead);
    10             } while (charRead > 0);
    11 
    12             sr.Dispose();
    13             sw.Dispose();
    View Code

    流还包括装饰器流,包装器类还包括BinaryReader和BinaryWriter。在这里就不详细展开了。

    对称加密

    加密和解密属于数据安全的范畴,在消息传输时,通过对消息进行特殊编码(即加密),建立一种安全的交流方式,使得只有发送者所期望的接收者能够理解(即解密)。一般场景中有三种角色:发送方,接收方,第三方。

    消息加密应同时满足以下三个条件:

    1)完整性,消息的可以确定消息在传输途中没有被篡改过,消息是完好无损的。

    2)保密性,消息的发送方能够确定消息只有预期的接收方可以理解或解密(不保证第三方无法获得,但保证第三方无法解密)。

    3)可认证性,消息的接收方可以确定消息是由谁发送的(接收方可以确认消息确定是由预期的发送方发送的)。

    消息加密有散列运算(即Hash运算)、对称加密、非对称加密等,这里介绍一下对称加密(比较简单易于理解)。

    对称加密流程如下:

    1)发送方和接收方持有相同的密钥,并严格保密。

    2)发送方使用密钥对消息进行加密,然后发送消息。

    3)接收方收到消息后,使用同样的密钥对消息进行解密。

    在上述流程中,第三方可能截取消息,但得到一堆乱码,没有密钥解密。

    .net提供了一组类型(命名空间System.Security.Cryptography)来实现对称加密和解密。这些类型拥有共同的基类SymmetricAlgorithm,见下图。

    可以看到上面类型分为CryptoServiceProvider和Managed两类,前者是由托管代码写的,后者调用的是Windows Crypto API,相当于一个包装类。

    TripleDES算法加密

    假设选择TripleDES算法进行加密,步骤如下:

    1)创建一个TripleDESCryptoServiceProvider实例(假定变量名为provider)

    2)在provider上指定密钥和IV。密钥通常为128位或192位字节,IV为64位。IV是为了解决同样的字符加密后字符仍一样的问题,例如ABABABCDE加密后,前面三个AB的数据理论上是一样且位置不变,引入IV之后即使是重复的也被打乱了。

    3)利用provider创建加密器或解密器。ICryptoTransform定义了加密转换的运算,.net在底层调用这个接口。加密器:CreateEncryptor()方法,解密器:CreateDecryptor()方法。

    4).net采用流的方式进行加密和解密,运算过程会涉及两个流,一个是明文流,包含加密前的数据,一个是密文流,包含加密后的数据。在两者之间,有一个中介者,负责将明文流转换为密文流,以及将密文流转换为明文流。这个中介者也是一个流类型,叫CryptoStream,它的构造函数有三个参数 

    public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode),其中每次传入的流都是密文流,根据需要传入加密器或解密器,以及写或读模式。

    5)创建完以上几个对象,就可以进行转换了,加密过程为:明文流读字节,CryptoStream写密文流;解密过程为:CryptoStream读密文流,明文流写字节。

    密钥应注意一点:3DES算法,如果1重、2重和3重密钥(每8位)有一个相同,算法会退化为2重或1重,运行报错。见下图:

    加解密过程可以简单归纳如下:

    1)创建TripleDESCryptoServiceProvider对象,指定密钥和IV,创建加密器或解密器

    2)创建明文流和密文流

    3)创建转换中介者CryptoStream对象,将密文流传入。

    4)加密:明文流读字节,CryptoStream写密文流;解密:CryptoStream读密文流,明文流写字节。

    实例

    加密帮助类

     1 using System;
     2 using System.Security.Cryptography;
     3 using System.IO;
     4 using System.Text;
     5 
     6 namespace ch09
     7 {
     8     class EncryptorHelper
     9     {
    10         //密钥应注意一点:3DES算法,如果1重、2重和3重密钥(每8位)有一个相同,算法会退化为2重或1重,运行报错
    11         private static string _rgbKey = "thisishelloworld";
    12         private static byte[] _rgbIV = new byte[] { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
    13 
    14         public static string Encryptor(string plainText)
    15         {
    16             TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();//创建provider,利用其产生加密器
    17             provider.Key = Encoding.Default.GetBytes(_rgbKey);
    18             provider.IV = _rgbIV;
    19             ICryptoTransform encryptor = provider.CreateEncryptor();//加密器
    20             byte[] plainBytes = Encoding.GetEncoding("gb2312").GetBytes(plainText);
    21             MemoryStream plainStream = new MemoryStream(plainBytes);//创建明文流
    22             MemoryStream cipherStream = new MemoryStream();//创建密文流
    23             CryptoStream enCryptoStream = new CryptoStream(cipherStream, encryptor, CryptoStreamMode.Write);//创建加密中介
    24             int maxSize = 10;
    25             byte[] buffer = new byte[maxSize];
    26             int bytesRead = 0;
    27             do
    28             {
    29                 bytesRead = plainStream.Read(buffer, 0, maxSize);
    30                 enCryptoStream.Write(buffer, 0, bytesRead);//谨记这里应该是写入读出的长度,而不是buffer本身的长度
    31             } while (bytesRead > 0);
    32             enCryptoStream.FlushFinalBlock();
    33             return Convert.ToBase64String(cipherStream.ToArray());
    34 
    35         }
    36 
    37 
    38         public static string Decryptor(string cipherText)
    39         {
    40             TripleDESCryptoServiceProvider provider = new TripleDESCryptoServiceProvider();
    41             provider.Key = Encoding.Default.GetBytes(_rgbKey);
    42             provider.IV = _rgbIV;
    43             ICryptoTransform decryptor = provider.CreateDecryptor();
    44             byte[] cipherByte = Convert.FromBase64String(cipherText);
    45             MemoryStream plainStream = new MemoryStream();
    46             MemoryStream cipherStream = new MemoryStream(cipherByte);
    47             CryptoStream deCryptoStream = new CryptoStream(cipherStream, decryptor, CryptoStreamMode.Read);
    48             int maxSize = 10;
    49             byte[] buffer = new byte[maxSize];
    50             int bytesRead = 0;
    51             do
    52             {
    53                 bytesRead = deCryptoStream.Read(buffer, 0, maxSize);
    54                 plainStream.Write(buffer, 0, bytesRead);
    55             } while (bytesRead > 0);
    56 
    57             deCryptoStream.Dispose();
    58             return Encoding.GetEncoding("gb2312").GetString(plainStream.ToArray());
    59         }
    60     }
    61 }
    View Code

    使用帮助类

    1  string plainText = "我要握住一个最美的梦,给未来的自己~~real me!";
    2             Console.WriteLine("原文:" + plainText);
    3             string encryptedString = EncryptorHelper.Encryptor(plainText);
    4             Console.WriteLine("加密后:" + encryptedString);
    5             Console.WriteLine("解密:" + EncryptorHelper.Decryptor(encryptedString));
    6             Console.Read();
    View Code

    输出

  • 相关阅读:
    一步一步学EF系列【4、升级篇 实体与数据库的映射】live writer真坑,第4次补发
    一步一步学EF系列3【升级篇 实体与数据库的映射】
    一步一步学EF系列2【最简单的一个实例】
    一步一步学EF系列1【Fluent API的方式来处理实体与数据表之间的映射关系】
    MVC5 Entity Framework学习之创建复杂的数据模型
    Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
    动手写一个Remoting接口测试工具(附源码下载)
    通信服务器群集——跨服务器通信Demo(源码)
    轻量级通信引擎StriveEngine —— C/S通信demo(2) —— 使用二进制协议 (附源码)
    PAT A1011 World Cup Betting(20)
  • 原文地址:https://www.cnblogs.com/kingsleylam/p/3606423.html
Copyright © 2020-2023  润新知