使用Salt / IV创建/解密密码

时间:2015-10-06 14:08:10

标签: c# encryption windows-runtime cryptography windows-store-apps

我被要求在涉及Windows 8加密的项目中执行任务。

场景是这样的:

我从服务器获得byte[],前16个字节是IV,接下来的128个是Salt,其余的是文件本身。

用户然后提供密码,并且我应该创建一个具有40次迭代的PKCS5密钥,密钥应该有32字节长。

现在我已经将我需要的byte[]分开,但我不知道其余的是如何在Windows C#中完成的。

2 个答案:

答案 0 :(得分:3)

我已经完成了一些加密/解密工作,但是让我给你用于AES 256位加密的资源。希望这会让你知道如何将它切换到PKCS5,但我非常确定的其他一切都是一样的。这有点冗长,但如果这适用于您的情况,请告诉我。我很好奇PKCS5而不是AES256有多么不同。

编辑:因为他们发布的代码在迭代中不明确,所以迭代由行var key = Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);使用1000次迭代控制。

http://www.codeproject.com/Articles/769741/Csharp-AES-bits-Encryption-Library-with-Salt

核心加密代码

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

加密

public byte[] AES_Encrypt(byte[] bytesToBeEncrypted, byte[] passwordBytes)
{
    byte[] encryptedBytes = null;

    // Set your salt here, change it to meet your flavor:
    // The salt bytes must be at least 8 bytes.
    byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    using (MemoryStream ms = new MemoryStream())
    {
        using (RijndaelManaged AES = new RijndaelManaged())
        {
            AES.KeySize = 256;
            AES.BlockSize = 128;

            var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);

            AES.Mode = CipherMode.CBC;

            using (var cs = new CryptoStream(ms, AES.CreateEncryptor(), CryptoStreamMode.Write))
            {
                cs.Write(bytesToBeEncrypted, 0, bytesToBeEncrypted.Length);
                cs.Close();
            }
            encryptedBytes = ms.ToArray();
        }
    }

    return encryptedBytes;
}

解密

public byte[] AES_Decrypt(byte[] bytesToBeDecrypted, byte[] passwordBytes)
{
    byte[] decryptedBytes = null;

    // Set your salt here, change it to meet your flavor:
    // The salt bytes must be at least 8 bytes.
    byte[] saltBytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };

    using (MemoryStream ms = new MemoryStream())
    {
        using (RijndaelManaged AES = new RijndaelManaged())
        {
            AES.KeySize = 256;
            AES.BlockSize = 128;

            var key = new Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
            AES.Key = key.GetBytes(AES.KeySize / 8);
            AES.IV = key.GetBytes(AES.BlockSize / 8);

            AES.Mode = CipherMode.CBC;

            using (var cs = new CryptoStream(ms, AES.CreateDecryptor(), CryptoStreamMode.Write))
            {
                cs.Write(bytesToBeDecrypted, 0, bytesToBeDecrypted.Length);
                cs.Close();
            }
            decryptedBytes = ms.ToArray();
        }
    }

    return decryptedBytes;
}

使用Salt获取随机加密结果

如果我们加密相同的上下文(即“Hello World”字符串)10次,加密结果将是相同的。如果我们希望每次加密时结果都不同,该怎么办?

我所做的是在加密前在原始字节前面附加一个随机盐字节,并在解密后将其删除。

在加密字符串之前附加随机盐的示例

public string Encrypt(string text, string pwd)
{
    byte[] originalBytes = Encoding.UTF8.GetBytes(text);
    byte[] encryptedBytes = null;
    byte[] passwordBytes = Encoding.UTF8.GetBytes(pwd);

    // Hash the password with SHA256
    passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

    // Generating salt bytes
    byte[] saltBytes = GetRandomBytes();

    // Appending salt bytes to original bytes
    byte[] bytesToBeEncrypted = new byte[saltBytes.Length + originalBytes.Length];
    for (int i = 0; i < saltBytes.Length; i++)
    {
        bytesToBeEncrypted[i] = saltBytes[i];
    }
    for (int i = 0; i < originalBytes.Length; i++)
    {
        bytesToBeEncrypted[i + saltBytes.Length] = originalBytes[i];
    }

    encryptedBytes = AES_Encrypt(bytesToBeEncrypted, passwordBytes);

    return Convert.ToBase64String(encryptedBytes);
}

解密后去除盐的示例

public string Decrypt(string decryptedText, string pwd)
{
    byte[] bytesToBeDecrypted = Convert.FromBase64String(decryptedText);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(pwd);

    // Hash the password with SHA256
    passwordBytes = SHA256.Create().ComputeHash(passwordBytes);

    byte[] decryptedBytes = AES_Decrypt(bytesToBeDecrypted, passwordBytes);

    // Getting the size of salt
    int _saltSize = 4;

    // Removing salt bytes, retrieving original bytes
    byte[] originalBytes = new byte[decryptedBytes.Length - _saltSize];
    for (int i = _saltSize; i < decryptedBytes.Length; i++)
    {
        originalBytes[i - _saltSize] = decryptedBytes[i];
    }

    return Encoding.UTF8.GetString(originalBytes);
}

获取随机字节的代码

public byte[] GetRandomBytes()
{
    int _saltSize = 4;
    byte[] ba = new byte[_saltSize];
    RNGCryptoServiceProvider.Create().GetBytes(ba);
    return ba;
}

答案 1 :(得分:1)

步骤1:将传入的数据拆分为IV,salt和cyphertext。你说你做到了这一点。

步骤2:使用提供的密码和步骤1中的salt作为PKCS5密钥生成方法的输入,使用40次迭代。您的加密库中应该有一个PKCS5类。此步骤的输出将是一个关键。

步骤3:使用步骤2中的密钥和步骤1中的IV解密来自步骤1的密文。在指定模式下使用指定的解密算法(可能是AES)。由于提供了IV,因此很可能是CBC模式,因此您可能需要使用cypher库中的AES-CBC模式。检查问题规范以确认算法和密码模式 - 我只是在这里猜测。

如果您在执行上述任何步骤时遇到问题,请再次询问此处,显示您的代码并说明您遇到的错误。