加密空字符串
Encrypt empty string
我正在使用 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”
- 微软 SQL 服务器 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代码
如果可以使用DBMS提供的加密函数,那么,MySQLAES_ENCRYPT
,好像可以加密空字符串。
例如:
UPDATE some_table
SET some_column = AES_ENCRYPT('',UNHEX('F3229A0B371ED2D9441B830D21A390C3'));
默认情况下是 AES-128,我猜这会是个问题,因为您需要 AES-256。另外,不确定您使用的是哪个DBMS,以及该DBMS是否具有加密功能。
, it's as simple as not calling Cipher#update
with the empty string. The value returned by 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]
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
end
p decrypt(*encrypt("foo")) # "foo"
p decrypt(*encrypt("")) # ""
我正在使用 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”
- 微软 SQL 服务器 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代码
如果可以使用DBMS提供的加密函数,那么,MySQLAES_ENCRYPT
,好像可以加密空字符串。
例如:
UPDATE some_table
SET some_column = AES_ENCRYPT('',UNHEX('F3229A0B371ED2D9441B830D21A390C3'));
默认情况下是 AES-128,我猜这会是个问题,因为您需要 AES-256。另外,不确定您使用的是哪个DBMS,以及该DBMS是否具有加密功能。
Cipher#update
with the empty string. The value returned by 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]
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
end
p decrypt(*encrypt("foo")) # "foo"
p decrypt(*encrypt("")) # ""