[英]AES Encryption - Encryption/Decryption Adding Extra Bytes
我正在使用框架的对象编写一个用于加密/解密的简单库。 方法如下:
public static byte[] Encrypt(byte[] key, byte[] vector, byte[] input)
{
if(key.Length == 0)
throw new ArgumentException("Cannot encrypt with empty key");
if (vector.Length == 0)
throw new ArgumentException("Cannot encrypt with empty vector");
if (input.Length == 0)
throw new ArgumentException("Cannot encrypt empty input");
var unencryptedBytes = input;
using(AesCryptoServiceProvider aes = new AesCryptoServiceProvider {Key = key, IV = vector})
using(ICryptoTransform encryptor = aes.CreateEncryptor())
using (MemoryStream ms = new MemoryStream())
using (CryptoStream writer = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
{
writer.Write(unencryptedBytes, 0, unencryptedBytes.Length);
writer.FlushFinalBlock();
var byteArray = ms.ToArray();
if(byteArray.Length == 0)
throw new Exception("Attempted to encrypt but encryption resulted in a byte array of 0 length.");
return byteArray;
}
}
public static byte[] Decrypt(byte[] key, byte[] vector, byte[] encrypted)
{
if (key.Length == 0)
throw new ArgumentException("Cannot encrypt with empty key");
if (vector.Length == 0)
throw new ArgumentException("Cannot encrypt with empty vector");
if (encrypted == null || encrypted.Length == 0)
throw new ArgumentException("Cannot decrypt empty or null byte array");
byte[] unencrypted;
using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider { Key = key, IV = vector })
using (ICryptoTransform decryptor = aes.CreateDecryptor(key, vector))
using (MemoryStream ms = new MemoryStream(encrypted))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
cs.Read(encrypted, 0, encrypted.Length);
unencrypted = ms.ToArray();
}
return unencrypted;
}
例如,将其以编码字符串的形式提供:
var expected = "This is an example message";
var messageBytes = Encoding.UTF8.GetBytes(expected);
(在此示例中)输入26个字节。 加密后,它保留为32个字节,当将其转换为字符串时,它会在末尾附加随机字符,但在其他情况下则完全有效,如下所示:
"This is an example message�(4���"
生成新的向量/密钥会更改附加到末尾的随机字符。
如何消除这种超字节行为?
编辑
包括要求的单元测试。
[TestMethod]
public void CanEncryptAndDecryptByteArray()
{
var expected = "This is an example message";
var messageBytes = Encoding.UTF8.GetBytes(expected);
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.GenerateIV();
aes.GenerateKey();
var byteKey = Convert.ToBase64String(aes.Key);
var vectorKey = Convert.ToBase64String(aes.IV);
var key = Convert.FromBase64String("Qcf+3VzYNAfPUCfBO/ePSxCLBLItkVfk8ajK86KYebs=");
var vector = Convert.FromBase64String("aJNKWP7M2D44jilby6BzGg==");
var encrypted = EncryptionManager.Encrypt(key, vector, messageBytes);
var decrypted = EncryptionManager.Decrypt(key, vector, encrypted);
var actual = Encoding.UTF8.GetString(decrypted);
Assert.AreEqual(expected, actual);
}
垃圾字节是因为我们正在读取和写入同一数组。
new MemoryStream(encrypted))
告诉隐窝从读取encrypted
。
cs.Read(encrypted, 0, encrypted.Length);
告诉它要写入encrypted
。
解决方案:
using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider { Key = key, IV = vector })
using (ICryptoTransform decryptor = aes.CreateDecryptor(key, vector))
using (MemoryStream ms = new MemoryStream(encrypted))
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
var decrypted = new byte[encrypted.Length];
var bytesRead = cs.Read(decrypted, 0, encrypted.Length);
return decrypted.Take(bytesRead).ToArray();
}
请注意,我们从数组而不是整个数组中获取bytesRead
,否则我们将以null字节结尾(这将导致字符串比较失败,但在编辑器中看起来相同)
AES加密是一种块加密 ,其块大小为16字节(128位)[注意:密钥大小可以为128位,192位或256位,但是数据块大小为16字节的倍数] 。 因此,要使用AES,生成的加密消息将是16的乘积-否则不能。
要解密它,您可能也想摆脱它引起的额外字节。
一种方法是在邮件中附加标题,说明邮件的字节数。 然后在解密端,读取此标头并削减字节数
[header = value of 26] + [message]
或者,您可以在加密邮件的末尾附加一些额外的字节
[message][append with 000000] //to make up the block, such that the message length will be of multiplication of 16
在上面的两种方法中,我个人更喜欢第一种方法,因为它更清晰,而第二种方法则假定您接收到某些文本模式,该文本模式最后无法连接为0000。
除了以上两种给定的方法之外,我不知道是否有办法解决此问题-隐式(如使用CryptoStream )或显式。
AES加密以16、24或32字节(或128、192或256位)的块进行加密。 因此,您获取的数据只是打包到最后的随机数据。
您必须在数据前加上几个字节来表示实际的长度:
var length = new byte [] { (byte) ((unencryptedBytes.Length >> 8) & 0xff) ,
(byte) (unencryptedBytes.Length & 0xff);
writer.Write(length, 0, length.Length);
writer.Write(unencryptedBytes, 0, unencryptedBytes.Length);
writer.FlushFinalBlock();
然后在阅读器中检索长度:
unencrypted = ms.ToArray();
int length = ((int) unencrypted[0] << 8) + unencrypted[1];
var result = new byte[length];
unencrypted.CopyTo(result, 2, 0, length);
return result;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.