Ruby:解密消息,该消息使用 Java (AES/256/GCM) 加密,

问题描述 投票:0回答:1

我有一个 Java 代码,它使用 AES-256-GCM 加密消息。我想用 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 =  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 编写相同的实现(加密和解密)

我尝试了下面的 Ruby 解密代码。这给出了错误,

(irb):99:in 
最终':OpenSSL::Cipher::CipherError`

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')
java ruby encryption aes-gcm
1个回答
0
投票

正如评论中所解释的,Ruby 代码使用了错误的密钥并且缺少标签的分离(与 Java 不同,Ruby/OpenSSL 分别处理标签和密文):

require 'base64'
require 'openssl'
require 'stringio'

cipher_message = "ngii4DerThzOaBfFt93zNgxY4kJVC7V+m92buC++OQC+OcKHA/FP1u0mwTIAOlexDJM/+xA0LRarIfXE7Qr7IkEfy/V8m37qqR3twrtKghexlV0oNOab" # generated with the Java code
password = "password"
decoded_cipher_byte = Base64.decode64(cipher_message)

# separate IV, salt, ciphertext and tag
byte_buffer = StringIO.new(decoded_cipher_byte)
ivSize = 12
saltSize = 16
tagSize = 16
ciphertextSize = decoded_cipher_byte.length - ivSize - saltSize - tagSize
iv = byte_buffer.read(ivSize)
salt = byte_buffer.read(saltSize)
encrypted_byte = byte_buffer.read(ciphertextSize)
tag = byte_buffer.read

# derive key
secret_key = OpenSSL::KDF.pbkdf2_hmac(password, salt: salt, iterations: 65536, length: 32, hash: 'sha256')

# decrypt with AES-256, GCM
cipher = OpenSSL::Cipher::AES.new(256, :GCM).decrypt
cipher.iv = iv
cipher.key = secret_key # Fix 1: apply derived key
cipher.auth_tag = tag # Fix 2: apply detached tag
#cipher.auth_data = auth_data # no AAD
decrypted_message_byte = cipher.update(encrypted_byte) + cipher.final

puts decrypted_message_byte.force_encoding('UTF-8') # The quick brown fox jumps over the lazy dog

在这里您可以从 Ruby/OpenSSL 文档中找到使用 AES/GCM 进行身份验证加密的示例。

© www.soinside.com 2019 - 2024. All rights reserved.