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

时间:2015-01-16 15:15:05

标签: ruby encryption

我有两个用于使用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)而不是随机生成时,问题不会发生

1 个答案:

答案 0 :(得分:1)

问题源于您将二进制数据视为字符串这一事实。 iv以及encrypted.encode都是二进制文件,您将它们与“|”连接起来(一个字符串)。 iv以及消息都可能包含管道符,这会在拆分时导致问题。一般来说,最好将两个部分分别作为基础。

这是工作代码:

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下的来源)。