JWT 筆記(二)--演算法

JWT 的加密與雜湊演算法選擇,可以參考 RFC 7518

“alg” Value Digital Signature or MAC Algorithm Implementation Requirements
HS256 HMAC using SHA-256 Required
HS384 HMAC using SHA-384 Optional
HS512 HMAC using SHA-512 Optional
RS256 RSASSA-PKCS1-v1_5 using SHA-256 Recommended
RS384 RSASSA-PKCS1-v1_5 using SHA-384 Optional
RS512 RSASSA-PKCS1-v1_5 using SHA-512 Optional
ES256 ECDSA using P-256 and SHA-256 Recommended+
ES384 ECDSA using P-384 and SHA-384 Optional
ES512 ECDSA using P-521 and SHA-512 Optional
PS256 RSASSA-PSS using SHA-256 and MGF1 with SHA-256 Optional
PS384 RSASSA-PSS using SHA-384 and MGF1 with SHA-384 Optional
PS512 RSASSA-PSS using SHA-512 and MGF1 with SHA-512 Optional
none No digital signature or MAC performed Optional

Terms

老實說,這裡有很多不清楚的名詞,今天來查查吧!

  • 非對稱性加密 - 使用兩把金鑰來做加解密,公鑰 public key 加密,私鑰 private key 解密,也因此稱為「非對稱」
  • 對稱性加密 - 使用同一把金鑰 secret 來做加解密
  • MAC - Message authentication code ,參考 wiki :這在密碼學中,是指一小段資訊。它可以用特定演算法,從原有的一包資訊來產生,目的是確定原本的資訊沒有被更改過。
  • HMAC - Hash-based Message Authentication Code ,這是加上 secret 來產生 MAC 的方法。此演算法的公式可以在 RFC 2104 裡找到
  • RSA - 一種非對稱性加密演算法
  • RSASSA-PKCS1-v1_5 - 指的是 Section 8.2 of RFC 3447
  • RSASSA-PSS - 指的是 Section 8.1 of RFC 3447
  • ECDSA - The Elliptic Curve Digital Signature Algorithm

如何產 key

因需求,應該會使用 RS256ES256,接下來來看 key 如何產

RS256

RFC 裡提到了

A key of size 2048 bits or larger MUST be used with these algorithms.

必須要 2048 bits 以上的 key,來參考別人怎麼產

# generate private key
openssl genrsa -out rs256-private.pem 2048

# extatract public key from it
openssl rsa -in rs256-private.pem -pubout > rs256-public.pem

ES256

RFC

參考 Google 的說明

# generate private key
openssl ecparam -genkey -name prime256v1 -noout -out es256-private.pem

# extatract public key from it
openssl ec -in es256-private.pem -pubout -out es256-public.pem

驗證方法

使用 PHP,如果要使用 ES256 需先安裝 gmp

Debian 系列:

apt-get install libgmp-dev

CentOS 系列:

yum install gmp-devel

Alpine 系列:

apk add gmp-dev

PHP 測試程式碼,使用 lcobucci/jwt 套件

<?php

use Lcobucci\JWT\Signer\Ecdsa;
use Lcobucci\JWT\Signer\Rsa;

include 'vendor/autoload.php';

$signer = Ecdsa\Sha256::create();

$privateKey = file_get_contents(__DIR__ . '/es256-private.pem');
$publicKey = file_get_contents(__DIR__ . '/es256-public.pem');

$signature = $signer->sign('something', new \Lcobucci\JWT\Signer\Key($privateKey));
$isValid = $signer->verify($signature, 'something', new \Lcobucci\JWT\Signer\Key($publicKey));

echo ($isValid ? 'OK' : 'fail') . PHP_EOL;

$signer = new Rsa\Sha256();

$privateKey = file_get_contents(__DIR__ . '/rs256-private.pem');
$publicKey = file_get_contents(__DIR__ . '/rs256-public.pem');

$signature = $signer->sign('something', new \Lcobucci\JWT\Signer\Key($privateKey));
$isValid = $signer->verify($signature, 'something', new \Lcobucci\JWT\Signer\Key($publicKey));

echo ($isValid ? 'OK' : 'fail') . PHP_EOL;