【问题标题】:Is there a way to use Sodium Encrypt without the random nonce in PHP?有没有办法在 PHP 中没有随机数的情况下使用 Sodium Encrypt?
【发布时间】: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


【解决方案1】:

我知道这条消息很旧并且可能已解决,但我想这可能会有所帮助。

NONCE 的长度为 24 个字符。 -> 这几乎就是答案。但是,如果您尝试使 nonce 不是随机的,包括密钥,那么输出将不再是针对单个数据的一系列无穷无尽的随机字符。这很容易说成一对一。总之,KEY 是 32 个字符。让我们试试这个例子。

<?php
class justEncrypt {
     private $key = 'vDIa5JdknBqfrKOu8d7UpddnBMCH1vza'; //32 characters
     private $nonce = 'Ra5LeH7ntW2rvkz3dmqI5Stx'; //24 characters

     public function sodiumStaticEncrypt(string $data) {
           $encrypted = base64_encode(
                 sodium_crypto_secretbox(
                       $data,
                       $this->nonce,
                       $this->key
                 )
           );
           return $encrypted;
    }
}

测试脚本:

<?php
$site = new justEncrypt; // I feel like I should not have done this
    echo $site->sodiumStaticEncrypt("It's better late than never!");

会有5Was2l9V0RgsgEm5csEbXnCaIxLkWwWiOxnHBgrej9+Ipyqn4ehn8VImFa8= 的输出,仅此而已,因为您不希望它变得随机,对吧?

检索数据相对容易。只需添加此代码:

     public function sodiumStaticDecrypt(string $data) {
           // decode the base64 on $data first
           $decrypt = base64_decode($data);
           $decrypted = sodium_crypto_secretbox_open($data,$this->nonce,$this->key);
           return $decrypted;
     }

因此:

<?php

echo $site->sodiumStaticDecrypt('5Was2l9V0RgsgEm5csEbXnCaIxLkWwWiOxnHBgrej9+Ipyqn4ehn8VImFa8=');

它会返回纯文本:It's better late than never!

无论你做什么,只要你不改变密钥和随机数,加密永远不会改变。这就像一对一的加密。只要确保没有人知道密钥和随机数,因为一切都会变得无用。别忘了NONCE应该是24个字符,不多也不少; KEY 应该是 32 个字符长,不多也不少。

无论随机数和密钥每次都是随机的,也可以使用常规的钠随机加密(保存电子邮件、用户名等)。但这不是问题。无论如何,我建议不要将其设为静态,因为它的设计目的不是一体。

好吧,我希望你已经解决了这个问题,我希望这会有所帮助(即使我真的这么想,它也没有)。

【讨论】:

    【解决方案2】:

    @Tesmurd101 上只有一条评论。 在 sodiumStaticDecrypt 以下行

    $decrypted = sodium_crypto_secretbox_open($data,$this->nonce,$this->key);
    

    应该是

    $decrypted = sodium_crypto_secretbox_open($decrypt,$this->nonce,$this->key);
    

    【讨论】:

    • 由于您引用的代码行在公共函数 sodiumStaticDecrypt(string $data) 中,$data 变量引用了函数头中的 $data 语句,它是正确的。当然,如果两个变量都命名为 $encrypt 会更好读 :-)
    猜你喜欢
    • 2016-01-10
    • 2016-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    相关资源
    最近更新 更多