我为每个用户生成随机HMAC密钥并将密钥存储在我们的数据库中。如果用户请求密钥,用户只能获得密钥,并且通常只是使用我们的API令牌(SWT)作为BASE64编码的不透明密钥,而不必担心它们的完整性。为什么我不能加密/解密数据库存储的HMAC密钥?
我想在将密钥存储到我们的SQL Server数据库之前对其进行加密,以防止密钥泄露。它们的加密密钥存储在varbinary(MAX)列中。没有加密,一切都很好。
我使用AES进行加密,随机生成的IV存储在加密值的开头。
在我的单元测试中,使用简单的字符串,一切都很好,但是,对于HMAC密钥,解密值永远不会与原始值匹配。如果我生成一个HMAC密钥,加密它,将它存储在数据库中。当我检索它时,解密它,并使用它们键来生成一个HMAC散列,它与原始HMAC散列值不匹配。
请参阅下面的加密/解密方法。
public static byte[] Encrypt(byte[] value)
{
using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(_password, Encoding.ASCII.GetBytes(_salt));
aes.Key = key.GetBytes(aes.KeySize/8);
aes.GenerateIV();
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
using (var crypt = aes.CreateEncryptor(aes.Key, aes.IV))
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, crypt, CryptoStreamMode.Write))
{
cs.Write(aes.IV, 0, aes.IV.Length);
using (BinaryWriter bw = new BinaryWriter(cs))
{
bw.Write(value);
cs.FlushFinalBlock();
}
return ms.ToArray();
}
}
}
}
public static byte[] Decrypt(byte[] value)
{
using (AesCryptoServiceProvider aes = new AesCryptoServiceProvider())
{
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(_password, Encoding.ASCII.GetBytes(_salt));
aes.Key = key.GetBytes(aes.KeySize/8);
aes.Padding = PaddingMode.PKCS7;
aes.Mode = CipherMode.CBC;
using (MemoryStream ms = new MemoryStream(value))
{
byte[] iv = new byte[aes.IV.Length];
ms.Read(iv, 0, aes.IV.Length);
aes.IV = iv;
using (var crypt = aes.CreateDecryptor(aes.Key, aes.IV))
using (CryptoStream cs = new CryptoStream(ms, crypt, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
return Encoding.ASCII.GetBytes(sr.ReadToEnd());
}
}
}
}
密码和salt存储在编译为代码的常量字符串文字中。我意识到这并不理想,但现在是这样。
你已经给出了一些代码,但没有说它不工作的方式... –
如果我生成一个HMAC密钥,加密它,将它存储在数据库中。当我检索它时,解密它,并使用它们键来生成一个HMAC散列,它与原始HMAC散列值不匹配。 –
那么你是如何诊断问题的呢?你记录了每个阶段涉及的字节吗? (在加密之前,在保存到数据库之前进行加密之后,从数据库中获取之后但在解密之前,在解密之后......)基本上,您需要确切地确定造成问题的阶段。 –