生成正确的AES-256-CBC密钥/如何存储?

时间:2019-01-23 14:29:12

标签: php encryption openssl key aes

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

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

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

我得到了一个64位长的十六进制字符串,我想在两端保存,因此它们都可以在一侧进行加密,而在另一侧进行解密。

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

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

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

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

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

目前,我已经使用了这16个字符串,但是看起来不太正确。那么,如何生成有效的AES-256-CBC密钥,以及如何存储它呢?如果需要base64,该如何工作?编码64个生成的十六进制密钥可以使我返回88个字符串。

感谢您的帮助。

2 个答案:

答案 0 :(得分: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:生成命令以生成此密钥

也许该命令可以完成您尝试做的所有事情?

答案 1 :(得分:1)

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来实现。在表用户上创建一个新的迁移,像这样追加列密钥对:

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(或更好地称为现时)和cyprto盒发送给Alice。如果爱丽丝现在想阅读消息,则可以使用她的私钥和鲍勃斯公钥进行阅读。

$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*一起存储。