在 T-SQL 上解密 AES 128

发布于 2024-11-03 14:45:02 字数 280 浏览 0 评论 0原文

我有一个当前使用 AES 128 的数据库。该数据库大约有 800 万条记录,客户想要的是解码密码并对其进行哈希处理,这样密码就无法被解密。这是一个网络应用程序,数据存储在远程服务器上。我尝试使用网络应用程序进行转换,但它总是超时。由于这是 800 万条,需要一段时间才能浏览完所有项目,因此我的下一个想法是让 SQL 进行解密和哈希处理。我可以让它运行接下来的几天。

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

谢谢!

I have a database that is currently using AES 128. The database has about 8 million records, and what the client wants is to decode the passwords and hash them instead so the passwords cannot be decrypted. This is a web app with data stored on a remote server. I tried using a web app to do the conversion, but it keeps timing out. Since this is 8 mil, it will take a while to go through all the items, so my next idea was to get SQL do do the decryption and hashing. I could let it run for the next few days.

The problem I am having is that each column has the encrypted password with a unique salt. I can't find a function to decrypt the password using the encrypted password and salt. Is there a function? Even third party? Is there a better way to go about this?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

红尘作伴 2024-11-10 14:45:02

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

The easiest/only way to do this in SQL Server would by to write a CLR User-Defined Function (UDF) in C#. See

for more details. If it was me, I'd add a new column to contain the new password hash and run an update statement periodically to construct the new password hash, something like this:

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

where DecryptAndHash() is your CLR UDF. Once the transform is complete, you should be free to drop the old column and roll out the update to use the new authentication logic.

Probably want to put an trigger on the table to keep the hash in sync with the encrypted password in case anybody changes their password while all this is going on.

FWIW, the code shouldn't be much more complicated than

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();
            }

        }

    }
}

Implementation of the internals of EncryptionEngine is left as an exercise for the reader.

说谎友 2024-11-10 14:45:02

您可以查看应用程序的身份验证,并从源代码中了解它如何对密码进行身份验证。您应该看到应用程序正在加密密码并将其与数据库中的加密值进行比较。那里的加密功能应该很容易被逆向。盐通常不与加密一起使用,它在生成哈希时使用以防止查找攻击。

我不认为 SQL 可以对 AES128 进行解密,无论如何都不能以直接的方式进行。但是您可以使用标准 API 编写一个简单的 .NET 应用程序,该应用程序将解密每个密码,使用盐对其进行哈希处理,然后将其写回数据库。

You can take a look at the authentication of your application, and see from the source code how it authenticates the password. There you should see that the app is encrypting the password and comparing it with the encrypted value in the database. The encryption function there should be easy to reverse. A salt is not usually used along with encryption, it is used when generating a hash to protected against lookup attacks.

I don't think SQL can do decryption on AES128, not in a straightforward manner anyway. But you can write a simple .NET app using the standard APIs that will decrypt each password, hash it with the salt and write it back to the database.

昵称有卵用 2024-11-10 14:45:02

存储加密密码的要点是它们无法被解密。事实上,加密是使用密码作为密钥对某些常量(+盐)进行的。

所以基本上目标已经达到了,你无法解密“密码”以获取其明文版本。

The point with storing encrypted passwords is that they cannot be decrypted. The encryption is in fact made on some constant (+salt) using the password as the key.

So basically the goal has already been met, you cannot decrypt the "passwords" to get their clear text versions.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文