使用对称加密算法AES
加密通常有对称加密(DES、AES)、非对称加密(RSA)、单向加密(MD5不可复原),非对称算法很安全但是速度慢一般用于传输对称加密的秘钥,本文主要介绍C#如何使用基于AES标准的Rijndael算法对数据包进行加密传输。
RijndaelManaged类为Rijndael算法管理类。这里有几个主要参数,单位都是bit:BlockSize、FeedbackSize、KeySize、Mode、Padding。这些参数可以影响私钥和IV长度,以及数据加密方式等。
ICryptoTransform为数据转换接口,有TransformBlock和TransformFinalBlock两个方法,这两个方法基本一样,主要是TransformBlock要求被处理数组需为InputBlockSize的整数倍,因为需要使用缓存减少GC这里在外部实现TransformFinalBlock中做的处理。
下方方法都是参照RijndaelManagedTransform.cs的源码实现的,对一个字节数组加密前需要先调用CheckBlock,返回值为存储加密后的数组大小。
public static int CheckBlock(this NetDataWriter dataWriter, int offset)
{
int bodySize = dataWriter.WritePos - offset;//dataWriter.WritePos为数组大小,offset为偏移
int inputBlockSize = NetConstants.BlockSize >> 3;
int lonelyBytes = bodySize % inputBlockSize;
int padSize = inputBlockSize - lonelyBytes;
if (padSize != inputBlockSize)//官方TransformBlock里不会做这个判断
{
bodySize += padSize;
}
int packetSize = offset + bodySize + inputBlockSize;//EncryptData返回值为inputCount+padSize,TransformBlock前保证了数组为inputBlockSize的整数倍,所以padSize=inputBlockSize
return packetSize;
}
public static int GetInputBlockSizeBytes(CipherMode cipherMode=NetConstants.ModeValue)
{
switch (cipherMode)
{
case CipherMode.ECB:
case CipherMode.CBC:
return NetConstants.BlockSize >> 3;
case CipherMode.CFB:
return NetConstants.FeedbackSize >> 3;
default:
throw new CryptographicException("Cryptography_InvalidCipherMode");
}
}
加密与解密操作
public static int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, byte[] Key, byte[] IV, bool needGenerateIV = true)
{
if (inputBuffer == null || inputBuffer.Length <= 0)
{
throw new Exception("inputBuffer is null or length is zero when encrypt");
}
if (Key == null || Key.Length != GetKeySizeBytes())
{
throw new Exception("private Key is null or length less than key size when encrypt");
}
if (IV == null || IV.Length != GetBlockSizeBytes())
{
throw new Exception("the IV is null or length less than iv size when encrypt");
}
using (RijndaelManaged managed = new RijndaelManaged())
{
managed.BlockSize = NetConstants.BlockSize;
managed.FeedbackSize = NetConstants.FeedbackSize;
managed.KeySize = NetConstants.KeySize;
if (needGenerateIV)
{
managed.GenerateIV();
Buffer.BlockCopy(managed.IV, 0, IV, 0, IV.Length);
}
managed.Mode = NetConstants.ModeValue;
managed.Padding = NetConstants.PaddingValue;
using (ICryptoTransform encryptor = managed.CreateEncryptor(Key, IV))
{
return encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
}
}
public static int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset, byte[] Key, byte[] IV)
{
if (inputBuffer == null || inputBuffer.Length <= 0)
{
throw new Exception("inputBuffer is null or length is zero when decrypt");
}
if (Key == null || Key.Length != GetKeySizeBytes())
{
throw new Exception("private Key is null or length less than key size when decrypt");
}
if (IV == null || IV.Length != GetBlockSizeBytes())
{
throw new Exception("the IV is null or length less than IV size when decrypt");
}
using (RijndaelManaged managed = new RijndaelManaged())
{
managed.BlockSize = NetConstants.BlockSize;
managed.FeedbackSize = NetConstants.FeedbackSize;
managed.KeySize = NetConstants.KeySize;
managed.Mode = NetConstants.ModeValue;
managed.Padding = NetConstants.PaddingValue;
using (ICryptoTransform encryptor = managed.CreateDecryptor(Key, IV))
{
return encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
}
}