C# MachineKey加密不是持久性的

C# MachineKey加密不是持久性的,c#,asp.net,asp.net-mvc,encryption,machinekey,C#,Asp.net,Asp.net Mvc,Encryption,Machinekey,我使用MachineKey.Protect()方法加密在asp.net MVC应用程序中作为查询字符串传递的id 下面是我用来加密/解密的代码: public static string Encrypt(this string expression) { if (string.IsNullOrEmpty(expression)) return string.Empty; byte[] stream = Encoding.Unicode.GetBytes(expr

我使用
MachineKey.Protect()
方法加密在asp.net MVC应用程序中作为查询字符串传递的id

下面是我用来加密/解密的代码:

public static string Encrypt(this string expression)
{
    if (string.IsNullOrEmpty(expression))
        return string.Empty;

    byte[] stream = Encoding.Unicode.GetBytes(expression);
    byte[] encodedValue = MachineKey.Protect(stream);            
    return HttpServerUtility.UrlTokenEncode(encodedValue);            
}

public static string Decrypt(this string expression)
{
    if (string.IsNullOrEmpty(expression))
        return string.Empty;

    byte[] stream = HttpServerUtility.UrlTokenDecode(expression);
    byte[] decodedValue = MachineKey.Unprotect(stream);
    return Encoding.Unicode.GetString(decodedValue);
}
下面是我的
web.config
文件中的
MachineKey
元素:

<system.web>
    .
    .
    .
    <machineKey validationKey="xxx" decryptionKey="xxx" validation="SHA1" decryption="AES" />
</system.web>

.
.
.

问题是加密的id不是持久的。每次调用该方法时,都会得到一个新的加密表达式。如何使其持久化?

尝试向Machine.Key.protect方法添加一个purpose参数!像这样

public static class Key
{       
    public static string EncryptWithAPurpose(this string expression, string[] purpose)
    {
        if (string.IsNullOrEmpty(expression))
            return string.Empty;

        byte[] stream = Encoding.Unicode.GetBytes(expression);
        byte[] encodedValue = MachineKey.Protect(stream, purpose);
        return HttpServerUtility.UrlTokenEncode(encodedValue);
    }

