AES-256-CFB 在使用 `random_iv` 时切断消息

AES-256-CFB cuts off message when using `random_iv`

我有两个使用 AES 加密和解密消息的脚本。

这里是encrypt.rb

require 'openssl'
require 'base64'
require 'digest'

KEY = 'sekrit_key'
MESSAGE = "My Name is Rabbit and I don't know anything!"

cipher = OpenSSL::Cipher::AES256.new(:CFB)
cipher.encrypt
cipher.key = KEY
# hexdigest the IV to make sure encode64 doesn't fuck up
iv = Digest::MD5.hexdigest(cipher.random_iv)
cipher.iv = iv

encrypted = cipher.update(secret_message)+cipher.final
puts Base64.urlsafe_encode64(iv+'|'+encrypted.encode)

... 和 decrypt.rb:

require 'openssl'
require 'base64'

KEY = 'sekrit_key'
encrypted_message = STDIN.read.strip

parts = Base64.urlsafe_decode64(encrypted_message ).split('|')
iv = parts[0]
encrypted = parts[1]

decipher = OpenSSL::Cipher::AES256.new(:CFB)
decipher.decrypt
decipher.key = KEY
decipher.iv = iv

message = decipher.update(encrypted)+decipher.final

if message.eql?("My Name is Rabbit and I don't know anything!")
    print '.'
else
    puts
    puts encrypted_message
    puts message
end

当我现在连续 运行 这两个脚本时,我的输出经常被切断!

$ while true; do ruby encrypt.rb | ruby decrypt.rb; done
....
YmZhNDg2ODJjNGZiOGIzZTcyMzAwYzMxZWUwNWI0Y2V8w2aJk930EL3gh3rfQsd2B3xZKy5wjoCzlZoYHBgmv6m51ZwAWQHGtCJoNRg=
My Name is Rabbi
..
YjMwNDQxOGRjMjg4NGEzOThmM2IwNGFiZDBiZTQxZGZ8OfLyjGQGKV3PPUpCvfL08IDuk7M7d3w7fj6F5Rql94jkRdwaCuuMfedqtFk=
My Name is Rabbit and
..
OWUxYzFlZWU5MTc4NGZjYWYxYzZiOGEwOTBjOGMxYzJ8g7I4X_Dt6K9ufByMhLBGlpoYCv8vlR0lTBqP-zS647tmmFh81rXdR8T-UkM=
My Name i
....
# and so on

为什么我的很多消息都被截断了?

更新: 当在 encrypt.rb 中使用固定 IV(例如,将 cipher.random_iv 替换为 KEY)而不是随机生成时,问题没有发生。

问题源于您将二进制数据视为字符串这一事实。 ivencrypted.encode 是二进制的,你用“|”连接它们(一个字符串)。 iv 和消息都可能包含管道字符,这会导致拆分时出现问题。一般来说,最好分别对这两个部分进行base64。

这是工作代码:

encrypt.rb

require 'openssl'
require 'base64'
require 'digest'

KEY = 'sekrit_key123456' * 2
MESSAGE = "My Name is Rabbit and I don't know anything!"

cipher = OpenSSL::Cipher::AES256.new(:CFB)
cipher.encrypt
cipher.key = KEY
iv = cipher.random_iv

encrypted = cipher.update(MESSAGE)+cipher.final
puts Base64.strict_encode64(iv)+'|'+Base64.strict_encode64(encrypted.encode)

decrypt.rb

require 'openssl'
require 'base64'

KEY = 'sekrit_key123456' * 2 # key needs to be the right length
encrypted_message = STDIN.read.strip

parts = encrypted_message.split('|')
iv = Base64.strict_decode64(parts[0])
encrypted = Base64.strict_decode64(parts[1])

decipher = OpenSSL::Cipher::AES256.new(:CFB)
decipher.decrypt
decipher.key = KEY
decipher.iv = iv

message = decipher.update(encrypted)+decipher.final

if message.eql?("My Name is Rabbit and I don't know anything!")
    print '.'
else
    puts
    puts encrypted_message
    puts message
end

另请注意,random_iv 已将 iv 分配给密码,因此您不需要(请参阅 http://apidock.com/ruby/v1_9_3_125/OpenSSL/Cipher/random_iv 下的源代码)。