gpt4 book ai didi

ruby - 模仿 Ruby 中的 AES_ENCRYPT 和 AES_DECRYPT 函数

转载 作者:数据小太阳 更新时间:2023-10-29 08:29:34 24 4
gpt4 key购买 nike

我需要模仿 MySQL 在使用内置函数 AES_ENCRYPT() 和 AES_DECRYPT() 加密和解密字符串时所做的事情。

我已经阅读了几篇博客文章,显然 MySQL 对这些函数使用 AES 128 位加密。最重要的是,由于此加密需要 16 位 key ,MySQL 会用 x0 个字符 (\0s) 填充字符串,直到它的大小为 16 位。

MySQL 源代码中的 C 算法被发现 here .

现在我需要在 Rails 应用程序中复制 MySQL 的功能,但我尝试过的每一件事都不起作用。

这是一种复制我得到的行为的方法:

1) 创建一个新的 Rails 应用

rails encryption-test
cd encryption-test

2) 创建一个新的脚手架

script/generate scaffold user name:string password:binary

3) 编辑你的 config/database.yml 并添加一个测试 MySQL 数据库

development:
adapter: mysql
host: localhost
database: test
user: <<user>>
password: <<password>>

4) 运行迁移

rake db:migrate

5) 进入控制台,创建用户并从MySQL查询更新其密码

script/console
Loading development environment (Rails 2.2.2)
>> User.create(:name => "John Doe")
>> key = "82pjd12398JKBSDIGUSisahdoahOUASDHsdapdjqwjeASIduAsdh078asdASD087asdADSsdjhA7809asdajhADSs"
>> ActiveRecord::Base.connection.execute("UPDATE users SET password = AES_ENCRYPT('password', '#{key}') WHERE name='John Doe'")

这就是我被卡住的地方。如果我尝试解密它,使用 MySQL 就可以了:

>> loaded_user = User.find_by_sql("SELECT AES_DECRYPT(password, '#{key}') AS password FROM users WHERE id=1").first
>> loaded_user['password']
=> "password"

但是,如果我尝试使用 OpenSSL 库,我无法让它工作:

cipher = OpenSSL::Cipher::Cipher.new("AES-128-ECB") 
cipher.padding = 0
cipher.key = key
cipher.decrypt

user = User.find(1)
cipher.update(user.password) << cipher.final #=> "########gf####\027\227"

我试过填充 key :

desired_length = 16 * ((key.length / 16) + 1)
padded_key = key + "\0" * (desired_length - key.length)

cipher = OpenSSL::Cipher::Cipher.new("AES-128-ECB")
cipher.key = key
cipher.decrypt

user = User.find(1)
cipher.update(user.password) << cipher.final #=> ""|\e\261\205:\032s\273\242\030\261\272P##"

但是真的不行。

有人知道如何在 Ruby 中模仿 MySQL AES_ENCRYPT() 和 AES_DECRYPT() 函数的行为吗?

谢谢!

最佳答案

供将来引用:

根据我之前发的博文,下面是MySQL的工作原理您提供的 key AES_ENCRYPT/DECRYPT:

"The algorithm just creates a 16 byte buffer set to all zero, then loops through all the characters of the string you provide and does an assignment with bitwise OR between the two values. If we iterate until we hit the end of the 16 byte buffer, we just start over from the beginning doing ^=. For strings shorter than 16 characters, we stop at the end of the string."

我不知道你是否可以阅读 C,但这是提到的片段:

http://pastie.org/425161

特别是这部分:

bzero((char*) rkey,AES_KEY_LENGTH/8);      /* Set initial key  */

for (ptr= rkey, sptr= key; sptr < key_end; ptr++,sptr++)
{
if (ptr == rkey_end)
ptr= rkey; /* Just loop over tmp_key until we used all key */
*ptr^= (uint8) *sptr;
}

所以我想到了这个方法(在来自 ruby​​ 论坛的 Rob Biedenharn 的帮助下):

def mysql_key(key)
final_key = "\0" * 16
key.length.times do |i|
final_key[i%16] ^= key[i]
end
final_key
end

也就是说,给定一个字符串,返回 MySQL 在加密和解密时使用的 key 。所以你现在需要的是:

def aes(m,k,t)
(aes = OpenSSL::Cipher::AES128.new("ECB").send(m)).key = k
aes.update(t) << aes.final
end

def encrypt(key, text)
aes(:encrypt, key, text)
end

def decrypt(key, text)
aes(:decrypt, key, text)
end

要使用 openssl lib,内置在 ruby​​ 中,然后你可以制作两个“最终”方法:

def mysql_encrypt(s, key)
encrypt(mysql_key(key), s)
end

def mysql_decrypt(s, key)
decrypt(mysql_key(key), s)
end

你已经准备好了!此外,完整的代码可以在此 Gist 中找到:

http://gist.github.com/84093

:-)

关于ruby - 模仿 Ruby 中的 AES_ENCRYPT 和 AES_DECRYPT 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/675380/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com