在T-SQL上解密AES 128
本文关键字:AES 解密 T-SQL | 更新日期: 2023-09-27 17:53:51
我有一个数据库,目前使用AES 128。该数据库有大约800万条记录,客户端想要的是解码密码并对其进行散列,这样密码就无法被解密。这是一个数据存储在远程服务器上的web应用程序。我试着用一个网络应用程序来进行转换,但它总是超时。由于这是8 mil,因此遍历所有项需要一段时间,因此我的下一个想法是让SQL执行解密和散列。我可以让它再运行几天。
我遇到的问题是,每一列都有一个唯一的盐的加密密码。我找不到使用加密密码和盐解密密码的函数。有函数吗?甚至是第三方?有更好的办法吗?
谢谢!
在SQL Server中做到这一点最简单/唯一的方法是用c#编写CLR用户定义函数(UDF)。看到
- SQL Server 2005:创建你的第一个c# CLR UDF在10个简单的步骤(其中之一包括聚会)
- SQLCLR -创建CLR用户定义函数(UDF) -使用RegEx检查EmailAddress列约束
- MSDN: CLR用户定义函数(ADO.NET)
查看更多详细信息。如果是我,我会添加一个新列来包含新密码哈希,并定期运行更新语句来构造新密码哈希,如下所示:
update top 10000 dbo.users
set hashedPassword = DecryptAndHash( encryptedPassword )
where hashedPassword is null
,其中DecryptAndHash()
是CLR UDF。转换完成后,您应该可以自由地删除旧列并推出更新以使用新的身份验证逻辑。
可能想在表上放一个触发器,以保持哈希值与加密密码同步,以防有人在这一切进行时更改密码。
一般情况下,代码不应该比
复杂得多using System;
using Microsoft.SqlServer.Server;
namespace Sandbox
{
public static class EncryptionFunctions
{
/// <summary>
/// Encrypts a string
/// </summary>
/// <param name="plainText"></param>
/// <returns>varbinary</returns>
[SqlFunction]
public static byte[] Encrypt( string plainText )
{
byte[] cipherText ;
using ( EncryptionEngine cipher = EncryptionEngine.GetInstance() )
{
cipherText = cipher.Encrypt( plainText ) ;
}
return cipherText ;
}
/// <summary>
/// Decrypts a previously encrypted varbinary
/// </summary>
/// <param name="cipherText"></param>
/// <returns>string</returns>
[SqlFunction]
public static string Decrypt( byte[] cipherText )
{
string plainText ;
using ( EncryptionEngine cipher = EncryptionEngine.GetInstance() )
{
plainText = cipher.Decrypt( cipherText ) ;
}
return plainText ;
}
/// <summary>
/// Compute the secure hash of a [plaintext] string
/// </summary>
/// <param name="plainText"></param>
/// <returns> varbinary </returns>
[SqlFunction]
public static byte[] SecureHash( string plainText )
{
byte[] hash ;
using ( EncryptionEngine cipher = EncryptionEngine.GetInstance() )
{
hash = cipher.ComputeSecureHash( plainText ) ;
}
return hash ;
}
/// <summary>
/// Convenience wrapper method to take a previously encrypted string, decrypt it and compute its secure hash
/// </summary>
/// <param name="cipherText"></param>
/// <returns>varbinary</returns>
[SqlFunction]
public static byte[] DecryptAndHash( byte[] cipherText )
{
byte[] hash ;
using ( EncryptionEngine cipher = EncryptionEngine.GetInstance() )
{
hash = cipher.ComputeSecureHash( cipher.Decrypt( cipherText ) ) ;
}
return hash ;
}
/// <summary>
/// The core encrypt/decrypt/hash engine
/// </summary>
private class EncryptionEngine : IDisposable
{
/// <summary>
/// get an instance of this class
/// </summary>
/// <returns></returns>
public static EncryptionEngine GetInstance()
{
return new EncryptionEngine() ;
}
#region IDisposable Members
/// <summary>
/// Dispose of any unmanaged resources
/// </summary>
public void Dispose()
{
throw new NotImplementedException();
}
#endregion
/// <summary>
/// Encrypt a plaintext string
/// </summary>
/// <param name="plainText"></param>
/// <returns></returns>
internal byte[] Encrypt( string plainText )
{
throw new NotImplementedException();
}
/// <summary>
/// Decrypt an encrypted string
/// </summary>
/// <param name="cipherText"></param>
/// <returns></returns>
internal string Decrypt( byte[] cipherText )
{
throw new NotImplementedException();
}
/// <summary>
/// Compute the secure hash of a string
/// </summary>
/// <param name="plainText"></param>
/// <returns></returns>
internal byte[] ComputeSecureHash( string plainText )
{
throw new NotImplementedException();
}
}
}
}
EncryptionEngine
的内部实现留给读者作为练习。
您可以查看一下应用程序的身份验证,并从源代码中查看它是如何对密码进行身份验证的。在这里,您应该看到应用程序正在加密密码,并将其与数据库中的加密值进行比较。那里的加密功能应该很容易逆转。盐通常不与加密一起使用,它在生成哈希以防止查找攻击时使用。
我不认为SQL可以在AES128上做解密,而不是以直接的方式。但是,您可以使用标准api编写一个简单的。net应用程序,该应用程序将解密每个密码,用盐对其进行散列并将其写回数据库。
存储加密密码的关键是它们不能被解密。加密实际上是在某个常数(+salt)上进行的,使用密码作为密钥。
所以基本上目标已经实现了,你不能解密"密码"来获得它们的明文版本。