    public static string DecryptWithAPurpose(this string expression, string[] purpose)
    {
        if (string.IsNullOrEmpty(expression))
            return string.Empty;

        byte[] stream = HttpServerUtility.UrlTokenDecode(expression);

        byte[] decodedValue = MachineKey.Unprotect(stream,purpose);
        return Encoding.Unicode.GetString(decodedValue);
    }

}
对于测试:

  • 添加一个链接->@Html.ActionLink(“获取新密钥”、“获取密钥”、新{id=Guid.NewGuid()})
  • 添加控制器方法
  • 添加ViewModel
  • 添加视图
  • {


    摘要:

    如果希望每次都获得相同的结果,则需要使用不同的方法来保护数据。
    MachineKey.protect
    每次运行都使用不同的IV,从而每次产生不同的结果

    细节

    微软使许多dotnet框架的源代码可以在互联网上自由查看

    从顶部开始:

    保护方法使用

    如果您通过
    AspNetCryptoServiceProvider.GetCryptoService
    跟踪代码,您将发现:

    public byte[] Protect(byte[] clearData) {
            // The entire operation is wrapped in a 'checked' block because any overflows should be treated as failures.
            checked {
    
                // These SymmetricAlgorithm instances are single-use; we wrap it in a 'using' block.
                using (SymmetricAlgorithm encryptionAlgorithm = _cryptoAlgorithmFactory.GetEncryptionAlgorithm()) {
                    // Initialize the algorithm with the specified key and an appropriate IV
                    encryptionAlgorithm.Key = _encryptionKey.GetKeyMaterial();
    
                    if (_predictableIV) {
                        // The caller wanted the output to be predictable (e.g. for caching), so we'll create an
                        // appropriate IV directly from the input buffer. The IV length is equal to the block size.
                        encryptionAlgorithm.IV = CryptoUtil.CreatePredictableIV(clearData, encryptionAlgorithm.BlockSize);
                    }
                    else {
                        // If the caller didn't ask for a predictable IV, just let the algorithm itself choose one.
                        encryptionAlgorithm.GenerateIV();
                    }
                    byte[] iv = encryptionAlgorithm.IV;
    
                    using (MemoryStream memStream = new MemoryStream()) {
                        memStream.Write(iv, 0, iv.Length);
    
                        // At this point:
                        // memStream := IV
    
                        // Write the encrypted payload to the memory stream.
                        using (ICryptoTransform encryptor = encryptionAlgorithm.CreateEncryptor()) {
                            using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write)) {
                                cryptoStream.Write(clearData, 0, clearData.Length);
                                cryptoStream.FlushFinalBlock();
    
                                // At this point:
                                // memStream := IV || Enc(Kenc, IV, clearData)
    
                                // These KeyedHashAlgorithm instances are single-use; we wrap it in a 'using' block.
                                using (KeyedHashAlgorithm signingAlgorithm = _cryptoAlgorithmFactory.GetValidationAlgorithm()) {
                                    // Initialize the algorithm with the specified key
                                    signingAlgorithm.Key = _validationKey.GetKeyMaterial();
    
                                    // Compute the signature
                                    byte[] signature = signingAlgorithm.ComputeHash(memStream.GetBuffer(), 0, (int)memStream.Length);
    
                                    // At this point:
                                    // memStream := IV || Enc(Kenc, IV, clearData)
                                    // signature := Sign(Kval, IV || Enc(Kenc, IV, clearData))
    
                                    // Append the signature to the encrypted payload
                                    memStream.Write(signature, 0, signature.Length);
    
                                    // At this point:
                                    // memStream := IV || Enc(Kenc, IV, clearData) || Sign(Kval, IV || Enc(Kenc, IV, clearData))
    
                                    // Algorithm complete
                                    byte[] protectedData = memStream.ToArray();
                                    return protectedData;
                                }
                            }
                        }
                    }
                }
            }
        }
    
    该类是使用默认选项初始化的,因此
    \u predictableIV
    为false

    因此,它每次都使用一个新的IV,这意味着每次结果都会不同,即使输入相同


    IV包含在结果中,因此
    Unprotect
    方法可以反转加密。

    我可以问一下为什么要加密GET-url参数吗?因为GET-url参数是机密id。上面的代码“应该”工作。我有代码和一个网络配置,除了我使用UTF8和一些字符串压缩外,几乎与此完全相同。你确定中间的字符串没有任何变化吗?你的“encodedValue”是否每次使用输入字符串时看起来都不一样?你确定你的machinekey元素在webconfig中的位置正确吗?@JuhaKangas,这段代码可以工作。唯一的问题是加密字符串每次使用输入字符串时看起来都不一样。但是,它仍然被正确解密。它应该是这样工作的吗?顺便问一下,我的
    MachineKey
    元素位于
    web.config
    文件中的
    system.web
    元素中。我更新了我问题中的代码。请不要相信我的话,但我认为这就是加密的工作方式。是的。加密/解密过程中使用的加密数据中填充了一个种子值。您可以可能是在什么地方读到的。我以前有目的地尝试过它。它不起作用。我明天再试一次,让你知道。谢谢!我又累了。正如我所料,它不起作用。
    目的
    参数只是为加密增加了一个安全级别。它对我在问题中解释的行为没有任何影响打开。谢谢!因此,在使用
    MachineKey.Protect()
    时,似乎无法使加密表达式始终保持不变。Microsoft最好为此向方法添加一个布尔参数。
    public byte[] Protect(byte[] clearData) {
            // The entire operation is wrapped in a 'checked' block because any overflows should be treated as failures.
            checked {
    
                // These SymmetricAlgorithm instances are single-use; we wrap it in a 'using' block.
                using (SymmetricAlgorithm encryptionAlgorithm = _cryptoAlgorithmFactory.GetEncryptionAlgorithm()) {
                    // Initialize the algorithm with the specified key and an appropriate IV
                    encryptionAlgorithm.Key = _encryptionKey.GetKeyMaterial();
    
                    if (_predictableIV) {
                        // The caller wanted the output to be predictable (e.g. for caching), so we'll create an
                        // appropriate IV directly from the input buffer. The IV length is equal to the block size.
                        encryptionAlgorithm.IV = CryptoUtil.CreatePredictableIV(clearData, encryptionAlgorithm.BlockSize);
                    }
                    else {
                        // If the caller didn't ask for a predictable IV, just let the algorithm itself choose one.
                        encryptionAlgorithm.GenerateIV();
                    }
                    byte[] iv = encryptionAlgorithm.IV;
    
                    using (MemoryStream memStream = new MemoryStream()) {
                        memStream.Write(iv, 0, iv.Length);
    
                        // At this point:
                        // memStream := IV
    
                        // Write the encrypted payload to the memory stream.
                        using (ICryptoTransform encryptor = encryptionAlgorithm.CreateEncryptor()) {
                            using (CryptoStream cryptoStream = new CryptoStream(memStream, encryptor, CryptoStreamMode.Write)) {
                                cryptoStream.Write(clearData, 0, clearData.Length);
                                cryptoStream.FlushFinalBlock();
    
                                // At this point:
                                // memStream := IV || Enc(Kenc, IV, clearData)
    
                                // These KeyedHashAlgorithm instances are single-use; we wrap it in a 'using' block.
                                using (KeyedHashAlgorithm signingAlgorithm = _cryptoAlgorithmFactory.GetValidationAlgorithm()) {
                                    // Initialize the algorithm with the specified key
                                    signingAlgorithm.Key = _validationKey.GetKeyMaterial();
    
                                    // Compute the signature
                                    byte[] signature = signingAlgorithm.ComputeHash(memStream.GetBuffer(), 0, (int)memStream.Length);
    
                                    // At this point:
                                    // memStream := IV || Enc(Kenc, IV, clearData)
                                    // signature := Sign(Kval, IV || Enc(Kenc, IV, clearData))
    
                                    // Append the signature to the encrypted payload
                                    memStream.Write(signature, 0, signature.Length);
    
                                    // At this point:
                                    // memStream := IV || Enc(Kenc, IV, clearData) || Sign(Kval, IV || Enc(Kenc, IV, clearData))
    
                                    // Algorithm complete
                                    byte[] protectedData = memStream.ToArray();
                                    return protectedData;
                                }
                            }
                        }
                    }
                }
            }
        }