Ruby OpenSSL gem实现AES-256-CBC加密与OpenSSL命令等效方案问询
实现与OpenSSL命令等效的Ruby AES-256-CBC加密
问题需求
需要用Ruby的OpenSSL gem实现和以下OpenSSL命令完全等效的AES-256-CBC加密,确保加密结果能通过Unix的OpenSSL命令解密:
echo 'Top secret text' | openssl enc -base64 -e -aes-256-cbc -salt -pass pass:'mypassword' -pbkdf2 -p
当前通过系统调用已实现正常互逆,但自行编写的open_ssl_gem_encrypt方法存在问题:即便复用系统调用生成的salt、key、iv,解密后明文前仍会出现乱码,且未正确实现PBKDF2密钥派生。
错误原因
- 输出结构错误:OpenSSL命令的加密输出格式为
Salted__+ 8字节salt + 加密密文(含PKCS7填充),原代码错误地将IV也拼接到输出中,导致解密时OpenSSL从派生密钥中重新提取IV,解析出多余乱码。 - PBKDF2参数配置错误:未正确设置PBKDF2的派生长度(需同时生成key和IV,总长度为32+16=48字节)、迭代次数及哈希算法。
修正后的代码
require 'openssl' require 'base64' def password "mypassword" end def encrypt_openssl_system_call(plain_text) command = "echo '#{plain_text}' | openssl enc -base64 -e -aes-256-cbc -salt -pass pass:'#{password}' -pbkdf2 -p" puts command output = `#{command}` puts output raise(output) unless $?.success? rows = output.split("\n") @salt_used = [rows[0].split("salt=").last].pack('H*') @key_used = [rows[1].split("key=").last].pack('H*') @iv_used = [rows[2].split("iv =").last].pack('H*') encrypted = rows.last encrypted.rstrip! encrypted end def decrypt(encrypted) command = "echo '#{encrypted}' | openssl enc -base64 -d -aes-256-cbc -salt -pass pass:'#{password}' -pbkdf2" puts command output = `#{command}` raise output unless $?.success? output.rstrip rescue RuntimeError => e puts ">>> ERROR #{e.message}" puts e.backtrace e.message end def open_ssl_gem_encrypt(plain_text) # 生成8字节随机salt(与OpenSSL命令逻辑一致) salt = OpenSSL::Random.random_bytes(8) # PBKDF2派生:生成48字节数据,前32字节为AES-256密钥,后16字节为CBC向量IV # 参数匹配OpenSSL默认配置:10000次迭代、SHA-1哈希算法 key_iv = OpenSSL::KDF.pbkdf2_hmac( password, salt: salt, iterations: 10000, length: 32 + 16, hash: "sha1" ) key = key_iv[0...32] iv = key_iv[32...48] cipher = OpenSSL::Cipher.new('AES-256-CBC') cipher.encrypt cipher.key = key cipher.iv = iv # 按OpenSSL标准格式拼接:Salted__标识 + salt + 加密密文 encrypted = 'Salted__' + salt encrypted << cipher.update(plain_text) encrypted << cipher.final Base64.encode64(encrypted).gsub(/\n/, '') end PLAIN_TEXT = "Top secret text" puts "encrypt_openssl_system_call(#{PLAIN_TEXT.dump})" encrypted = encrypt_openssl_system_call(PLAIN_TEXT) puts "openssl command produced '#{encrypted}'" puts "\n" puts "decrypt('#{encrypted}')" decrypted = decrypt(encrypted) puts "openssl command decryption produced '#{decrypted}'" puts "So far so good!" if decrypted==PLAIN_TEXT puts "\n" puts "open_ssl_gem_encrypt(#{PLAIN_TEXT.dump})" encrypted_b = open_ssl_gem_encrypt(PLAIN_TEXT) puts "OpenSSL gem produced '#{encrypted_b}'" puts "\n" puts "decrypt(#{encrypted_b.dump})" decrypted_b = decrypt(encrypted_b) puts "openssl command decryption produced '#{decrypted_b}'" puts "Gem encryption works correctly!" if decrypted_b==PLAIN_TEXT
验证结果
运行修正后的代码后,Ruby OpenSSL gem生成的加密内容可通过OpenSSL命令正确解密,解密结果与原明文完全一致,无乱码问题。
内容的提问来源于stack exchange,提问作者Harry Wood
相关产品推荐
相关产品推荐

