josekit
JOSE (Javascript Object Signing and Encryption: JWT, JWS, JWE, JWA, JWK) library based on OpenSSL for Rust.
Install
[dependencies]
josekit = "0.8.7"
This library depends on OpenSSL 1.1.1 or above DLL. Read more about Crate openssl.
Build
sudo apt install build-essential pkg-config libssl-dev
cd josekit-rs
cargo build --release
Supported signing algorithms
Supported encryption algorithms
Supported key formats
Private Key
Public Key
Usage
Signing a JWT by HMAC
HMAC is used to verify the integrity of a message by common secret key.
Three algorithms are available for HMAC: HS256, HS384, and HS512.
You can use any bytes as the key. But the key length must be larger than
or equal to the output hash size.
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";
let signer = HS256.signer_from_bytes(key)?;
let jwt = jwt::encode_with_signer(&payload, &header, &signer)?;
let verifier = HS256.verifier_from_bytes(key)?;
let (payload, header) = jwt::decode_with_verifier(&jwt, &verifier)?;
Ok(())
}
Signing a JWT by RSASSA
RSASSA is used to verify the integrity of a message by two keys: public and private.
Three algorithms are available for RSASSA: RS256, RS384, and RS512.
You can generate the keys by executing openssl command.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem
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");
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)?;
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(())
}
Signing a JWT by RSASSA-PSS
RSASSA-PSS is used to verify the integrity of a message by two keys: public and private.
The raw key format of RSASSA-PSS is the same as RSASSA. So you should use a PKCS#8 wrapped key. It contains some optional attributes.
Three algorithms are available for RSASSA-PSS: PS256, PS384, and PS512.
You can generate the keys by executing openssl command.
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
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
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
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");
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)?;
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(())
}
Signing a JWT by ECDSA
ECDSA is used to verify the integrity of a message by two keys: public and private.
Four algorithms are available for ECDSA: ES256, ES384, ES512 and ES256K.
You can generate the keys by executing openssl command.
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out private.pem
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out private.pem
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521 -out private.pem
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp256k1 -out private.pem
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");
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)?;
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(())
}
Signing a JWT by EdDSA
EdDSA is used to verify the integrity of a message by two keys: public and private.
A algorithm is only available "EdDSA" for EdDSA.
But it has two curve types: Ed25519, Ed448.
You can generate the keys by executing openssl command.
openssl genpkey -algorithm ED25519 -out private.pem
openssl genpkey -algorithm ED448 -out private.pem
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");
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)?;
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(())
}
Encrypting a JWT by a Direct method
A "Direct" method is used to encrypt a message by CEK (content encryption key).
The algorithm name is "dir" only.
You can use any bytes as the key. But the length must be the same as the length of the 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";
let encrypter = Dir.encrypter_from_bytes(key)?;
let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;
let decrypter = Dir.decrypter_from_bytes(key)?;
let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
Ok(())
}
Encrypting a JWT by ECDH-ES
ECDH-ES is used to encrypt a message a message by random bytes as CEK (content encryption key)
and the CEK is delivered safely by two keys: public and private.
Four algorithms are available for ECDH-ES: ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW and ECDH-ES+A256KW.
The types of key are available both EC and ECX.
The EC key has four curve types: P-256, P-384, P-521 and secp256k1.
The ECX key has two curve types: X25519 and X448.
You can generate the keys by executing openssl command.
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out private.pem
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-384 -out private.pem
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-521 -out private.pem
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp256k1 -out private.pem
openssl genpkey -algorithm X25519 -out private.pem
openssl genpkey -algorithm X448 -out private.pem
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");
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)?;
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(())
}
Encrypting a JWT by AESKW
AES is used to encrypt a message by random bytes as CEK (content encryption key)
and the CEK is wrapping by common secret key.
Three algorithms are available for AES: A128KW, A192KW and A256KW.
You can use any bytes as the key. But the length must be AES key size.
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";
let encrypter = A128KW.encrypter_from_bytes(key)?;
let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;
let decrypter = A128KW.decrypter_from_bytes(key)?;
let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
Ok(())
}
Encrypting a JWT by AES-GCM
AES-GCM is used to encrypt a message by random bytes as CEK (content encryption key)
and the CEK is wrapping by common secret key.
Three algorithms are available for AES-GCM: A128GCMKW, A192GCMKW and A256GCMKW.
You can use any bytes as the key. But the length must be AES key size.
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";
let encrypter = A128GCMKW.encrypter_from_bytes(key)?;
let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;
let decrypter = A128GCMKW.decrypter_from_bytes(key)?;
let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
Ok(())
}
Encrypting a JWT by PBES2-HMAC+AESKW
PBES2-HMAC+AES is used to encrypt a message by random bytes as CEK (content encryption key)
and the CEK is wrapping by common secret key.
Three algorithms are available for AES-GCM: PBES2-HS256+A128KW, PBES2-HS384+A192KW and PBES2-HS512+A256KW.
You can use any bytes as the key. But a password is recommended that the length is no shorter
than AES key size and no longer than 128 octets.
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";
let encrypter = PBES2_HS256_A128KW.encrypter_from_bytes(key)?;
let jwt = jwt::encode_with_encrypter(&payload, &header, &encrypter)?;
let decrypter = PBES2_HS256_A128KW.decrypter_from_bytes(key)?;
let (payload, header) = jwt::decode_with_decrypter(&jwt, &decrypter)?;
Ok(())
}
Encrypting a JWT by RSAES
RSAES is used to encrypt a message a message by random bytes as CEK (content encryption key)
and the CEK is delivered safely by two keys: public and private.
Two algorithms are available for now: RSA1_5, RSA-OAEP.
You can generate the keys by executing openssl command.
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem
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");
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)?;
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(())
}
Unsecured 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(())
}
Validate payload
use josekit::{JoseError, jwt::{JwtPayload, JwtPayloadValidator}};
use std::time::{Duration, SystemTime};
fn main() -> Result<(), JoseError> {
let mut validator = JwtPayloadValidator::new();
validator.set_issuer("http://example.com");
validator.set_audience("user1");
validator.set_jwt_id("550e8400-e29b-41d4-a716-446655440000");
validator.set_base_time(SystemTime::now() + Duration::from_secs(30));
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(())
}
License
Licensed under either of
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
References