#加密密钥 #jwt #jws #jose #jwe #jwa

josekit

基于Rust的JOSE (JavaScript对象签名和加密) 库

19 个版本

0.8.7 2024年7月22日
0.8.6 2024年3月16日
0.8.5 2024年1月10日
0.8.4 2023年10月8日
0.6.0 2020年10月13日

#11 in 身份验证

Download history 10714/week @ 2024-05-03 11286/week @ 2024-05-10 11510/week @ 2024-05-17 10409/week @ 2024-05-24 12690/week @ 2024-05-31 13667/week @ 2024-06-07 11697/week @ 2024-06-14 11988/week @ 2024-06-21 10954/week @ 2024-06-28 13352/week @ 2024-07-05 12531/week @ 2024-07-12 15505/week @ 2024-07-19 14709/week @ 2024-07-26 17252/week @ 2024-08-02 14460/week @ 2024-08-09 14458/week @ 2024-08-16

63,554 每月下载量
12 crates 中使用

MIT/Apache

740KB
17K SLoC

josekit

基于OpenSSL的Rust库,提供JWT、JWS、JWE、JWA、JWK等JOSE (JavaScript Object Signing and Encryption) 功能。

安装

[dependencies]
josekit = "0.8.7"

此库依赖于OpenSSL 1.1.1或更高版本的DLL。更多关于Crate openssl的信息。

构建

sudo apt install build-essential pkg-config libssl-dev
cd josekit-rs
cargo build --release

支持的签名算法

名称 描述 密钥类型
HS256 使用SHA-256的HMAC oct (大小:32字节或更多)
HS384 使用SHA-384的HMAC oct (大小:48字节或更多)
HS512 使用SHA-512的HMAC oct (大小:64字节或更多)
RS256 使用SHA-256的RSASSA-PKCS1-v1_5 RSA (大小:1024位或更多)
RS384 使用SHA-384的RSASSA-PKCS1-v1_5
RS512 使用SHA-512的RSASSA-PKCS1-v1_5
PS256 使用SHA-256和MGF1使用SHA-256的RSASSA-PSS
PS384 使用SHA-384和MGF1使用SHA-384的RSASSA-PSS
PS512 使用SHA-512和MGF1使用SHA-512的RSASSA-PSS
ES256 使用P-256和SHA-256的ECDSA EC (曲线:P-256)
ES384 使用P-384和SHA-384的ECDSA EC (曲线:P-384)
ES512 使用P-521和SHA-512的ECDSA EC (曲线:P-521)
ES256K 使用secp256k1曲线和SHA-256的ECDSA EC (曲线:secp256k1)
EdDSA EdDSA签名算法 OKP (曲线:Ed25519或Ed448)
none 不执行数字签名或MAC -

支持的加密算法

名称 描述 密钥类型
dir 直接使用共享对称密钥作为CEK oct (大小:CEK取决于。见下文)
  • A128CBC-HS256: 32字节
  • A192CBC-HS384: 48字节
  • A256CBC-HS512: 64字节
  • A128GCM: 16字节
  • A192GCM: 24字节
  • A256GCM: 32字节
ECDH-ES 使用Concat KDF的椭圆曲线Diffie-Hellman Ephemeral Static密钥协商 EC (曲线:P-256, P-384, P-521或secp256k1)
OKP (曲线:X25519或X448)
ECDH-ES+A128KW 使用Concat KDF和"A128KW"包装CEK的ECDH-ES
ECDH-ES+A192KW 使用Concat KDF和"A192KW"包装CEK的ECDH-ES
ECDH-ES+A256KW 使用Concat KDF和"A256KW"包装CEK的ECDH-ES
A128KW 使用默认初始值的128位密钥的AES Key Wrap oct (大小:16字节)
A192KW 使用默认初始值和192位密钥的AES密钥封装 oct (大小:24字节)
A256KW 使用默认初始值和256位密钥的AES密钥封装 oct (大小:32字节)
A128GCMKW 使用128位密钥的AES GCM密钥封装 oct (大小:16字节)
A192GCMKW 使用192位密钥的AES GCM密钥封装 oct (大小:24字节)
A256GCMKW 使用256位密钥的AES GCM密钥封装 oct (大小:32字节)
PBES2-HS256+A128KW PBES2使用HMAC SHA-256和"A128KW"封装 oct (大小:1字节或更多)
PBES2-HS384+A192KW PBES2使用HMAC SHA-384和"A192KW"封装
PBES2-HS512+A256KW PBES2使用HMAC SHA-512和"A256KW"封装
RSA1_5 RSAES-PKCS1-v1_5 RSA (大小:1024位或更多)
RSA-OAEP RSAES OAEP使用默认参数
RSA-OAEP-256 RSAES OAEP使用SHA-256和MGF1使用SHA-256
RSA-OAEP-384 RSAES OAEP使用SHA-384和MGF1使用SHA-384
RSA-OAEP-512 RSAES OAEP使用SHA-512和MGF1使用SHA-512

