ruby - 在 ruby 中使用 OpenSSL 解密 aes-128-gcm tls 包时的一个非常奇怪的现象
问题描述
我正在使用自己的 ssl/tls 库进行学习。这些天,当我将加密消息播种到服务器时,我会收到“bad mac”警报。今天我用这个问题的记录来调试我的代码。
这就是奇怪的事情发生的地方。我使用他的 server_random、client_random 和 master-secret 来生成 client_write_key 和 client_write_iv。然后我得到与他相同的输出。但是,当我使用 client_wrtie_key 和 client_write_iv 解密“GET / HTTP/1.0\n”消息时,我得到以下输出:
Q▒W▒ ▒7▒3▒▒▒
这与正确的消息是如此不同!我的整个调试输出是
C:/Users/ayanamists/.babun/cygwin/home/ayanamists/my_ssl_in_ruby/encrypt_handler/aes_gcm_handler.rb:87:in `final': OpenSSL::Cipher::CipherError
from C:/Users/ayanamists/.babun/cygwin/home/ayanamists/my_ssl_in_ruby/encrypt_handler/aes_gcm_handler.rb:87:in `recv_decrypt'
from decrypt.rb:72:in `<main>'
client write key is
4b 11 9d fb fc 93 0a be 13 00 30 bd 53 c3 bf 78
nonce is
20 29 ca e2 c9 1d e0 05 e2 ae 50 a8
what to be decrypt:
a5 7a be e5 5c 18 36 67 b1 36 34 3f ee f4 a3 87 cb 7c f8 30 30
the tag is
a4 7e 23 0a f2 68 37 8c 4f 33 c8 b5 ba b3 d2 6d
the additional data is
00 00 00 00 00 00 00 01 17 03 03 00 00 15
decrypter is
OpenSSL::Cipher::AES
Q▒W▒ ▒7▒3▒▒▒
output is
bd 8c e8 87 b7 ab c6 f7 eb 31 fd cb 65 4c d4 a9 16 ae 1b ca da
the correct is
47 45 54 20 2f 20 48 54 54 50 2f 31 2e 30 0a
你可以看到我的key和nonce和他的key和nonce没有区别,但是为什么结果是错误的呢?代码是:
require_relative 'encrypt_message_handler'
require 'pp'
class AES_CGM_Handler
include EncryptMessageHandler
attr_accessor :send_cipher, :recv_cipher, :send_implicit, :recv_implicit,
:send_seq_num, :recv_seq_num
def initialize(server_random, client_random, certificate = '', length = 0,
usage = 'client', version_major = 0x03, version_minor = 0x03)
if block_given?
@master = yield
@version = [0x03, 0x03]
else
super(server_random, client_random, certificate)
end
# the nonce of AES_GCM is defined by:
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# + 0 1 2 3 | 0 1 2 3 4 5 6 7 +
# + salt | nonce_explicit +
# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
# salt is server_write_iv or client_write_iv, so you need 4 * 2
# and length need to /8(bit->byte) and * 2(both server and client), so it's length/4
key_block = (length/4 + 4 * 2).tls_prf(@master, "key expansion", server_random + client_random)
arr = key_block.unpack "a#{length/8}a#{length/8}a4a4"
client_write_key = arr[0]
server_write_key = arr[1]
client_write_iv = arr[2]
server_write_iv = arr[3]
@send_cipher = OpenSSL::Cipher::AES.new(length, :GCM).encrypt
@recv_cipher = OpenSSL::Cipher::AES.new(length, :GCM).decrypt
if usage == 'client'
@send_cipher.key = client_write_key
@send_implicit = client_write_iv
@recv_cipher.key = server_write_key
@recv_implicit = server_write_iv
puts "server write key is #{server_write_key.to_hex}"
elsif usage == 'server'
@send_cipher.key = server_write_key
@send_implicit = server_write_iv
@recv_cipher.key = client_write_key
@recv_implicit = client_write_iv
puts "client write key is\n #{client_write_key.to_hex}"
else
raise "AES_GCM_HANDLER: BAD_ARGUMENT"
end
@send_seq_num = 0
@recv_seq_num = 0
end
def send_encrypt(type = 22, seqence = '')
nonce_explicit = OpenSSL::Random.random_bytes(8)
nonce = @send_implicit + nonce_explicit
@send_cipher.iv = nonce
length = seqence.length
#the handle of seq_num may be wrong
@send_cipher.auth_data = [0, @send_seq_num,
type, @version[0], @version[1], 0 ,length].pack("NNCCCCn")
encrypt = @send_cipher.update(seqence) + @send_cipher.final
encrypt = encrypt + @send_cipher.auth_tag
return encrypt
end
def recv_decrypt(type = 22, sequence = '', seq_num = 0)
if seq_num != 0
@recv_seq_num = seq_num
end
template = 'a8a*'
arr = sequence.unpack(template)
nonce_explicit = arr[0]
length = sequence.length - 8 - 16
sequence = arr[1]
encrypted = sequence[0, sequence.length - 16]
@recv_cipher.auth_tag = sequence[sequence.length - 16, sequence.length]
@recv_cipher.iv = @recv_implicit + nonce_explicit
puts "nonce is\n #{(@recv_implicit + nonce_explicit).to_hex}"
puts "what to be decrypt: \n #{encrypted.to_hex}"
puts "the tag is \n #{sequence[sequence.length - 16, sequence.length].to_hex}"
@recv_cipher.auth_data =
[0, @recv_seq_num, type ,@version[0], @version[1], 0 ,length].pack("NNCCCCn")
puts "the additional data is\n #{([0, @recv_seq_num, type ,@version[0], @version[1], 0 ,length].pack("NNCCCCn")).to_hex }"
puts "decrypter is\n #{@recv_cipher.class}"
puts @recv_cipher.update(encrypted)
puts "output is\n #{@recv_cipher.update(encrypted).to_hex}"
puts "the correct is\n #{"GET / HTTP/1.0\n".to_hex}"
decrypt = @recv_cipher.update(encrypted) + @recv_cipher.final
return decrypt
end
end
请帮我解决这个问题,我将不胜感激!
解决方案
我终于解决了这个问题!如果有人想使用此测试向量,请不要忘记将“789c”添加为 zlib compress
推荐阅读
- java - 为什么我在运行一个简单的 Spring Boot gradle 项目时会得到 404 状态?
- amazon-web-services - 在 terraform 中添加定义不同堆栈的变量的最佳方法是什么?
- php - 为什么这个 PHP 比较它不会返回 True
- promise - 为什么我看到 Promise 未决
- python - 如何从另一个 Python 文件调用一个 Python 文件?
- tensorflow - 如何使用 Tensorflow QAT 将 CNN 正确量化为 4 位?
- oracle - Oracle 多租户 - 从 PL/SQL 更改容器
- java - Java Kafka Consumer 可以与新的 Consumer Group ID 一起正常工作,但是在关闭并重新启动时它不会消耗任何消息
- c# - 包含作为方法参数的 C# LINQ lambda 表达式
- c++ - 什么是“一元构造函数”?