我为每个用户生成随机HMAC密钥,并将密钥存储在我们的数据库中。用户只有在获得密钥时才会获取密钥,并且通常只使用我们的API令牌(SWT)作为BASE64编码的不透明密钥,并且不用担心它们的完整性。
我希望在将密钥存储到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存储在编译成代码的const字符串文字中。我意识到这不是理想的,但现在就是这样。
答案 0 :(得分:0)
我认为这个问题有两个问题。第一个,正如Jon Skeet所讨论的那样,IV被加密,因此用于解密该值时不同。我通过直接写入MemoryStream而不是CryptoStream来纠正以下代码。
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))
using (BinaryWriter bw = new BinaryWriter(cs))
{
ms.Write(aes.IV, 0, aes.IV.Length);
bw.Write(value);
cs.FlushFinalBlock();
return ms.ToArray();
}
}
}
下一部分我并不完全确定,但我确实认为Jon对于读取字符串并返回字节数组存在一些问题也是正确的。我通过使用类似于他在此处找到的代码更正了这一点:jonskeet.uk/csharp/readbinary.html将流直接读入字节数组。请参阅以下代码,其中ReadStream()是我基于Jon编写的方法。
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))
return ReadStream(cs, 0, ms.Length);
}
}
}
感谢Jon的帮助。我也感谢你,不仅仅是放弃它。如果我要学习一些东西,我不介意为它工作。这是我得到的报酬。
答案 1 :(得分:-1)
简单和定制的东西怎么样?
using System.Security.Cryptography;
using System.Text;
namespace GrimoireTactics.Framework.Security
{
public enum ObfuscatorType
{
Encrypt,
Decrypt
}
public class Obfuscator
{
private string _seed;
private byte[] _hashedSeedBytes;
private readonly SHA256Managed _hashingAlgorithm;
public string Seed
{
get
{
return _seed;
}
set
{
this._seed = value;
SeedHash = GenerateHash(value);
this._hashedSeedBytes = GetBytes(SeedHash);
}
}
public byte[] SeedBytes
{
get
{
return _hashedSeedBytes;
}
}
public string SeedHash { get; private set; }
public Obfuscator(string seed)
{
this._hashingAlgorithm = new SHA256Managed();
this.Seed = seed;
}
public byte[] Encrypt(byte[] data)
{
return Transform(data, ObfuscatorType.Encrypt);
}
public byte[] Encrypt(string data)
{
return Transform(GetBytes(data), ObfuscatorType.Encrypt);
}
public byte[] Decrypt(byte[] data)
{
return Transform(data, ObfuscatorType.Decrypt);
}
public byte[] Transform(byte[] bytes, ObfuscatorType type)
{
int passwordShiftIndex = 0;
byte[] data = bytes;
byte offset = 0;
switch (type)
{
case ObfuscatorType.Encrypt:
for (int i = 0; i < data.Length; i++)
{
byte currentByte = _hashedSeedBytes[passwordShiftIndex];
offset += (byte)(1 + currentByte); // Incrementing Offset
data[i] = (byte)(data[i] + currentByte + offset);
passwordShiftIndex = (passwordShiftIndex + 1) % _hashedSeedBytes.Length;
}
break;
case ObfuscatorType.Decrypt:
for (int i = 0; i < data.Length; i++)
{
byte currentByte = _hashedSeedBytes[passwordShiftIndex];
offset += (byte)(1 + currentByte); // Incrementing Offset
data[i] = (byte)(data[i] - currentByte - offset);
passwordShiftIndex = (passwordShiftIndex + 1) % _hashedSeedBytes.Length;
}
break;
}
return data;
}
public byte[] GetBytes(string data)
{
return Encoding.UTF8.GetBytes(data);
}
public byte[] GetBytes(string data, Encoding encoding)
{
return encoding.GetBytes(data);
}
public string GetString(byte[] data)
{
return Encoding.UTF8.GetString(data);
}
public string GetString(byte[] data, Encoding encoding)
{
return encoding.GetString(data);
}
public string GenerateHash(string text)
{
byte[] bytes = Encoding.UTF8.GetBytes(text);
byte[] hash = _hashingAlgorithm.ComputeHash(bytes);
string hashString = string.Empty;
for (int index = 0; index < hash.Length; index++)
{
byte x = hash[index];
hashString += $"{x:x2}";
}
return hashString;
}
}
}
用法示例:
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using GrimoireDevelopmentKit.DevelopmentKit.UserInterface;
using GrimoireTactics.Framework.OpenGL.Modeling;
using GrimoireTactics.Framework.OpenGL.Texturing;
using GrimoireTactics.Framework.Security;
namespace GrimoireDevelopmentKit.DevelopmentKit
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
//Application.EnableVisualStyles();
//Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new DevelopmentKitEditor());
Obfuscator obs = new Obfuscator("My Arbitary Seed");
byte[] obufsicatedData = obs.Encrypt("Some Top Secret Data");
byte[] unobufsicatedData = obs.Decrypt(obufsicatedData);
Console.WriteLine(obs.GetString(unobufsicatedData));
Console.Read();
}
}
}
我们所做的就是使用自定义算法对字节进行模糊处理。代码可供任何人免费使用;我只是将它作为一种额外的安全措施。