使用Salt/IV创建/解密密码
本文关键字:解密 密码 创建 IV Salt 使用 | 更新日期: 2023-09-27 18:16:38
我被要求在一个涉及windows 8加密的项目中完成一项任务。
场景是这样的:
我从服务器得到一个byte[]
,前16个字节是IV
,接下来的128个字节是Salt
,剩下的是文件本身。
用户然后提供一个密码和盐,我应该创建一个PKCS5密钥,迭代40次,密钥长度应该是32字节。
现在我已经分裂了byte[]
在我需要的3,但我不知道其余的是如何在windows c#中完成的。
我已经做了一些加密/解密的工作,但是让我给你我用于AES 256位加密的资源。希望这将使您了解如何将其切换到PKCS5,但我很确定其他一切都是相同的。这有点长,但如果这适用于你的情况,请告诉我。我很好奇PKCS5和AES256会有多大的不同。
编辑:因为他们发布的代码对迭代不清楚,迭代由var key = Rfc2898DeriveBytes(passwordBytes, saltBytes, 1000);
行控制,使用1000次迭代。
核心加密码
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);
}
解密后移除Salt示例
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:将传入数据拆分为IV、salt和密文。你说你做了这件事。
步骤2:通过40次迭代,将步骤1中提供的密码和盐作为输入传递给PKCS5密钥生成方法。您的加密库中应该有PKCS5类。此步骤的输出将是一个密钥。
步骤3:使用步骤2中的密钥和步骤1中的IV来解密步骤1中的密文。在指定的模式下使用指定的解密算法,可能是AES。由于提供了IV,因此很可能打算使用CBC模式,因此您可能需要使用密码库中的AES-CBC模式。检查问题说明以确认算法和密码模式——这里我只是猜测。
如果您对这些步骤中的任何一个有问题,请再次询问,显示您的代码并解释您得到的错误。