只能首次解密加密数据

时间:2015-03-24 13:28:28

标签: c# encryption

我有以下代码来加密/解密PII数据。

public static class Encryption
{
    public static readonly int KeyLengthBits = 256; //AES Key Length in bits
    public static readonly int SaltLength = 8; //Salt length in bytes
    private static readonly RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

    private const int PBKDF2IterCount = 1000; // default for Rfc2898DeriveBytes
    private const int PBKDF2SubkeyLength = 256 / 8; // 256 bits
    private const int SaltSize = 128 / 8; // 128 bits

    public static string DecryptString(string ciphertext, string passphrase)
    {
        var inputs = ciphertext.Split(":".ToCharArray(), 3);
        var iv = Convert.FromBase64String(inputs[0]); // Extract the IV
        var salt = Convert.FromBase64String(inputs[1]); // Extract the salt
        var ciphertextBytes = Convert.FromBase64String(inputs[2]); // Extract the ciphertext

        // Derive the key from the supplied passphrase and extracted salt
        byte[] key = DeriveKeyFromPassphrase(passphrase, salt);

        // Decrypt
        byte[] plaintext = DoCryptoOperation(ciphertextBytes, key, iv, false);

        // Return the decrypted string
        return Encoding.UTF8.GetString(plaintext);
    }

    public static string EncryptString(string plaintext, string passphrase)
    {
        var salt = GenerateRandomBytes(SaltLength); // Random salt
        var iv = GenerateRandomBytes(16); // AES is always a 128-bit block size
        var key = DeriveKeyFromPassphrase(passphrase, salt); // Derive the key from the passphrase

        // Encrypt
        var ciphertext = DoCryptoOperation(Encoding.UTF8.GetBytes(plaintext), key, iv, true);

        // Return the formatted string
        return String.Format("{0}:{1}:{2}", Convert.ToBase64String(iv), Convert.ToBase64String(salt), Convert.ToBase64String(ciphertext));
    }

    private static byte[] DeriveKeyFromPassphrase(string passphrase, byte[] salt, int iterationCount = 2000)
    {
        var keyDerivationFunction = new Rfc2898DeriveBytes(passphrase, salt, iterationCount);  //PBKDF2

        return keyDerivationFunction.GetBytes(KeyLengthBits / 8);
    }

    private static byte[] GenerateRandomBytes(int lengthBytes)
    {
        var bytes = new byte[lengthBytes];
        rng.GetBytes(bytes);

        return bytes;
    }

    // This function does both encryption and decryption, depending on the value of the "encrypt" parameter
    private static byte[] DoCryptoOperation(byte[] inputData, byte[] key, byte[] iv, bool encrypt)
    {
        byte[] output;

        using (var aes = new AesCryptoServiceProvider())
        using (var ms = new MemoryStream())
        {
            var cryptoTransform = encrypt ? aes.CreateEncryptor(key, iv) : aes.CreateDecryptor(key, iv);

            using (var cs = new CryptoStream(ms, cryptoTransform, CryptoStreamMode.Write))
                cs.Write(inputData, 0, inputData.Length);

            output = ms.ToArray();
        }

        return output;
    }
}

如果我发布此代码并加密数据然后对其进行解密,则没有问题。我正确地收到了未加密的数据。如果我重新构建我的应用程序而不进行任何更改,那么再次发布它而不重新加密数据(此时它已经加密),我无法解密它。它只返回加密的字符串。

为什么要重新发布到同一台服务器?我应该使用不同的方法吗?如果是这样,请建议采用不同的方法。

由于

0 个答案:

没有答案