在 PHP 中生成 Paseto V2 公钥/令牌,在 Node.js 中验证

Woo*_*row 6 php slim node.js cryptojs paseto

前言:

什么是 Paseto?:https : //developer.okta.com/blog/2019/10/17/a-thorough-introduction-to-paseto

  • 我从这里使用 Paseto 的 PHP 库
  • 我正在使用这里的 Node.js Paseto 库

我已经能够使用PHP lib成功实现创建Paseto V1令牌和相应的公钥(在服务器端使用RSA私钥进行密钥对),然后使用公钥在节点上验证给定的令牌.js 方面:

PHP Paseto Public V1:

    $privateKeyV1 = new AsymmetricSecretKey($rsaPrivate, new Version1());
    $publicKeyV1  = $privateKeyV1->getPublicKey();

    $token = (string) (new Builder())
        ->setKey($privateKeyV1)
        ->setVersion(new Version1())
        ->setPurpose(Purpose::public())
        // Set it to expire in one day
        ->setExpiration(
            (new DateTime())->add(new DateInterval('P01D'))
        )
        ->setAudience('Foo')
        ->setIssuedAt(new DateTime())
        ->setIssuer('Bar')
        ->setNotBefore()
        ->setSubject('IDP Paseto')
        ->setClaims([
            'claim' => json_decode($this->claimJSON(), true),
        ])->toString();

    return $response->withJson([
       'public_key_v1' => $publicKeyV1->raw(), 
       'token' => $token
    ]);
Run Code Online (Sandbox Code Playgroud)

NodeJS Paseto Public V1:

const token    = "v1.public.sdsw5vsdf4554...............exampletoken:"; // Example paseto V1 token
const pubKey   = await createPublicKey("-----BEGIN PUBLIC KEY-----\r\npubKeyFromAbovePHP\r\n-----END PUBLIC KEY-----"); // Example public key
const response = await verify(token, pubKey);
Run Code Online (Sandbox Code Playgroud)

这很好用,我可以在 Node.js 中验证我的声明并使用摄取的数据处理我需要的内容。

现在,如果我尝试使用 V2 执行以下操作,调用bin2hex()公钥以便能够存储它并在 Node.js 端使用它,我将无法在 Node.js 中正确验证。我相信它与钠加密二进制密钥的生成有关,以及如何$publicKey->encode()使用Base64UrlSafe::encodeUnpadded($this->key);但我不确定..我从来没有BEGIN PUBLIC KEY从使用 V2 创建的 publicKey 中获得,因为我相信它只是存储为二进制?

PHP Paseto Public V2:

$privateKeyV2 = AsymmetricSecretKey::generate(new Version2()); 
$publicKeyV2  = $privateKeyV2->getPublicKey();

$token = (string) (new Builder())
        ->setKey($privateKeyV2)
        ->setVersion(new Version2())
        ->setPurpose(Purpose::public())
        ->setExpiration((new DateTime())->add(new DateInterval('P01D')))       
        ->setClaims([
            'claim' => json_decode($this->claimJSON(), true),
        ])->toString();

       return $response->withJson([
        'public_key_v2' => bin2hex($publicKeyV2->raw()),
        'token' => $token
       ]);
Run Code Online (Sandbox Code Playgroud)

NodeJS Paseto Public V2:

const pubKey = await createPublicKey(Buffer.from('public_key_from_php_response_above', 'hex'));
const token = 'token_output_from_php_response_above';
const response = await verify(token, pubKey);
console.log(response);
Run Code Online (Sandbox Code Playgroud)

感谢您提供的任何反馈。如果您有任何其他问题,请告诉我。我slim为 PHP 框架标记了这个,因为我在一个瘦项目中使用 PHP paseto 库来存储我的瘦容器等上的公钥/私钥和 lambda 上下文中的 NodeJS。

小智 1

如果有人仍然需要这个答案 - 使用

V2.bytesToKeyObject(publicKey) 
Run Code Online (Sandbox Code Playgroud)

这对我有用。

因此,不要使用加密库的createPublicKey方法,而是使用 paseto V2 的bytesToKeyObject方法来生成密钥以输入 V2.verify。

const { V2 } = require('paseto');

const publicKeyString = Buffer.from('Wxar8cbJRI9flcB', 'base64'); // or 'hex' if that's the encoding you used initially
const pubKey = V2.bytesToKeyObject(publicKeyString);
const payload = await V2.verify(token, publicKey);
Run Code Online (Sandbox Code Playgroud)

就我而言,我使用的是公共 paseto 方案,其中签名者是 Ruby on Rails 应用程序,验证者是下游节点应用程序。

在 Ruby 中,我使用 mguymon 的 paseto gem 创建了公钥/私钥对https://github.com/mguymon/paseto.rb (v2)