Я использую довольно стандартный пример (один, который сломан для моих целей) из CBC шифрования рубина:AES CBC шифрование потоков в рубине?
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') в конце строки был зашифрован. В конце концов, каждый вызов для обновления возвращает строку, которая ((string.length/16) + 1) * 16 байт, подразумевая, что она шифрует дополнительный байт при каждом обновлении.
Как получить шифрование и дешифрование OpenSSL для работы в режиме, в котором я могу проходить в блоках данных и получать тот же результат обратно, независимо от размера фрагментов, в которые я разбиваю данные?
EDIT:
Вопрос не зависит от base64 кодирования. Ниже приводятся 3 различных результата cyphertext:
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)
Я считаю, что то, что вы видите, на самом деле является IV для шифрования CBC. Вы можете проверить это, сделав длину '255' вместо' 256'. Если он действительно шифрует '' \ 0'' байт в конце, то каждый из них должен иметь длину всего 256 байтов. – Omnifarious
Я сделал то, что предложил, и доказал, что ошибаюсь. – Omnifarious
Кстати, я вообще не программирую в Ruby. Было бы полезно, если бы вы ввели инструкции 'require 'openssl.rb'' и' require' base64.rb''. :-) – Omnifarious