支持的关键格式

私钥

算法 JWK PEM DER
PKCS#8 传统 PKCS#8 原始
RSA OK OK OK OK OK
RSA-PSS OK OK OK OK OK
EC OK OK OK OK OK
ED OK OK OK OK -
ECX OK OK OK OK -

公钥

算法 JWK PEM DER
SPKI 传统 SPKI 原始
RSA OK OK OK OK OK
RSA-PSS OK OK OK OK OK
EC OK OK - OK -
ED OK OK - OK -
ECX OK OK - OK -

用途

使用HMAC签名JWT

HMAC通过常用密钥验证消息的完整性。HMAC有三种算法:HS256、HS384和HS512。

您可以使用任何字节作为密钥。但密钥长度必须大于或等于输出哈希大小。

use josekit::{JoseError, jws::{JwsHeader, HS256}, jwt::{self, JwtPayload}};

fn main() -> Result<(), JoseError> {
    let mut header = JwsHeader::new();
    header.set_token_type("JWT");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    let key = b"0123456789ABCDEF0123456789ABCDEF";

    // Signing JWT
    let signer = HS256.signer_from_bytes(key)?;
    let jwt = jwt::encode_with_signer(&payload, &header, &signer)?;

    // Verifing JWT
    let verifier = HS256.verifier_from_bytes(key)?;
    let (payload, header) = jwt::decode_with_verifier(&jwt, &verifier)?;

    Ok(())
}

使用RSASSA签名JWT

RSASSA使用两个密钥(公钥和私钥)验证消息的完整性。RSASSA有三种算法:RS256、RS384和RS512。

您可以通过执行openssl命令生成密钥。

# Generate a new private key. Keygen bits must be 2048 or more.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem

# Generate a public key from the private key.
openssl pkey -in private.pem -pubout -out public.pem
use josekit::{JoseError, jws::{JwsHeader, RS256}, jwt::{self, JwtPayload}};

const PRIVATE_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/RSA_2048bit_private.pem");
const PUBLIC_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/RSA_2048bit_public.pem");

fn main() -> Result<(), JoseError> {
    let mut header = JwsHeader::new();
    header.set_token_type("JWT");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    // Signing JWT
    let private_key = std::fs::read(PRIVATE_KEY).unwrap();
    let signer = RS256.signer_from_pem(&private_key)?;
    let jwt = jwt::encode_with_signer(&payload, &header, &signer)?;

    // Verifing JWT
    let public_key = std::fs::read(PUBLIC_KEY).unwrap();
    let verifier = RS256.verifier_from_pem(&public_key)?;
    let (payload, header) = jwt::decode_with_verifier(&jwt, &verifier)?;
    
    Ok(())
}

使用RSASSA-PSS签名JWT

RSASSA-PSS使用两个密钥(公钥和私钥)验证消息的完整性。

RSASSA-PSS的原始密钥格式与RSASSA相同。因此,您应使用PKCS#8封装的密钥。它包含一些可选属性。

RSASSA-PSS有三种算法:PS256、PS384和PS512。您可以通过执行openssl命令生成密钥。

# Generate a new private key

# for PS256
openssl genpkey -algorithm RSA-PSS -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_pss_keygen_md:sha256 -pkeyopt rsa_pss_keygen_mgf1_md:sha256 -pkeyopt rsa_pss_keygen_saltlen:32 -out private.pem

# for PS384
openssl genpkey -algorithm RSA-PSS -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_pss_keygen_md:sha384 -pkeyopt rsa_pss_keygen_mgf1_md:sha384 -pkeyopt rsa_pss_keygen_saltlen:48 -out private.pem

