【发布时间】:2019-11-10 20:08:33
【问题描述】:
我正在对新库“Libsodium”进行一些实验。基于https://www.zimuel.it/slides/zendcon2018/sodium#/21 幻灯片。在这张幻灯片中,有一个关于使用钠进行加密和解密的示例。
$msg = 'This is a super secret message!';
// Generating an encryption key and a nonce
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); // 256 bit
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
// Encrypt
$ciphertext = sodium_crypto_secretbox($msg, $nonce, $key);
// Decrypt
$plaintext = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
echo $plaintext === $msg ? 'Success' : 'Error';
我在这样的 PHP 类方法中使用了它:
public function sodium_encrypt($p_sPlaintext)
{
try{
if(!empty($p_sPlaintext) && is_string($p_sPlaintext)){
// Generating an encryption key and a nonce
$key = random_bytes(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); // 256 bit
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
// Encrypt Note: the encryption is always authenticated, you need to store also nonce + ciphertext
$eCiphertext = sodium_crypto_secretbox($p_sPlaintext, $nonce, $key);
$eCryptotext = $nonce.$eCiphertext;
if(!empty($eCiphertext)){
return($eCiphertext);
} else{
throw new Exception('clse004'); // Error trigger
}
} else{
throw new Exception('clse005'); // Error trigger
}
} catch (Exception $e){
echo("<br>Errormessage, code: ".$e->getMessage());
}
}
它的工作原理应该是这样,没有问题。但是...... :-) 总是有一个“但是”。
如果我使用这种方法加密,例如,电子邮件地址并将其作为用户登录凭据存储在数据库中,那么它们是他凭据的唯一加密。下次用户输入他的凭据并加密这些凭据时,由于 $key 和 $nonce 的随机生成,我在数据库中找到了他。
如果我生成自己的非随机密钥:(https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx)
$key = "4D6251655468576D597133743677397A24432646294A404E635266556A586E32"; // 256 bit hex
然后我收到消息:“密钥大小应为 SODIUM_CRYPTO_SECRETBOX_KEYBYTES 字节”。
用钥匙:
$key = "E)H@McQfTjWnZr4u7w!z%C*F-JaNdRgU"; // 256 bit non hex
这个问题也解决了吗?
那么 $ciphertext 仍然是随机的,因为随机数。用非随机随机数替换随机数发生器,例如:(https://www.random.org/bytes/)
$nonce = "d80ac8385bb52cef7920ded5bda4de50697efc95ea53d81b" ; // 24 bytes hex
显示此消息:“nonce 大小应为 SODIUM_CRYPTO_SECRETBOX_NONCEBYTES 字节”。
同理:
$nonce = "249206220193104991548714284109130186236311295118249161302345616 " ; // 24 bytes decimal
$nonce = "056073032127157034374115050245203151150054323272014260311360377272100266" ; // 24 bytes octal
目前我目前的方法如下:
public function sodium_encrypt($p_sPlaintext)
{
try{
if(!empty($p_sPlaintext) && is_string($p_sPlaintext)){
// Generating an encryption key and a nonce
$key = "E)H@McQfTjWnZr4u7w!z%C*F-JaNdRgU"; // 256 bit
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES); // 24 bytes
// Encrypt Note: the encryption is always authenticated, you need to store also nonce + ciphertext
$eCiphertext = sodium_crypto_secretbox($p_sPlaintext, $nonce, $key);
//$eCryptoText = $nonce.$eCiphertext;
echo $eCiphertext;
if(!empty($eCiphertext)){
return($eCiphertext);
} else{
throw new Exception('clse004'); // Error trigger
}
exit();
} else{
throw new Exception('clse005'); // Error trigger
}
} catch (Exception $e){
echo("<br>Errormessage, code: ".$e->getMessage());
}
}
我查看了https://download.libsodium.org/doc/secret-key_cryptography,但找不到一个解决方案来创建一个非随机(秘密)nonce 以在此加密实例中使用。 有人有想法吗?是否有更多人在 PHP 中使用 Sodium? 欢迎任何意见。
【问题讨论】:
-
一般情况下(不仅适用于 Sodium),对于为相同明文(概率)生成不同密文的算法,不可能从两个密文的不等式中推断出明文的不等式。这只能通过使用相同的随机数(当然,假设使用相同的密钥)来实现,但这会降低安全性甚至完全破坏它,即只使用一次密钥/随机数对是至关重要的。当然,从技术上讲,您可以通过将带有
hex2bin的十六进制字符串转换为相应的字节数组来使用任何随机数。
标签: php encryption sodium