2

我有以下两种方法。

第一种方法

  //SymmetricEncryting 
 private byte[] SymmetricEncrypt()
  {
  try
      {
        //Get Byte Value 
        byte[] x= Encoding.Default.GetBytes("Test");

        byte [] y;

        //Create Symmetric Key Encription
        RijndaelManaged rijndaelManaged = new RijndaelManaged();

        //GetSymmetricPublicKey
        _symmetricPublicKey = rijndaelManaged.Key;

        //Get Symmetric Public IV
        _symmetricPublicIv = rijndaelManaged.IV;

        using (MemoryStream memoryStream = new MemoryStream(x))
        {
            //Start EncriptionProcess
            var cryptoStream = new CryptoStream(memoryStream,
                                                rijndaelManaged.CreateEncryptor
                                                 (_symmetricPublicKey,
                                                 _symmetricPublicIv),
                                                CryptoStreamMode.Write);

            cryptoStream.Write(x, 0, x.Length);

            // Complete the encryption process
            //cryptoStream.FlushFinalBlock();

            y= memoryStream.ToArray();


        }

        return y;
    }
    catch (Exception)
    {
        throw;
    }
}

第二种方法

private string Decrypt(
    byte[] y,
    byte[] symmetricPublicKey,
    byte[] symmtricPublicIv)
{
    try
    {
        //Create the Key Container
        CspParameters cspParameters = new CspParameters();

        //Get the AsyPrivate and Public key from the Container
        cspParameters.KeyContainerName = "Keys";


        var rsaCryptoServiceProvider = new RSACryptoServiceProvider(cspParameters);

        //Decrypt and get the Symmetric Public key
        var decryptedSymmetricPubk = rsaCryptoServiceProvider.Decrypt(symmetricPublicKey, false);

        //Decrypt and get the Symmetric Public IV
        var decryptedSymmetricPubIv = rsaCryptoServiceProvider.Decrypt(symmtricPublicIv, false);

        //Create RijndaelManaged object to do the Symmtric dycrption
        RijndaelManaged rijndaelManaged = new RijndaelManaged();

        //Create cryptostream using decrypted symmetric Public Key and IV
        ICryptoTransform iCryptoTransform = rijndaelManaged.CreateDecryptor(decryptedSymmetricPubk,
                                                                            decryptedSymmetricPubIv);
        //Create a memory stream 
        using (MemoryStream memoryStream = new MemoryStream(y))
        {

            var cryptoStream = new CryptoStream(memoryStream, iCryptoTransform, CryptoStreamMode.Read);

            byte[] z= new byte[y.Length];

            cryptoStream.Read(z, 0, z.Length);

            //cryptoStream.FlushFinalBlock();

            //Convert byte array to string
            var x= System.Text.Encoding.Default.GetString(z);

            return x;
        }
    }
    catch (Exception)
    {
        throw;
    }

正如您在代码中看到的那样,我正在尝试使用对称加密来加密字符串。我使用我已经创建的非对称公钥来加密对称公钥和 Iv。然后我正在尝试解密加密的字符串。

问题 1加密和解密 的目的是什么cryptoStream.FlushFinalBlock();。正如我从 msdn 中了解到的,它将结束在 cyptostream 上运行的进程

问题 2 如果我取消注释cryptoStream.FlushFinalBlock();它会引发异常 的行"Memory stream is not expandable."。但是,如果我评论该行,它将正常工作并返回一个字节数组。

问题 3"system.security.cryptography.cryptographicexception length of the data to decrypt is invalid然而,第二种方法在执行 cryptoStream.Read(z, 0, z.Length); 行时 抛出异常。

我在调试时找不到这些错误的实际原因。我也在谷歌上进行了一些搜索。但不幸的是我找不到任何解决方案。谁能解释一下答案?

4

2 回答 2

9

您正在使用 PKCS 填充进行加密(这是默认设置)。AES/Rijndael 是一种分组密码,这意味着它一次只能加密 16 个字节的块。为了允许分组密码加密任意大小的数据,我们使用填充算法。PKCS 填充的工作原理是在加密时在末尾添加 1-16 个字节,在解密时删除它们。填充的长度在填充本身中编码。

您需要FlushFinalBlock在加密时让 CryptoStream 知道没有更多的传入数据,它应该添加填充。当您在读取模式下使用 CryptoStream 时,它不是必需的,也不应该使用。

第一个例外是因为您使用纯文本数组作为 MemoryStream 的后备存储。由于填充,加密将大于明文。

第二个例外是因为您删除了该FlushFinalBlock语句,并且因为 MemoryStream 不允许调整大小以生成正确长度的数组。加密数据应始终为 16 字节的倍数,但由于 MemoryStream 将重用xy因此将具有与 相同的长度x,这并不总是有效的长度。

解决方案是:

  1. FlushFinalBlock在 SymmetricEncrypt 中使用。
  2. 替换using (MemoryStream memoryStream = new MemoryStream(x))和。using (MemoryStream memoryStream = new MemoryStream(y))_ using (MemoryStream memoryStream = new MemoryStream())这将允许MemoryStreams 自由调整大小。
于 2012-05-30T05:55:02.673 回答
0

奇怪的是,我也可以在解密时进行写操作。就像是:

var decryptMemoryStream = new MemoryStream();
var decryptStream = new CryptoStream(decryptMemoryStream, iCryptoTransform , CryptoStreamMode.Write);

//write the unencrypted data array to the stream
decryptStream.Write(y, 0, y.Length);
decryptStream.Flush();
decryptStream.Close();

var decryptedData = decryptMemoryStream.ToArray();
于 2018-03-05T00:06:41.703 回答