# for PS512
openssl genpkey -algorithm RSA-PSS -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_pss_keygen_md:sha512 -pkeyopt rsa_pss_keygen_mgf1_md:sha512 -pkeyopt rsa_pss_keygen_saltlen:64 -out private.pem

# Generate a public key from the private key.
openssl pkey -in private.pem -pubout -out public.pem
use josekit::{JoseError, jws::{JwsHeader, PS256}, jwt::{self, JwtPayload}};

const PRIVATE_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/RSA-PSS_2048bit_SHA-256_private.pem");
const PUBLIC_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/RSA-PSS_2048bit_SHA-256_public.pem");

fn main() -> Result<(), JoseError> {
    let mut header = JwsHeader::new();
    header.set_token_type("JWT");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    // Signing JWT
    let private_key = std::fs::read(PRIVATE_KEY).unwrap();
    let signer = PS256.signer_from_pem(&private_key)?;
    let jwt = jwt::encode_with_signer(&payload, &header, &signer)?;

    // Verifing JWT
    let public_key = std::fs::read(PUBLIC_KEY).unwrap();
    let verifier = PS256.verifier_from_pem(&public_key)?;
    let (payload, header) = jwt::decode_with_verifier(&jwt, &verifier)?;

    Ok(())
}

使用ECDSA签名JWT

ECDSA使用两个密钥(公钥和私钥)验证消息的完整性。ECDSA有四种算法:ES256、ES384、ES512和ES256K。

您可以通过执行openssl命令生成密钥。

# Generate a new private key

# for ES256
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out private.pem

# for ES384
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out private.pem

# for ES512
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521 -out private.pem

# for ES256K
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp256k1 -out private.pem

# Generate a public key from the private key.
openssl pkey -in private.pem -pubout -out public.pem
use josekit::{JoseError, jws::{JwsHeader, ES256}, jwt::{self, JwtPayload}};

const PRIVATE_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/EC_P-256_private.pem");
const PUBLIC_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/EC_P-256_public.pem");

fn main() -> Result<(), JoseError> {
    let mut header = JwsHeader::new();
    header.set_token_type("JWT");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    // Signing JWT
    let private_key = std::fs::read(PRIVATE_KEY).unwrap();
    let signer = ES256.signer_from_pem(&private_key)?;
    let jwt = jwt::encode_with_signer(&payload, &header, &signer)?;

    // Verifing JWT
    let public_key = std::fs::read(PUBLIC_KEY).unwrap();
    let verifier = ES256.verifier_from_pem(&public_key)?;
    let (payload, header) = jwt::decode_with_verifier(&jwt, &verifier)?;

    Ok(())
}

使用EdDSA签名JWT

EdDSA使用两个密钥(公钥和私钥)验证消息的完整性。EdDSA只有一个算法“EdDSA”。但它有两种曲线类型:Ed25519和Ed448。

您可以通过执行openssl命令生成密钥。

# Generate a new private key

# for Ed25519
openssl genpkey -algorithm ED25519 -out private.pem

# for Ed448
openssl genpkey -algorithm ED448 -out private.pem

# Generate a public key from the private key.
openssl pkey -in private.pem -pubout -out public.pem
use josekit::{JoseError, jws::{JwsHeader, EdDSA}, jwt::{self, JwtPayload}};

const PRIVATE_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/ED25519_private.pem");
const PUBLIC_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/ED25519_public.pem");

fn main() -> Result<(), JoseError> {
    let mut header = JwsHeader::new();
    header.set_token_type("JWT");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    // Signing JWT
    let private_key = std::fs::read(PRIVATE_KEY).unwrap();
    let signer = EdDSA.signer_from_pem(&private_key)?;
    let jwt = jwt::encode_with_signer(&payload, &header, &signer)?;

    // Verifing JWT
    let public_key = std::fs::read(PUBLIC_KEY).unwrap();
    let verifier = EdDSA.verifier_from_pem(&public_key)?;
    let (payload, header) = jwt::decode_with_verifier(&jwt, &verifier)?;

    Ok(())
}

使用直接方法加密JWT

“直接”方法通过CEK(内容加密密钥)加密消息。算法名称仅为“dir”。

