Logstash管道中AES加密Ruby代码故障排查求助
Logstash Ruby AES-GCM加密代码修复
我有一段实现AES加密的Java代码,逻辑是用PBKDF2生成密钥,AES-GCM模式加密,最后把IV、Salt和加密数据(含GCM标签)拼接后Base64编码:
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256"); KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(), 65536, 256); SecretKey secret = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES"); if (data == null) return encryptedText; Cipher encryptCipher = Cipher.getInstance("AES/GCM/NoPadding"); // get IV byte[] iv = getRandomNonce(12); encryptCipher.init(Cipher.ENCRYPT_MODE, secret, new GCMParameterSpec(128, iv)); // encrypted data: byte[] encryptedBytes = encryptCipher.doFinal(data.getBytes("UTF-8")); // prefix IV and Salt to cipher text byte[] cipherTextWithIvSalt = ByteBuffer.allocate(iv.length + salt.length() + encryptedBytes.length).put(iv) .put(salt.getBytes()).put(encryptedBytes).array(); encryptedText = Base64.getEncoder().encodeToString(cipherTextWithIvSalt);
现在我在Logstash管道里用Ruby代码尝试实现相同逻辑,但无法正常工作,代码如下:
ruby { code => " require 'openssl' require 'base64' password = 'secret_key' salt = 'random_salt' iterations = 65536 key_len = OpenSSL::Cipher.new('aes-256-gcm').key_len key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_len, 'sha256') cipher = OpenSSL::Cipher.new('aes-256-gcm') cipher.encrypt cipher.key = key iv = Random.new.bytes(12) encrypted = cipher.update(event.get('secret')) + cipher.final length=iv.length+salt.length+encrypted.length // buffer =IO::Buffer.new(10)// not working encrypted_text = Base64.encode64(buffer).strip event.set('message_encrypted', encrypted_text) " add_field => { "new_secret" => "%{[message_encrypted]}" } }
代码问题分析
你的Ruby代码存在以下关键问题:
- 未定义
buffer变量:直接使用未初始化的buffer导致报错,且未正确拼接IV、Salt和加密数据 - 遗漏GCM认证标签:AES-GCM模式下,Ruby的OpenSSL实现不会自动把认证标签附加到加密数据后,需要手动获取
cipher.tag并拼接 - 语法错误:Ruby注释使用
#而非//,原始代码中的// buffer =IO::Buffer.new(10)是无效语法 - 编码不一致:未指定明文转字节的编码,可能和Java的UTF-8编码产生差异
- 未设置IV到加密器:生成IV后没有绑定到
cipher实例,加密逻辑不完整
修复后的Ruby代码
ruby { code => " require 'openssl' require 'base64' password = 'secret_key' salt = 'random_salt' iterations = 65536 cipher = OpenSSL::Cipher.new('aes-256-gcm') cipher.encrypt key_len = cipher.key_len key = OpenSSL::PKCS5.pbkdf2_hmac(password, salt, iterations, key_len, 'sha256') cipher.key = key iv = Random.new.bytes(12) cipher.iv = iv # 将IV绑定到加密器实例 # 处理空值,对应Java的data==null逻辑 plaintext = event.get('secret') return unless plaintext # 统一使用UTF-8编码转字节,和Java保持一致 encrypted_data = cipher.update(plaintext.encode('UTF-8')) + cipher.final gcm_tag = cipher.tag # 获取GCM认证标签 # 拼接IV、Salt字节、加密数据、GCM标签 cipher_text_with_iv_salt = iv + salt.bytes.pack('C*') + encrypted_data + gcm_tag # 使用strict_encode64避免添加换行符,和Java的Base64.getEncoder()输出一致 encrypted_text = Base64.strict_encode64(cipher_text_with_iv_salt) event.set('message_encrypted', encrypted_text) " add_field => { "new_secret" => "%{[message_encrypted]}" } }
修复说明
- 新增
cipher.iv = iv:将生成的IV绑定到加密器,确保加密逻辑正确 - 空值处理:添加
return unless plaintext,对应Java中data == null的判断 - 统一编码:使用
plaintext.encode('UTF-8')确保明文转字节和Java一致 - 正确拼接数据:按IV → Salt字节 → 加密数据 → GCM标签的顺序拼接,和Java逻辑对齐
- 使用
Base64.strict_encode64:避免默认encode64添加换行符,保证输出格式和Java一致
内容的提问来源于stack exchange,提问作者Manoj Singh
相关产品推荐
相关产品推荐

