Я использовал довольно стандартный пример (который сильно сломан для моих целей) шифрования cbc в ruby:
def aes(m,k,t)
(aes = OpenSSL::Cipher::Cipher.new('aes-256-cbc').send(m)).key = Digest::SHA256.digest(k)
aes.update(t) << aes.final
end
def encrypt(key, text)
aes(:encrypt, key, text)
end
def decrypt(key, text)
aes(:decrypt, key, text)
end
Это работает как приемлемая отправная точка, но мне нужновозможность шифровать большие потоки данных без загрузки их в один огромный кусок памяти.Я хочу загрузить мег за раз, обновить состояние потока шифрования, а затем перейти к следующему блоку.Глядя на документы по OpenSSL Cipher (которые удостоены многих наград), я ожидаю, что запрос на обновление должен просто продолжить поток данных.Тем не менее, простой тест говорит мне, что есть что-то очень неправильное:
Length = 256
newaes = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
newaes.encrypt
newaes.key= Digest::SHA256.digest("foo")
puts Base64.encode64(newaes.update("a"*Length))
puts Base64.encode64(newaes.update("a"*Length))
puts Base64.encode64(newaes.final)
Запуск этого с другими значениями для длины не должен давать мне разные потоки.Однако после окончания первого обновления всегда возникает проблема.Потоки расходятся.Я догадывался, что проблема заключалась в том, что по какой-то необъяснимой причине завершающий нулевой символ ('\ 0') в конце строки шифровался.В конце концов, каждый вызов update возвращает строку длиной ((string.length / 16) + 1) * 16 байт, что подразумевает шифрование дополнительного байта с каждым обновлением.
Как заставить шифрование и дешифрование OpenSSL работать в режиме, в котором я могу передавать блоки данных и получать тот же результат обратно, независимо от размера фрагментов, на которые я разбиваю данные?
РЕДАКТИРОВАТЬ:
Эта проблема не зависит от кодировки base64.Следующее дает 3 разных результата зашифрованного текста:
require 'digest/sha2'
require 'base64'
require 'openssl'
def base64(data)
Base64.encode64(data).chomp
end
def crypt_test(blocksize)
newaes = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
newaes.encrypt
newaes.key= Digest::SHA256.digest("foo")
plaintext = ""
cyphertext = ""
File.open("black_bar.jpg") do |fd|
while not fd.eof
data = fd.read(blocksize)
cyphertext += data
cyphertext += newaes.update(data)
end
end
cyphertext += newaes.final
puts base64(Digest::SHA256.digest(plaintext))
puts base64(Digest::SHA256.digest(cyphertext))
puts
end
crypt_test(1024)
crypt_test(512)
crypt_test(2048)