我需要模仿 MySQL 在使用内置函数 AES_ENCRYPT() 和 AES_DECRYPT() 加密和解密字符串时所做的事情。
我已经阅读了几篇博客文章,显然 MySQL 对这些功能使用了 AES 128 位加密。最重要的是,由于这种加密需要 16 位密钥,MySQL 用 x0 字符 (\0s) 填充字符串,直到它的大小为 16 位。
来自 MySQL 源代码的 C 语言算法在此处发现。
现在我需要复制 MySQL 在 Rails 应用程序中所做的事情,但是我尝试的每一件事都不起作用。
这是一种复制我得到的行为的方法:
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"
我试过填充键:
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() 函数的行为?
谢谢!