You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 17:33:23