【问题标题】:Storing encryption_key & initialization_vector for later use with openSSL存储加密密钥和初始化向量以供以后与 openSSL 一起使用
【发布时间】:2019-07-23 18:37:24
【问题描述】:

我想使用 OpenSSL 加密/解密数据库数据。我在以下链接中找到并尝试使用代码: How to encrypt plaintext with AES-256 CBC in PHP using OpenSSL?

但是,如果我希望能够在稍后阶段解密已加密的数据,我似乎需要保留加密密钥和初始化向量以供以后使用。这给了我一个问题,因为我找不到存储这些数据位的方法。它们是在我加密数据时随机生成的,并且在那之后我目前会丢失它们,因为看起来我无法存储它们。我可以将它们存储到 PHP 变量中,但不能长期将它们存储在其他任何地方。

我的目标是加密客户数据库中的所有数据,因此显然需要这些数据位在必要时解密数据。在数据库中添加新数据或编辑现有数据时,我也需要使用它们。

因此,我需要找到一种存储加密密钥和初始化向量以供以后使用的方法。它们都是字节数组(32 字节和 16 字节),但除了 PHP 变量之外,我找不到存储它们的方法。

任何帮助将不胜感激。

【问题讨论】:

  • 可能感兴趣:Where to store a server side encryption key? 另外,How to store the encryption keys securely in php code file。如果您使用其中一些相同的关键字进行搜索,可能还有很多其他关键字。
  • 我遇到的主要问题是重建加密密钥和初始化向量,它们需要是字节数组(加密密钥是 32 字节 + 初始化向量是 16 字节)。我可以在创建这些字段时从这些字段中获取数据,但我需要在稍后阶段重新构建它们,以便我可以使用它们使用相同的密钥和向量进行加密/解密。我只需要找出如何使用所需数据重建它们。这是我的主要问题。看起来我需要使用 PHP 打包/解包函数,但我看不到如何使用它们来创建包含二进制或十进制数据的字节。

标签: php encryption openssl


【解决方案1】:

但是,如果我希望能够在以后解密已加密的数据,我似乎需要保留加密密钥和初始化向量以供以后使用。

请注意不要混淆两者。

  • 您将为您的系统总共存储一个密钥。密钥可以重复用于多条消息。
  • 对于每条消息,初始化向量必须是唯一且不可预测的。

这甚至没有涉及其他问题(CBC 模式不是 IND-CCA2 安全的,针对 PKCS#7 填充的填充 oracle 攻击,以及在尝试通过构建一个CBC+HMAC 协议)。

如何安全地解决问题

最好的办法是把它变成别人的问题,并使用一个库来为你解决这个问题。正如安全专家所说,“不要推出自己的加密货币。”

CipherSweet 是一个 PHP 库(带有 Node.js 端口),旨在促进可搜索的对称加密。您不必使用可搜索位(它涉及创建从明文派生的盲索引),加密经过微调以确保安全性且易于使用。

例如见here

<?php
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\EncryptedField;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\KeyProvider\StringProvider;

// Set up CipherSweet; you can use other key providers (e.g. for Amazon KMS)
$provider = new StringProvider(
    // Example key, chosen randomly, hex-encoded:
    '4e1c44f87b4cdf21808762970b356891db180a9dd9850e7baf2a79ff3ab8a2fc'
);
$engine = new CipherSweet($provider);

// For just a single field
$fieldEncrypter = new EncryptedField($engine, 'my_table', 'my_field_name');
$ciphertext = $fieldEncrypter->encryptValue("some plaintext value");

// For multiple fields, this API is probably easier:
$rowEncrypter = (new EncryptedRow($engine, 'other_table'))
    ->addTextField('name')
    ->addIntegerField('hidden_id')
    ->addFloatField('latitude')
    ->addFloatField('longitude')
    ->addBooleanField('secret_boolean');

$safeToStore = $rowEncrypt->encryptRow([
   'name' => 'John',
   'hidden_id' => 123,
   'latitude' => 12.34,
   'longitude' => 56.789,
   'secret_boolean' => true
]);

它是免费的、开源的、获得许可的,由一家专门从事应用程序安全和密码学的公司开发,非常适合解决手头的问题。

CipherSweet 很酷的一点是,如果您使用它,您不必考虑字节数组和字符串之间的内在差异(以及两者之间的转换逻辑)。您甚至不必知道 IV 是什么,更不用说如何正确使用它们了。密码学工程已经为您完成。

如果您需要生成密钥,只需复制上面的StringProvider 示例并将十六进制编码的字符串替换为bin2hex(random_bytes(32)) 的输出即可。

【讨论】:

  • 我在一个大的应用程序中使用这个解决方案,很棒!
猜你喜欢
  • 2011-07-03
  • 2012-04-28
  • 2013-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-07-07
  • 1970-01-01
  • 2016-11-05
相关资源
最近更新 更多