我正在尝试对SSN等敏感数据进行加密/解密,加密过程顺利,DB中的保存看起来也很好,检索看起来也很好,但是当我在解密数据的最后一步时,我收到错误message:要解密的数据长度无效。
我创建了一个用于测试的SQL Server表,其中有一列用于保存数据,大小为500的varbinary
类型。
这是表中数据的样子:
现在这里是C#中的完整代码,用于加密数据,插入数据库,获取最后一条记录(测试)和解密。正如我所说,错误发生在解密步骤的最后一步:
加密步骤
public byte[] EncryptStringToBytes(string plainText)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
string keyStr = "cGFzc3dvcmQAAAAAAAAAAA==";
string ivStr = "cGFzc3dvcmQAAAAAAAAAAA==";
byte[] ivArr = Convert.FromBase64String(keyStr);
byte[] keyArr = Convert.FromBase64String(ivStr);
rijAlg.Key = keyArr;
rijAlg.KeySize = 256;
rijAlg.BlockSize = 128;
rijAlg.IV = ivArr;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
SaveData(encrypted);
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
将数据保存到数据库
public void SaveData(byte[] cipherText) {
string queryStmt = "INSERT INTO TestSSN(SSN) VALUES(@Content)";
using (SqlConnection _con = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
using (SqlCommand _cmd = new SqlCommand(queryStmt, _con))
{
SqlParameter param = _cmd.Parameters.Add("@Content", SqlDbType.VarBinary);
param.Value = cipherText;
_con.Open();
_cmd.ExecuteNonQuery();
_con.Close();
}
GetSSNData(1); }
从数据库中获取数据
public byte[] GetSSNData(int id)
{
byte[] cipherData = new byte[500];
string queryStmt = "SELECT SSN FROM TestSSN WHERE ID=7";
using (SqlConnection _con = new SqlConnection(ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString))
using (SqlCommand _cmd = new SqlCommand(queryStmt, _con))
{
_con.Open();
SqlDataReader rdr = _cmd.ExecuteReader();
if (rdr.HasRows)
{
while (rdr.Read())
{
cipherData = Encoding.ASCII.GetBytes(rdr[0].ToString());
}
}
_con.Close();
}
string roundtrip = DecryptStringFromBytes(cipherData);
return cipherData;
}
尝试解密数据(你会在这里注意到两种不同的解密方式,但我会同时收到相同的消息)
static string DecryptStringFromBytes(byte[] cipherText)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (RijndaelManaged rijAlg = new RijndaelManaged())
{
rijAlg.Mode = CipherMode.CBC;
rijAlg.Padding = PaddingMode.PKCS7;
string keyStr = "cGFzc3dvcmQAAAAAAAAAAA==";
string ivStr = "cGFzc3dvcmQAAAAAAAAAAA==";
byte[] ivArr = Convert.FromBase64String(keyStr);
byte[] keyArr = Convert.FromBase64String(ivStr);
rijAlg.Key = keyArr;
rijAlg.KeySize = 256;
rijAlg.BlockSize = 128;
rijAlg.IV = ivArr;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
byte[] decryptedText = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
string decrpyted = ASCIIEncoding.UTF8.GetString(decryptedText);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// byte[] decryptedText = decryptor.TransformFinalBlock(cipherText, 0, cipherText.Length);
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
建议更多,然后欢迎,我一整天都在与解密作斗争。
谢谢,Laziale
答案 0 :(得分:0)
检查从DB读取数据的位置:
cipherData = Encoding.ASCII.GetBytes(rdr[0].ToString());
如果rdr[0]
是byte
数组,我认为你不会得到字节串,可能你会得到“System.Byte []”。如果你得到“0xFFAA” - Encoding.ASCII.GetBytes
将不会给你一个带有{0xFF,0xAA}数据的字节数组。您应该使用SqlDataReader.GetBytes来读取此数据。
另外,我想提醒您SSN是敏感信息。您应该通知您的用户您将保存此信息。如果您需要此信息来验证身份 - 您可以使用最后4位数字或哈希值。如果您没有真正的理由,请考虑不保存SSN。