【问题标题】:Generate correct AES-256-CBC key / how to store?生成正确的 AES-256-CBC 密钥/如何存储?
【发布时间】:2019-06-17 04:12:31
【问题描述】:

我使用 Laravel 5.7 并且有两个应用程序在不同的服务器上运行。我想与加密通信。所以两端都需要有一定的key。默认 laravel 加密设置为 AES-256-CBC。

所以我想,我需要一个这样的 32 字节密钥:

$key = bin2hex(openssl_random_pseudo_bytes(32, $cstrong));

我得到一个 64 长的十六进制字符串,我想在两端保存,所以双方都可以访问一侧加密和另一侧解密。

但不知何故,这个密钥不被接受。 Laravel 抛出: 唯一受支持的密码是具有正确密钥长度的 AES-128-CBC 和 AES-256-CBC

我还尝试将其设置为 16 字节,使用 32 个字符的密钥。也不行。

但是,它确实可以将其设置为 8 位,使用 16 个字符的密钥。但这对我来说没有任何意义?

Laravel 本身使用类似这样的键: base64:X,其中 X=44 个字符串。

我在某处读到 AES-256-CBC 需要 64 个字符的密钥,其中 44 个字符应该是 base64。我不确定这是否正确,但我很难做到这一点。如何读取带有 base64 前缀的密钥:?如何将其恢复为常规字符串。

目前我已经解决了这 16 个字符的字符串,但似乎不正确。那么如何生成有效的 AES-256-CBC 密钥,以及如何存储它呢?如果需要base64,它是如何工作的?对生成的 64 位十六进制密钥进行编码会返回一个 88 字符的字符串。

感谢任何帮助。

【问题讨论】:

    标签: php encryption openssl key aes


    【解决方案1】:

    我自己无法尝试,但请查看源代码here:

    /**
     * Create a new encryption key for the given cipher.
     *
     * @param  string  $cipher
     * @return string
     */
    public static function generateKey($cipher)
    {
        return random_bytes($cipher === 'AES-128-CBC' ? 16 : 32);
    }
    

    所以调用random_bytes()(或其等效的openssl)是您需要做的所有事情,或者要求16个字节(在AES-128-CBC的情况下)或32个字节(在AES-256-CBC的情况下)。这是有道理的,因为最终,AES 的密钥只不过是一堆随机字节。

    您可能会感到困惑的是string 一词的用法。与 string 类型的常见用法不同,在这种情况下,它不是 printable 字符串,而只是字节的集合,其中 16 或 32 个字节。

    这就是Base64 translation 出现的原因。它允许您仅通过ASCII 字符来表示字节集合。我怀疑您所指的“base64:X,其中 X=44 字符串”值存在于某些配置文件中,该文件通常应仅包含可读字符。实际上,将 32 个字节转换为 Base64 格式将产生 44 个字符。在这种情况下,base64: 前缀仅用于指示该值以 Base64 格式存储。

    一个说明这一切的例子:

    $key = random_bytes(32);
    var_dump($key);
    var_dump(base64_encode($key));
    

    给予

    string(32) "?9???֔e?N??Y?&[??b?4@O|?\?"
    string(44) "45U5nvetGyfWlGWOF06N+VnIJlvwx2L3fzRAT3z5XPY="
    

    后者是一种方便的存储密钥的格式。

    PS:Encryption - Configuration section of the docuemntation 提到

    在使用 Laravel 的加密器之前,你必须在你的 config/app.php 配置文件。你应该使用 php artisan key:generate 命令生成此密钥

    也许该命令会执行您自己尝试执行的所有操作?

    【讨论】:

    • base64 是一个完美的存储互译器。我建议使用内置的 PHP 扩展,如 LibSodium (PHP 7.2+) 进行 IV 翻译 (nonce) random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES) 并使用 sodium_crypto_box 进行加密。我built a container 让它更容易。使用后者的概念的绝佳答案。
    【解决方案2】:

    Laravel 使用Illuminate\Support\Facades\Crypt,它专为端到端加密而设计。这意味着您可以安全地加密和解密数据库中的数据,但它不是为大众通信加密而设计的。

    PHP 7.2+ 与 LibSodium 紧密结合:不赞成使用您自己的宅基地加密方法。您可以在 php.ini 配置中启用扩展,或者使用配置编译 PHP。你可以read more on the docs。

    假设 Bob 想向 Alice 发送一条消息。 Bob 和 Alice 都需要密钥对来加密和解密消息或数据。

    sodium_crypto_box_keypair();
    

    这些应该存储在数据库中,并且可以使用相互翻译器或后者来完成,例如base64*。每个用户都应持有唯一的密钥对,该密钥对可在帐户注册时颁发。

    您可以通过附加您的 Laravel \App\User.php 文件并添加一个新的可填充对象 keypair 来实现此目的。在表 users 上创建一个新的迁移,像这样附加列密钥对:

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('key_pair')->unique()->nullable();
        });
    }
    

    然后转到您的 App\Http\Controllers\Auth\RegisterController.php 文件并附加 create 方法。

    当您现在要加密时,可以参考用户密钥对。假设 Bob:Bob 的 id 为 1。假设 Alice:Alice 的 id 为 2。

    $bob   = User::find(1);
    $alice = User::find(2);
    

    我们现在可以加密来自 Bob 的消息并将其发送给 Alice,方法是创建一个像这样的钠加密盒:

    $kp = sodium_crypto_box_keypair_from_secretkey_and_publickey(
        sodium_crypto_box_secretkey($bob->keypair),
        sodium_crypto_box_publickey($alice->keypair) # Encrypt with Alices Public Key
    );
    
    $cbox = sodium_crypto_box(base64_encode('Hello, Alice. This is Bob.'), ($nonce = random_bytes(SODIUM_CRYPTO_BOX_NONCEBYTES)), $kp);
    

    我们现在可以将 IV 或更好地称为 nonce 和 cyprto 盒子发送给 Alice。如果 Alice 现在想阅读该消息,她可以使用她的私钥和 Bobs 的公钥来阅读。

    $kp = sodium_crypto_box_keypair_from_secretkey_and_publickey(
        sodium_crypto_box_secretkey($alice->keypair),
        sodium_crypto_box_publickey($bob->keypair) # Decrypt with Bobs public key
    );
    
    echo base64_decode(sodium_crypto_box_open($cbox, $nonce, $kp));
    

    我built a container 使用 LibSodium 使加密和签名消息更容易。我希望这有助于理解这个概念以及如何使用加密和存储 base64* 后者。

    【讨论】:

      猜你喜欢
      • 2021-05-11
      • 1970-01-01
      • 2017-11-21
      • 2020-02-02
      • 2013-06-16
      • 2017-02-12
      • 2014-01-13
      • 1970-01-01
      • 2017-05-23
      相关资源
      最近更新 更多