首页 > 解决方案 > Rijndael 加密器:获取空字节 []。不加密任何东西

问题描述

晚上好!

我正在尝试在 c# 中使用 Rijndael 算法和 Rijndael 类来实现加密器。我试图遵循(不做完全相同的代码)下面的链接,但问题是给出了一个要加密的字符串我没有得到任何结果。我也没有收到任何错误消息。

https://docs.microsoft.com/pt-br/dotnet/api/system.security.cryptography.rijndael?view=netframework-4.8

CryptDecrypt.cs

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace RijndaelAlgorithm {
    public class CryptDecrypt {
        private Byte[] iv;
        private Byte[] key; 

        public CryptDecrypt(String key) {
            iv = new Byte[] {21, 10, 21, 251, 132, 76, 121, 27, 210, 81, 215, 99, 14, 235, 11, 75};
            this.key = Encoding.ASCII.GetBytes(key);
        }

        public String encryptMsg(String originalMsg) {
            byte[] encryptedMsg;

            Rijndael rijAlg = Rijndael.Create();
            rijAlg.Key = formatKey();
            rijAlg.IV = iv;

            MemoryStream msEncrypt = new MemoryStream();
            ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
            CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

            StreamWriter swEncrypt = new StreamWriter(csEncrypt);
            swEncrypt.Write(originalMsg);

            encryptedMsg = msEncrypt.ToArray();
            Console.WriteLine("encryptedMsg.Length: " + encryptedMsg.Length);

            return Convert.ToBase64String(encryptedMsg, 0, encryptedMsg.Length);
        }

        private Byte[] formatKey() {
            int len = key.Length;

            String strKey = System.Text.Encoding.UTF8.GetString(key);
            String fillKey = "";
            String strFormatedKey = "";

            Byte[] formatedKeyByte;

            if (len < 16)
                fillKey = new String('X',(16 - len));

            strFormatedKey = String.Concat(strKey, fillKey);
            formatedKeyByte = Encoding.ASCII.GetBytes(strFormatedKey);

            return formatedKeyByte;
        }
    }
}

菜单.cs

using System;

namespace RijndaelAlgorithm {
    public class Menu {
        private CryptDecrypt r;

        public Menu() {
            r = new CryptDecrypt("123654");
        }

        public void showMenu() {
            Console.WriteLine("the encrypted message is: " + r.encryptMsg("isjustatest"));
        }
    }
}

标签: c#encryptionaesrijndael

解决方案


您似乎想用您的 .NET 应用程序加密一条消息,并希望获得与您在评论中提到的特定在线服务相同的加密字节。

范围

加密的一个参数是初始化向量 (IV)。它应该是随机的并且只使用一次。因此,如果正确实现了两个应用程序(具有不同的随机 IV),则加密的字节是不同的。

即使您使用相同的输入,每次您按下该键时,此服务都会返回不同的结果。

但是,如果您通常采用不同的加密结果并使用相同的密钥对其进行解密,您将获得原始字节。

使用此特定服务进行测试的下一个问题是,它们始终提供相同的前缀 base64 序列“U2FsdGVkX1”。这不是标准的 AES 输出(如果你解码这个 base64 序列,你会得到'Salted_P')。因此,使用不同的在线服务进行测试是有意义的。

因此,如果两个 AES-256 编码实现使用相同的参数,我们将得到相同的编码结果。我们需要它:

  • 密钥(32 个字节,而不是 AES-256 的 16 个字节)
  • 四(16字节)

说到密钥长度:正如其他人在评论中提到的那样,您不应该简单地添加“X”或类似的东西,而是使用标准的加密机制来派生一个好的密钥。

方便测试的方法是将十六进制字符串转换为字节数组并返回,例如,请参阅这个很酷的答案中的 StringToByteArray 和 ByteArrayToString 方法: https ://stackoverflow.com/a/311179

试一试吧。如果我们收到您的消息“isjustatest”,其中包含十六进制字符串“69736a7573746174657374374”,我们需要 AES-256 的 32 字节密钥和 16 字节 IV。

正如评论中提到的其他人一样,您需要刷新和关闭流(或者更好的是,使用“使用”语句)。

获取您的代码并更改密钥和 iv 分配并将加密消息输出到控制台:

rijAlg.Key = StringToByteArray("519C7C3402A943D8AF83746C1548E475319EBDA6A38046059F83B21709BD6A5B"); //32 bytes
rijAlg.IV =  StringToByteArray("0D024CF947CE4C288880D0B34D29BFA5"); // 16 bytes
...
swEncrypt.Write(originalMsg);
swEncrypt.Flush();
swEncrypt.Close();
...
Console.WriteLine("encrypted bytes: '" + ByteArrayToString(encryptedMsg) + "'");

这会在调试控制台中输出“419536f27da3406625b2d07f43833aab”。

所以现在我们可以使用在线服务,例如https://cryptii.com/pipes/aes-encryption,我们可以在其中输入输入数据,选择加密算法,提供密钥和 IV 字节,然后我们会得到与您的相同的结果程序,请参见此处的屏幕截图:

在此处输入图像描述

如上所述,在实际应用中使用时不要忘记使用不同的随机 IV。


推荐阅读