在T-SQL上解密AES 128

时间:2011-04-28 16:57:20

标签: c# .net sql-server tsql encryption

我有一个当前使用AES 128的数据库。该数据库有大约800万条记录,客户想要的是解密密码并对它们进行哈希处理,以便密码无法解密。这是一个Web应用程序,其数据存储在远程服务器上。我尝试使用网络应用程序进行转换,但它会保持超时。由于这是8密耳,所以需要一段时间来完成所有项目,所以我的下一个想法是让SQL做解密和散列。我可以让它在接下来的几天内运行。

我遇到的问题是每列都有加密密码和唯一的盐。我找不到使用加密密码和salt解密密码的功能。有功能吗?甚至是第三方?有没有更好的方法来解决这个问题?

谢谢!

3 个答案:

答案 0 :(得分:3)

在SQL Server中执行此操作的最简单/唯一方法是在C#中编写CLR用户定义函数(UDF)。参见

了解更多详情。如果是我,我会添加一个新列来包含新密码哈希并定期运行更新语句来构造新的密码哈希,如下所示:

update top 10000 dbo.users
set hashedPassword = DecryptAndHash( encryptedPassword )
where hashedPassword is null

其中DecryptAndHash()是您的CLR UDF。转换完成后,您应该可以放弃旧列并推出更新以使用新的身份验证逻辑。

可能希望在表上设置触发器以使哈希与加密密码保持同步,以防任何人在完成所有这些操作时更改密码。

FWIW,代码不应该比

复杂得多
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内部的实现留给读者练习。

答案 1 :(得分:2)

您可以查看应用程序的身份验证,并从源代码中查看它如何验证密码。在那里你应该看到应用程序正在加密密码并将其与数据库中的加密值进行比较。那里的加密功能应该易于反转。 salt通常不与加密一起使用,它在生成散列以防止查找攻击时使用。

我认为SQL无法在AES128上进行解密,无论如何都不能直接进行解密。但是你可以使用标准API编写一个简单的.NET应用程序,它将解密每个密码,用盐哈希并将其写回数据库。

答案 2 :(得分:-1)

存储加密密码的关键是他们无法解密。加密实际上是使用密码作为密钥在某些常量(+ salt)上进行的。

所以基本上已经达到目标,你不能解密“密码”来获得他们的明文版本。