使用 ECDSA P-256 SHA-256 和 PHP 创建 JWT

问题描述 投票:0回答:3

我想知道是否可以使用 P256 曲线和 PHP 正确创建签名。 PHP 中的 OpenSSL 支持创建密钥并按顺序获取正确的内容。

根据本文档 - http://self-issued.info/docs/draft-jones-json-web-token-01.html#DefiningECDSA - 第 8.3 节指出:

JWT 使用 ECDSA P-256 SHA-256 签名进行签名,如下所示:

  1. 使用 ECDSA P-256 SHA-256 和所需的私钥生成 JWT 签名输入的 UTF-8 表示形式的数字签名。输出将是 EC 点 (R, S),其中 R 和 S 是无符号整数。
  2. 将 R 和 S 按大端顺序转换为字节数组。每个数组的长度为 32 个字节。
  3. 按照 R、S 的顺序连接两个字节数组。
  4. Base64url 对本规范中定义的 64 字节数组进行编码。

这里的问题在于获取R和S字节数组。

这是我正在尝试做的一个例子。

//Create Array Configuration
$config = array(
    "curve_name" => "prime256v1",
    "private_key_type" => OPENSSL_KEYTYPE_EC,
);
$ourkey = openssl_pkey_new($config);

/* We would get the key details to help extract out other information such as x/y coord 
of curve and private key but it's not necessary to show for this part*/

// Extract the private key from $res to $privKey
openssl_pkey_export($ourkey, $privKey);

$data = "Example data we will be using to sign";
$data = hash("sha256", $data);

$signature = "";
openssl_sign($data, $signature, $privKey); // Should I include the digest algo in this call as well?

这里的问题是这个签名不是我可以用来连接在一起来制作我需要的真正签名的 R 和 S...我认为。

最终,有什么方法可以从 php 中的 openssl 函数获取 R 和 S 值吗?

非常感谢任何帮助!

php cryptography jwt digital-signature xbox-one
3个回答
2
投票

如果您需要类似 JWT 但不是特别需要 JWT,请考虑PASETO

假设您选择 v2,PASETO 不使用 ECDSA,它使用比 Ed25519 更安全的 EdDSA。此外,该标准特意变得“无聊”,因此实施显然是安全的。 (如果您选择 v1,PASETO 使用 RSASSA-PSS。)

如果您

确实

特别需要JWT,那么lcobucci/jwt就是最好的选择,它又使用PHPECC进行ECDSA。 曾几何时,PHPECC 充满了侧通道漏洞,这使其成为在生产系统中使用的糟糕选择。如今,它的安全性与 ECDSA 的 PHP 实现一样安全。如果有人想在最安全的配置中使用 PHPECC,我编写了一个名为

easy-ecc

的可用性包装器。 据我所知,Luís Cobucci 的 JWT 库是唯一经过安全公司正式审核的 JWT PHP 实现。该报告是公开的并发布在这里

这些函数帮助我对曲线生成的签名进行编码和解码,我希望这有帮助。

0
投票
编码:

function encode_signature() { $data = "HOLA"; $private_key = <<<EOD -----BEGIN PRIVATE KEY----- MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDKuYJPma+sA2svl02CPCJECESuBrW2nExuUR1vtHgozw== -----END PRIVATE KEY----- EOD; $binary_signature = ""; openssl_sign($data, $binary_signature, $private_key, OPENSSL_ALGO_SHA256); $valid_signature = base64_encode($binary_signature); return $valid_signature; }

解码:
function decode_signature($signature) {
    $data = "HOLA";

$public_key = <<<EOD
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/kmRxyn5LUQdC3owkWDp6DkLnTlBN2VPd86FS5WAqQJA4y9oaowYYVSu0A7kv8tUa9FLAqb7UPfUNeh5zDnrFQ==
-----END PUBLIC KEY-----
EOD;

    $publicKey = openssl_pkey_get_public($public_key);
    $verify = openssl_verify($data, base64_decode($signature), $publicKey, OPENSSL_ALGO_SHA256);

    return (bool) $verify;
}

我知道该线程较旧,但因为我经常使用 Web crypto api 生成的密钥对和签名,并尝试使用 php openssl_verify() 方法进行验证...

0
投票
上面的功能看起来不错,但在经过多次测试的变体中对我来说不起作用。尝试了不同的操作系统基础(centos、alpine)和 php 版本(7.4、8.1、8.2、8.3),但每次验证 ecdsa 签名都会失败并显示“-1”。

将密钥对移至 RSASSA-PKCS1-v1_5 首次使用相同的 php 代码即可工作。 所以它看起来像是 php / openssl 问题 / Ecdsa 密钥对的错误?

© www.soinside.com 2019 - 2024. All rights reserved.