【问题标题】:Rijndael encrypter: Getting empty byte[]. Not encrypting anythingRijndael 加密器:获取空字节 []。不加密任何东西
【发布时间】:2019-10-24 10:39:02
【问题描述】:

晚上好!

我正在尝试在 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"));
        }
    }
}

【问题讨论】:

  • 您能否在单独的项目或 .net 上创建一个 minimal reproducible example,仅解决您问题的加密部分
  • 我尽我所能。 RijndaelAlgorithm 类只有两个方法,可能问题出在 formatKey() 中。可能不会,但我不知道。 Menu 类是我定义要加密的密钥和消息的地方。
  • 为什么要去掉 using() 结构?由于它们已经消失,您现在必须手动调用swEncrypt.Flush();,然后在写入之后调用csEncrypt.FlushFinalBlock()
  • 因为我是 c# 的新手,而且这个合成器对我来说非常丑陋和不寻常。我添加了 swEncrypt.Flush();然后是 swEncrypt.Write(originalMsg); 之后的 csEncrypt.FlushFinalBlock()现在工作正常。显然。问题是我尝试在crypt-online.ru/en/crypts/aes 中加密相同的消息,但我得到了另一件事。我为密钥大小选择 256 位,为密钥选择“123654”,我得到了编码:U2FsdGVkX1+IVWR60YK3F6fN7F3a7SKPSpPDvF6ZXlA= 并使用我的代码得到 GlIhsK3UihG+nlmBZHgHYg== 为什么?
  • 您的代码使用 128 位密钥,而不是 256。此外,使用 'X' 填充是非常不寻常的,并且不太可能由该在线工具完成。使用基于密码的密钥派生函数(例如 Argon2 或 PBKDF2)将低熵密钥转换为适当的加密密钥。并且不要为任何给定的密钥重复使用 IV。

标签: c# encryption aes rijndael


【解决方案1】:

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

参数

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

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

但是,如果你一般取不同的加密结果,用相同的密钥解密,你会得到原来的字节。

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

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

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

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

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

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

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

获取您的代码并更改密钥和 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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多