在T-SQL上解密AES 128

本文关键字:AES 解密 T-SQL | 更新日期: 2023-09-27 17:53:51

我有一个数据库,目前使用AES 128。该数据库有大约800万条记录,客户端想要的是解码密码并对其进行散列,这样密码就无法被解密。这是一个数据存储在远程服务器上的web应用程序。我试着用一个网络应用程序来进行转换,但它总是超时。由于这是8 mil,因此遍历所有项需要一段时间,因此我的下一个想法是让SQL执行解密和散列。我可以让它再运行几天。

我遇到的问题是,每一列都有一个唯一的盐的加密密码。我找不到使用加密密码和盐解密密码的函数。有函数吗?甚至是第三方?有更好的办法吗?

谢谢!

在T-SQL上解密AES 128

在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)上进行的,使用密码作为密钥。

所以基本上目标已经实现了,你不能解密"密码"来获得它们的明文版本。