您可以使用任何字节作为密钥。但长度必须与CEK的长度相同。

use josekit::{JoseError, jwe::{JweHeader, Dir}, jwt::{self, JwtPayload}};

fn main() -> Result<(), JoseError> {
    let mut header = JweHeader::new();
    header.set_token_type("JWT");
    header.set_content_encryption("A128CBC-HS256");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    let key = b"0123456789ABCDEF0123456789ABCDEF";

    // Encrypting JWT
    let encrypter = Dir.encrypter_from_bytes(key)?;
    let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;

    // Decrypting JWT
    let decrypter = Dir.decrypter_from_bytes(key)?;
    let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;

    Ok(())
}

使用ECDH-ES加密JWT

ECDH-ES通过随机字节作为CEK(内容加密密钥)加密消息,并通过两个密钥(公钥和私钥)安全地传递CEK。ECDH-ES有四种算法:ECDH-ES、ECDH-ES+A128KW、ECDH-ES+A192KW和ECDH-ES+A256KW。

密钥类型既可以是EC也可以是ECX。EC密钥有四种曲线类型:P-256、P-384、P-521和secp256k1。ECX密钥有两种曲线类型:X25519和X448。

您可以通过执行openssl命令生成密钥。

# Generate a new private key

# for P-256 EC key
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out private.pem

# for P-384 EC key
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out private.pem

# for P-521 EC key
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521 -out private.pem

# for secp256k1 EC key
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp256k1 -out private.pem

# for X25519 ECX key
openssl genpkey -algorithm X25519 -out private.pem

# for X448 ECX key
openssl genpkey -algorithm X448 -out private.pem

# Generate a public key from the private key.
openssl pkey -in private.pem -pubout -out public.pem
use josekit::{JoseError, jwe::{JweHeader, ECDH_ES}, jwt::{self, JwtPayload}};

const PRIVATE_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/EC_P-256_private.pem");
const PUBLIC_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/EC_P-256_public.pem");

fn main() -> Result<(), JoseError> {
    let mut header = JweHeader::new();
    header.set_token_type("JWT");
    header.set_content_encryption("A128CBC-HS256");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    // Encrypting JWT
    let public_key = std::fs::read(PUBLIC_KEY).unwrap();
    let encrypter = ECDH_ES.encrypter_from_pem(&public_key)?;
    let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;

    // Decrypting JWT
    let private_key = std::fs::read(PRIVATE_KEY).unwrap();
    let decrypter = ECDH_ES.decrypter_from_pem(&private_key)?;
    let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;

    Ok(())
}

使用AESKW加密JWT

AES通过随机字节作为CEK(内容加密密钥)加密消息,并通过常用密钥封装CEK。AES有三种算法:A128KW、A192KW和A256KW。

您可以使用任何字节作为密钥。但长度必须是AES密钥大小。

use josekit::{JoseError, jwe::{JweHeader, A128KW}, jwt::{self, JwtPayload}};

fn main() -> Result<(), JoseError> {
    let mut header = JweHeader::new();
    header.set_token_type("JWT");
    header.set_content_encryption("A128CBC-HS256");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    let key = b"0123456789ABCDEF";

    // Encrypting JWT
    let encrypter = A128KW.encrypter_from_bytes(key)?;
    let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;

    // Decrypting JWT
    let decrypter = A128KW.decrypter_from_bytes(key)?;
    let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
    Ok(())
}

使用AES-GCM加密JWT

AES-GCM用于通过随机字节作为CEK(内容加密密钥)加密消息,CEK通过通用密钥进行封装。AES-GCM提供了三种算法:A128GCMKW、A192GCMKW和A256GCMKW。

您可以使用任何字节作为密钥。但长度必须是AES密钥大小。

use josekit::{JoseError, jwe::{JweHeader, A128GCMKW}, jwt::{self, JwtPayload}};

fn main() -> Result<(), JoseError> {
    let mut header = JweHeader::new();
    header.set_token_type("JWT");
    header.set_content_encryption("A128CBC-HS256");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    let key = b"0123456789ABCDEF";

    // Encrypting JWT
    let encrypter = A128GCMKW.encrypter_from_bytes(key)?;
    let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;

    // Decrypting JWT
    let decrypter = A128GCMKW.decrypter_from_bytes(key)?;
    let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
    Ok(())
}

