Rijndael:相同的字符串,不同的结果

发布于 2024-11-28 05:39:04 字数 3941 浏览 0 评论 0原文

我们有一个小型桌面应用程序,现在需要作为网络功能提供(.Net)。该应用程序包含一些加密代码并使用 .Net 框架中的 Rijndael 类。该代码接受输入字符串,对其进行加密并将结果写入文件。由于所有代码都包含在一个类中,因此我只是将该类复制到我的 Web 服务应用程序中。当我在原始应用程序和新应用程序中使用相同的密钥加密相同的字符串时,结果是不同的。 原始应用程序给出的结果字符串是我的网络服务给出的结果字符串的子集。后者在加密字符串的末尾有附加字符。

下面是我正在使用的代码。请注意,我没有开发这段代码,也没有完全理解它。对行为差异有什么想法吗?请帮忙!!

这是获取用户输入并调用加密器的代码。

    public void EncryptDomain(string EncryptValue, string outputDomainFile)
    {
            if (EncryptValue.Length > 0)
            {
                if ((outputDomainFile != null) && (outputDomainFile.Length > 0))
                {
                    _outputDomainFile = outputDomainFile;
                }

                byte[] input = Encoding.UTF8.GetBytes(EncryptValue);

                Transform(input, TransformType.ENCRYPT);

            }

这是加密器代码:

    private byte[] Transform(byte[] input, TransformType transformType)
    {
        CryptoStream cryptoStream = null;      // Stream used to encrypt
        RijndaelManaged rijndael = null;        // Rijndael provider
        ICryptoTransform rijndaelTransform = null;// Encrypting object            
        FileStream fsIn = null;                 //input file
        FileStream fsOut = null;                //output file
        MemoryStream memStream = null;          // Stream to contain data
        try
        {
            // Create the crypto objects
            rijndael = new RijndaelManaged();
            rijndael.Key = this._Key;
            rijndael.IV = this._IV;
            rijndael.Padding = PaddingMode.Zeros;   

            if (transformType == TransformType.ENCRYPT)
            {
                rijndaelTransform = rijndael.CreateEncryptor();
            }
            else
            {
                rijndaelTransform = rijndael.CreateDecryptor();
            }

            if ((input != null) && (input.Length > 0))
            {
                //memStream = new MemoryStream();
                //string outputDomainFile = 
                FileStream fsOutDomain = new FileStream(_outputDomainFile,
                                            FileMode.OpenOrCreate, FileAccess.Write);

                cryptoStream = new CryptoStream(
                     fsOutDomain, rijndaelTransform, CryptoStreamMode.Write);

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

                cryptoStream.FlushFinalBlock();

                //return memStream.ToArray();
                return null;
            }
            return null;

        }
        catch (CryptographicException)
        {
            throw new CryptographicException("Password is invalid. Please verify once again.");
        }
        finally
        {
            if (rijndael != null) rijndael.Clear();
            if (rijndaelTransform != null) rijndaelTransform.Dispose();
            if (cryptoStream != null) cryptoStream.Close();
            if (memStream != null) memStream.Close();
            if (fsOut != null) fsOut.Close();
            if (fsIn != null) fsIn.Close();
        }
 }

设置 IV 值的代码:

    private void GenerateKey(string SecretPhrase)
    {
        // Initialize internal values
        this._Key = new byte[24];
        this._IV = new byte[16];

        // Perform a hash operation using the phrase.  This will 
        // generate a unique 32 character value to be used as the key.
        byte[] bytePhrase = Encoding.ASCII.GetBytes(SecretPhrase);
        SHA384Managed sha384 = new SHA384Managed();
        sha384.ComputeHash(bytePhrase);
        byte[] result = sha384.Hash;

        // Transfer the first 24 characters of the hashed value to the key
        // and the remaining 8 characters to the intialization vector.
        for (int loop = 0; loop < 24; loop++) this._Key[loop] = result[loop];
        for (int loop = 24; loop < 40; loop++) this._IV[loop - 24] = result[loop];
    }

We had a small desktop app that needs to be provided as a web feature now (.Net). This app contains some code for encryption and uses Rijndael classes from .Net framework. The code accepts an input string, encrypts it and writes it out the results to a file. Since all the code is contained in one class, I just copied the class to my web service application. When I encrypt the same string, using the same key, in the original app and the new app, the results are different.
The result string given by the original app is a subset of the result string given by my web service. The latter has additional characters at the end of the encrypted string.

Below is the code I am using. Please note that I did not develop this code nor do I understand it fully. Any thoughts on the difference in behaviour? Please help!!

Here is the code that gets the user input and calls the encryptor.

    public void EncryptDomain(string EncryptValue, string outputDomainFile)
    {
            if (EncryptValue.Length > 0)
            {
                if ((outputDomainFile != null) && (outputDomainFile.Length > 0))
                {
                    _outputDomainFile = outputDomainFile;
                }

                byte[] input = Encoding.UTF8.GetBytes(EncryptValue);

                Transform(input, TransformType.ENCRYPT);

            }

This is the encryptor code:

    private byte[] Transform(byte[] input, TransformType transformType)
    {
        CryptoStream cryptoStream = null;      // Stream used to encrypt
        RijndaelManaged rijndael = null;        // Rijndael provider
        ICryptoTransform rijndaelTransform = null;// Encrypting object            
        FileStream fsIn = null;                 //input file
        FileStream fsOut = null;                //output file
        MemoryStream memStream = null;          // Stream to contain data
        try
        {
            // Create the crypto objects
            rijndael = new RijndaelManaged();
            rijndael.Key = this._Key;
            rijndael.IV = this._IV;
            rijndael.Padding = PaddingMode.Zeros;   

            if (transformType == TransformType.ENCRYPT)
            {
                rijndaelTransform = rijndael.CreateEncryptor();
            }
            else
            {
                rijndaelTransform = rijndael.CreateDecryptor();
            }

            if ((input != null) && (input.Length > 0))
            {
                //memStream = new MemoryStream();
                //string outputDomainFile = 
                FileStream fsOutDomain = new FileStream(_outputDomainFile,
                                            FileMode.OpenOrCreate, FileAccess.Write);

                cryptoStream = new CryptoStream(
                     fsOutDomain, rijndaelTransform, CryptoStreamMode.Write);

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

                cryptoStream.FlushFinalBlock();

                //return memStream.ToArray();
                return null;
            }
            return null;

        }
        catch (CryptographicException)
        {
            throw new CryptographicException("Password is invalid. Please verify once again.");
        }
        finally
        {
            if (rijndael != null) rijndael.Clear();
            if (rijndaelTransform != null) rijndaelTransform.Dispose();
            if (cryptoStream != null) cryptoStream.Close();
            if (memStream != null) memStream.Close();
            if (fsOut != null) fsOut.Close();
            if (fsIn != null) fsIn.Close();
        }
 }

Code that sets up the IV values:

    private void GenerateKey(string SecretPhrase)
    {
        // Initialize internal values
        this._Key = new byte[24];
        this._IV = new byte[16];

        // Perform a hash operation using the phrase.  This will 
        // generate a unique 32 character value to be used as the key.
        byte[] bytePhrase = Encoding.ASCII.GetBytes(SecretPhrase);
        SHA384Managed sha384 = new SHA384Managed();
        sha384.ComputeHash(bytePhrase);
        byte[] result = sha384.Hash;

        // Transfer the first 24 characters of the hashed value to the key
        // and the remaining 8 characters to the intialization vector.
        for (int loop = 0; loop < 24; loop++) this._Key[loop] = result[loop];
        for (int loop = 24; loop < 40; loop++) this._IV[loop - 24] = result[loop];
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

可是我不能没有你 2024-12-05 05:39:04

我猜这是因为 IV(初始化向量)

I would guess that's because of the IV (Initialisation Vector)

攒眉千度 2024-12-05 05:39:04

这是一个典型的错误。无论您是否自己生成 IV,Rijndael (AES) 都会为您提供一个。诀窍是始终保存 IV(RijndaelManaged 上有一个 getter)。

  • 解密时,需要两者传递Key和IV

如果您要将数据保存到文件或数据库中,您可以将 IV 存储为纯文本。您甚至可以以纯文本形式通过有线(网络、互联网)传递 IV。攻击者无法(据我所知)仅仅根据 IV 破解你的密码。传递或存储 IV 通常是通过在密文前面添加前缀或将其附加在末尾来完成的。 (连接两个字符串)

例如
密文 IV 或 IV 密文。 (请记住 IV 是明文形式,它应该具有固定长度 - 以便在接收解密或数据库插入时轻松分离)

因此,如果您的密钥是 ABCDEFABCDEFABCD 并且您的 IV 是ABCDEF0123456789
和这个明文:
“这是一些秘密文本”(比方说)会产生一个密码,例如:abcd1234abcd00

您可以像这样传输(或存储):ABCDEF0123456789abcd1234abcd00 >

This is a classic mistake. Whether you generate an IV yourself or not Rijndael (AES) will provide one for you. The trick is to always save the IV (there's a getter on RijndaelManaged).

  • When you decrypt, you need to pass both the Key and IV.

If you're saving data to a file or database you can store the IV as a plain text. You can even pass the IV on wire (network, internet) as a plain text. The attacker wont be able(as far as I know) break your cipher based just on an IV. Passing or storing the IV is usually done by prefixing it in front of ciphertext or appending it at the end. (concatenating the two strings)

e.g.
CiphertextIV or IVCiphertext. (remember IV is in plaintext is it should be of a fixed length - making it easy to separate upon receiving for decryption or for database insertion)

So, if your Key is ABCDEFABCDEFABCD and your IV is ABCDEF0123456789
and this plaintext:
'this is some secrect text' (let's say) produces a cipher such as: abcd1234abcd00

You would transmit(or store) like it this: ABCDEF0123456789abcd1234abcd00

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文