我使用
Ruby的
Open SSL bindings进行AES-256加密.我可以加密非空字符串.但是,在尝试加密空字符串时,Ruby会引发异常,抱怨数据不能为空.如何使用Ruby的OpenSSL绑定加密空字符串?
代码重现问题
require "openssl" KEY = OpenSSL::Cipher::Cipher.new("aes-256-cbc").random_key def encrypt(plaintext) cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") cipher.encrypt iv = cipher.random_iv cipher.iv = iv cipher.key = KEY ciphertext = cipher.update(plaintext) # <- ArgumentError here ciphertext << cipher.final [iv,ciphertext] end def decrypt(iv,ciphertext) cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") cipher.decrypt cipher.iv = iv cipher.key = KEY plaintext = cipher.update(ciphertext) plaintext << cipher.final plaintext end p decrypt(*encrypt("foo")) # "foo" p decrypt(*encrypt("")) # /tmp/foo.rb:11:in `update': data must not be empty (ArgumentError) # from /tmp/foo.rb:11:in `encrypt' # from /tmp/foo.rb:27:in `<main>'
版本
> ruby-2.2.2p95
> OpenSSL :: VERSION是“1.1.0”
> Microsoft sql Server 2014(12.0.2000.8)
为什么我要加密空字符串?
我正在编写一个ETL程序,用于将数据从一个数据库迁移到sqlServer数据库.必须先对源数据库中的某些列进行加密,然后再将其写入目标数据库.源列可以包含任何数据,包括空字符串.目标列通常是不可为空的.目标列将由.net代码解密.
目标#1:没有关于加密字段的信息,包括它是否存在,在没有正确解密的情况下,应该是可恢复的.加密的空字符串应与任何其他加密数据无法区分.
目标#2:将解密这些值的.net代码不需要特别处理空字符串.
如果我可以使用openssl加密空字符串,我将实现这两个目标.
解决方法 – 不要加密空字符串
我可以不加密空字符串,传递它们.
def encrypt(plaintext) return plaintext if plaintext.empty? ... end def decrypt(iv,ciphertext) return ciphertext if ciphertext.empty? ... end
这具有暴露信息的缺点,并且还需要在.net端写入协作代码.
我可以在加密前向明文添加一些常量字符串,并在解密后将其删除:
PLAINTEXT_SUFFIX = " " def encrypt(plaintext) plaintext += PLAINTEXT_SUFFIX ... end def decrypt(iv,ciphertext) ... plaintext.chomp(PLAINTEXT_SUFFIX) end
这隐藏了数据是否存在,但仍需要合作的.net代码.
解决方法
As suggested by @ArtjomB,就像没有用空字符串调用
Cipher#update
一样简单.
Cipher#final
返回的值然后正确加密空字符串.
require "openssl" KEY = OpenSSL::Cipher::Cipher.new("aes-256-cbc").random_key def encrypt(plaintext) cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") cipher.encrypt iv = cipher.random_iv cipher.iv = iv cipher.key = KEY ciphertext = "" ciphertext << cipher.update(plaintext) unless plaintext.empty? ciphertext << cipher.final [iv,ciphertext) cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc") cipher.decrypt cipher.iv = iv cipher.key = KEY plaintext = cipher.update(ciphertext) plaintext << cipher.final end p decrypt(*encrypt("foo")) # "foo" p decrypt(*encrypt("")) # ""