使用PBES2-HMAC+AESKW加密JWT

PBES2-HMAC+AES通过随机字节作为CEK(内容加密密钥)加密消息,CEK通过通用密钥进行封装。AES-GCM提供了三种算法:PBES2-HS256+A128KW、PBES2-HS384+A192KW和PBES2-HS512+A256KW。

您可以使用任何字节作为密钥。但建议使用密码,长度不短于AES密钥大小,不长于128个八进制字节。

use josekit::{JoseError, jwe::{JweHeader, PBES2_HS256_A128KW}, jwt::{self, JwtPayload}};

fn main() -> Result<(), JoseError> {
    let mut header = JweHeader::new();
    header.set_token_type("JWT");
    header.set_content_encryption("A128CBC-HS256");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    let key = b"01234567";

    // Encrypting JWT
    let encrypter = PBES2_HS256_A128KW.encrypter_from_bytes(key)?;
    let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;

    // Decrypting JWT
    let decrypter = PBES2_HS256_A128KW.decrypter_from_bytes(key)?;
    let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
    Ok(())
}

使用RSAES加密JWT

RSAES通过随机字节作为CEK(内容加密密钥)加密消息,CEK通过两个密钥安全地传递:公钥和私钥。目前提供了两种算法:RSA1_5和RSA-OAEP。

您可以通过执行openssl命令生成密钥。

# Generate a new private key. Keygen bits must be 2048 or more.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem

# Generate a public key from the private key.
openssl pkey -in private.pem -pubout -out public.pem
use josekit::{JoseError, jwe::{JweHeader, RSA_OAEP}, jwt::{self, JwtPayload}};

const PRIVATE_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/RSA_2048bit_private.pem");
const PUBLIC_KEY: &str = concat!(env!("CARGO_MANIFEST_DIR"), 
    "/data/pem/RSA_2048bit_public.pem");

fn main() -> Result<(), JoseError> {
    let mut header = JweHeader::new();
    header.set_token_type("JWT");
    header.set_content_encryption("A128CBC-HS256");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    // Encrypting JWT
    let public_key = std::fs::read(PUBLIC_KEY).unwrap();
    let encrypter = RSA_OAEP.encrypter_from_pem(&public_key)?;
    let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;

    // Decrypting JWT
    let private_key = std::fs::read(PRIVATE_KEY).unwrap();
    let decrypter = RSA_OAEP.decrypter_from_pem(&private_key)?;
    let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
    Ok(())
}

未加密的JWT

use josekit::{JoseError, jws::JwsHeader, jwt::{self, JwtPayload}};

fn main() -> Result<(), JoseError> {
    let mut header = JwsHeader::new();
    header.set_token_type("JWT");

    let mut payload = JwtPayload::new();
    payload.set_subject("subject");

    let jwt = jwt::encode_unsecured(&payload, &header)?;
    let (payload, header) = jwt::decode_unsecured(&jwt)?;
    Ok(())
}

验证负载

use josekit::{JoseError, jwt::{JwtPayload, JwtPayloadValidator}};
use std::time::{Duration, SystemTime};

fn main() -> Result<(), JoseError> {
    let mut validator = JwtPayloadValidator::new();
    // value based validation
    validator.set_issuer("http://example.com");
    validator.set_audience("user1");
    validator.set_jwt_id("550e8400-e29b-41d4-a716-446655440000");

    // time based validation: not_before <= base_time < expires_at
    validator.set_base_time(SystemTime::now() + Duration::from_secs(30));

    // issued time based validation: min_issued_time <= issued_time <= max_issued_time
    validator.set_min_issued_time(SystemTime::now() - Duration::from_secs(48 * 60));
    validator.set_max_issued_time(SystemTime::now() + Duration::from_secs(24 * 60));

    let mut payload = JwtPayload::new();

    validator.validate(&payload)?;

    Ok(())
}

许可

在以下任一许可下发布:

任选其一。

贡献

除非您明确声明,否则根据Apache-2.0许可定义的您有意提交的任何贡献,均应作为上述双重许可,没有任何附加条款或条件。

参考文献

依赖关系

~6.5–9.5MB
~181K SLoC