求对应Java AES-256-GCM的Ruby加解密实现及错误修复
问题:Java AES-256-GCM加密对应的Ruby加解密实现修正
我有一段使用AES-256-GCM加密消息的Java代码,需要编写对应的Ruby加解密代码。尝试写了Ruby解密代码,但出现(irb):99:in final': OpenSSL::Cipher::CipherError错误,求正确的Ruby加解密实现。
Java加密代码
import java.util.Base64; import javax.crypto.spec.PBEKeySpec; import javax.crypto.SecretKeyFactory; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.security.spec.KeySpec; import java.security.SecureRandom; // ---------------------- String plainMessage = "Hello Java"; String password = "password"; byte[] salt = new byte[16]; new SecureRandom().nextBytes(salt); KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256); SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); SecretKey secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); byte[] iv = new byte[12]; new SecureRandom().nextBytes(iv); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, secretKey, new GCMParameterSpec(128, iv)); byte[] encryptedMessageByte = cipher.doFinal(plainMessage.getBytes(StandardCharsets.UTF_8)); byte[] cipherByte = ByteBuffer.allocate(iv.length + salt.length + encryptedMessageByte.length) .put(iv) .put(salt) .put(encryptedMessageByte) .array(); String encryptedMessageBase64 = Base64.getEncoder().encodeToString(cipherByte);
出错的Ruby解密代码
require 'base64' require 'openssl' cipher_message = "encrypted-message-base64" password = "password" decoded_cipher_byte = Base64.decode64(cipher_message) byte_buffer = StringIO.new(decoded_cipher_byte) iv = byte_buffer.read(12) salt = byte_buffer.read(16) encrypted_byte = byte_buffer.read spec = OpenSSL::KDF.pbkdf2_hmac(password, salt: salt, iterations: 65536, length: 32, hash: 'sha256') secret_key = OpenSSL::Cipher.new('AES').tap { |c| c.key = spec }.random_key cipher = OpenSSL::Cipher.new('AES-GCM') cipher.decrypt cipher.iv = iv cipher.key = secret_key decrypted_message_byte = cipher.update(encrypted_byte) + cipher.final msg = decrypted_message_byte.force_encoding('UTF-8')
错误分析与修正
你的Ruby代码有两个关键错误:
- 密钥生成错误:通过PBKDF2生成的
spec已经是正确的AES密钥,但你用random_key重新生成了随机密钥,覆盖了正确密钥,导致解密时密钥不匹配。 - AES-GCM模式处理:Java中
cipher.doFinal()返回的字节数组包含密文+认证标签,Ruby的OpenSSL::Cipher在GCM模式下会自动从输入中提取认证标签进行验证,无需额外处理。
正确的Ruby解密代码
require 'base64' require 'openssl' require 'stringio' cipher_message = "替换为Java生成的Base64加密串" password = "password" decoded_cipher_byte = Base64.decode64(cipher_message) byte_buffer = StringIO.new(decoded_cipher_byte) iv = byte_buffer.read(12) salt = byte_buffer.read(16) encrypted_byte = byte_buffer.read # 直接使用PBKDF2生成的结果作为AES密钥 secret_key = OpenSSL::KDF.pbkdf2_hmac(password, salt: salt, iterations: 65536, length: 32, hash: 'sha256') cipher = OpenSSL::Cipher.new('AES-256-GCM') cipher.decrypt cipher.iv = iv cipher.key = secret_key # GCM模式下自动验证标签 decrypted_message = cipher.update(encrypted_byte) + cipher.final puts decrypted_message.force_encoding('UTF-8')
对应的Ruby加密代码
如果需要Ruby端生成兼容Java的加密串,可使用以下代码:
require 'base64' require 'openssl' plain_message = "Hello Ruby" password = "password" # 生成16字节salt salt = OpenSSL::Random.random_bytes(16) # 生成12字节IV(GCM推荐长度) iv = OpenSSL::Random.random_bytes(12) # 生成AES密钥 secret_key = OpenSSL::KDF.pbkdf2_hmac(password, salt: salt, iterations: 65536, length: 32, hash: 'sha256') cipher = OpenSSL::Cipher.new('AES-256-GCM') cipher.encrypt cipher.iv = iv cipher.key = secret_key # 加密并获取认证标签 encrypted_data = cipher.update(plain_message) + cipher.final tag = cipher.auth_tag # 按Java格式拼接:IV + Salt + 密文 + 标签 cipher_byte = iv + salt + encrypted_data + tag encrypted_message_base64 = Base64.strict_encode64(cipher_byte) puts encrypted_message_base64
内容的提问来源于stack exchange,提问作者Nalinda Dulwala
相关产品推荐
相关产品推荐

