1
0
mirror of https://github.com/BitskiCo/jwk-rs synced 2024-11-22 03:49:22 +00:00

Add key generation

This commit is contained in:
Nick Hynes 2020-07-13 23:07:02 +00:00
parent fa22e01714
commit ddb2613c4e
No known key found for this signature in database
GPG Key ID: 5B3463E9F1D73C83
4 changed files with 102 additions and 31 deletions

View File

@ -14,7 +14,9 @@ bitflags = "1.2"
derive_more = "0.99" derive_more = "0.99"
jsonwebtoken = { version = "7.2", optional = true } jsonwebtoken = { version = "7.2", optional = true }
num-bigint = { version = "0.2", optional = true } num-bigint = { version = "0.2", optional = true }
p256 = { version = "0.3", optional = true }
paste = "0.1" paste = "0.1"
rand = { version = "0.7", optional = true }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
syn = { version = "1.0", features = ["full"] } # required to parse const generics syn = { version = "1.0", features = ["full"] } # required to parse const generics
@ -24,6 +26,7 @@ zeroize = { version = "1.1", features = ["zeroize_derive"] }
[features] [features]
convert = ["num-bigint", "yasna"] convert = ["num-bigint", "yasna"]
generate = ["p256", "rand"]
[dev-dependencies] [dev-dependencies]
jsonwebtoken = "7.2" jsonwebtoken = "7.2"

View File

@ -40,4 +40,6 @@ fn main() {
* `convert` - enables `Key::{to_der, to_pem}`. * `convert` - enables `Key::{to_der, to_pem}`.
This pulls in the [yasna](https://crates.io/crates/yasna) crate. This pulls in the [yasna](https://crates.io/crates/yasna) crate.
* `generate` - enables `Key::{generate_p256, generate_symmetric}`.
This pulls in the [p256](https://crates.io/crates/p256) and [rand](https://crates.io/crates/rand) crates.
* `jsonwebtoken` - enables conversions to types in the [jsonwebtoken](https://crates.io/crates/jsonwebtoken) crate. * `jsonwebtoken` - enables conversions to types in the [jsonwebtoken](https://crates.io/crates/jsonwebtoken) crate.

View File

@ -200,9 +200,12 @@ impl Key {
pkcs8::write_private(oids, |writer: &mut DERWriterSeq| { pkcs8::write_private(oids, |writer: &mut DERWriterSeq| {
writer.next().write_i8(1); // version writer.next().write_i8(1); // version
writer.next().write_bytes(private_point.as_slice()); writer.next().write_bytes(private_point.as_slice());
writer.next().write_tagged(Tag::context(0), |writer| { // The following tagged value is optional. OpenSSL produces it,
writer.write_oid(&prime256v1_oid) // but many tools, including jwt.io and `jsonwebtoken`, don't like it,
}); // so we don't include it.
// writer.next().write_tagged(Tag::context(0), |writer| {
// writer.write_oid(&prime256v1_oid)
// });
writer.next().write_tagged(Tag::context(1), write_public); writer.next().write_tagged(Tag::context(1), write_public);
}) })
} }
@ -286,6 +289,45 @@ impl Key {
writeln!(&mut pem, "-----END {} KEY-----", key_ty).unwrap(); writeln!(&mut pem, "-----END {} KEY-----", key_ty).unwrap();
Ok(pem) Ok(pem)
} }
/// Generates a new symmetric key with the specified number of bits.
/// Best used with one of the HS algorithms (e.g., HS256).
#[cfg(feature = "generate")]
pub fn generate_symmetric(num_bits: usize) -> Self {
use rand::RngCore;
let mut bytes = Vec::with_capacity(num_bits / 8);
rand::thread_rng().fill_bytes(&mut bytes);
Self::Symmetric { key: bytes.into() }
}
/// Generates a new EC keypair using the prime256 curve.
/// Used with the ES256 algorithm.
#[cfg(feature = "generate")]
pub fn generate_p256() -> Self {
use p256::elliptic_curve::generic_array::GenericArray;
use rand::RngCore;
let mut sk_bytes = GenericArray::default();
rand::thread_rng().fill_bytes(&mut sk_bytes);
let sk = p256::SecretKey::new(sk_bytes);
let sk_scalar = p256::arithmetic::Scalar::from_secret(sk).unwrap();
let pk = p256::arithmetic::ProjectivePoint::generator() * &sk_scalar;
let pk_bytes = &pk
.to_affine()
.unwrap()
.to_uncompressed_pubkey()
.into_bytes()[1..];
let (x_bytes, y_bytes) = pk_bytes.split_at(32);
Self::EC {
curve: Curve::P256 {
d: Some(sk_scalar.to_bytes().into()),
x: ByteArray::try_from_slice(x_bytes).unwrap(),
y: ByteArray::try_from_slice(y_bytes).unwrap(),
},
}
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]

View File

@ -85,6 +85,32 @@ fn serialize_es256() {
); );
} }
#[cfg(feature = "generate")]
#[test]
fn generate_p256() {
extern crate jsonwebtoken as jwt;
#[derive(Serialize, Deserialize)]
struct TokenClaims {}
let mut the_jwk = JsonWebKey::new(Key::generate_p256());
the_jwk.set_algorithm(JsonWebAlgorithm::ES256).unwrap();
let encoding_key = jwt::EncodingKey::from_ec_der(&the_jwk.key.to_der().unwrap());
let token = jwt::encode(
&jwt::Header::new(the_jwk.algorithm.unwrap().into()),
&TokenClaims {},
&encoding_key,
)
.unwrap();
let mut validation = jwt::Validation::new(the_jwk.algorithm.unwrap().into());
validation.validate_exp = false;
let public_pem = the_jwk.key.to_public().unwrap().to_pem().unwrap();
let decoding_key = jwt::DecodingKey::from_ec_pem(public_pem.as_bytes()).unwrap();
jwt::decode::<TokenClaims>(&token, &decoding_key, &validation).unwrap();
}
#[test] #[test]
fn deserialize_hs256() { fn deserialize_hs256() {
let jwk_str = r#"{ let jwk_str = r#"{
@ -136,66 +162,65 @@ fn deserialize_rs256() {
public: RsaPublic { public: RsaPublic {
e: PublicExponent, e: PublicExponent,
n: vec![ n: vec![
149, 122, 70, 152, 26, 8, 198, 62, 122, 78, 154, 109, 2, 150, 154, 115, 164, 44, 219, 113, 223, 100, 142, 248, 57, 173, 241, 135, 116, 67, 22, 157,
165, 117, 247, 254, 214, 89, 186, 180, 107, 94, 26, 229, 65, 193, 6, 89, 122, 56, 247, 54, 193, 232, 82, 208, 250, 109, 1, 208, 27, 213, 167, 70,
28, 231, 131, 112, 33, 70, 182, 95, 138, 125, 57, 226, 182, 179, 46, 171, 168, 141, 85, 152, 107, 76, 110, 140, 47, 153, 63, 182, 97, 196, 28, 143,
45, 15, 245, 131, 80, 28, 75, 7, 236, 85, 76, 188, 48, 255, 145, 139 199, 39, 54, 61, 172, 240, 20, 146, 98, 246, 43, 217, 254, 8, 17, 195
] ]
.into() .into()
}, },
private: Some(RsaPrivate { private: Some(RsaPrivate {
d: vec![ d: vec![
94, 141, 21, 0, 123, 95, 87, 127, 7, 192, 150, 192, 35, 165, 254, 22, 238, 65, 218, 124, 107, 192, 223, 229, 57, 76, 105, 169, 104, 92, 10, 77, 23,
239, 187, 42, 16, 142, 123, 162, 74, 84, 33, 113, 40, 241, 159, 64, 89, 253, 222, 187, 203, 11, 28, 213, 155, 93, 216, 59, 209, 238, 88, 85, 48,
124, 179, 255, 12, 172, 93, 39, 96, 13, 129, 49, 149, 19, 76, 118, 227, 44, 209, 101, 31, 104, 135, 249, 115, 121, 253, 233, 26, 195, 12, 12, 230,
118, 7, 170, 21, 145, 28, 186, 27, 110, 96, 220, 157, 75, 140, 57 48, 76, 32, 42, 114, 123, 3, 83, 73, 244, 217, 115, 207, 134, 116, 1
] ]
.into(), .into(),
p: Some( p: Some(
vec![ vec![
252, 180, 162, 167, 154, 56, 121, 161, 159, 219, 155, 175, 195, 37, 42, 232, 4, 56, 200, 119, 159, 215, 182, 167, 254, 46, 75, 64, 241, 205,
246, 230, 209, 180, 167, 166, 172, 38, 168, 11, 27, 166, 162, 62, 183, 35, 28, 233, 31, 174, 113, 88, 228, 159, 254, 160, 129, 238, 175, 165,
2, 237 95, 35
] ]
.into() .into()
), ),
q: Some( q: Some(
vec![ vec![
151, 109, 34, 46, 152, 156, 17, 109, 238, 141, 173, 25, 131, 108, 79, 181, 37, 95, 165, 231, 194, 177, 253, 98, 90, 96, 44, 215, 54, 47, 197,
232, 56, 217, 107, 206, 155, 15, 130, 16, 223, 1, 87, 9, 194, 130, 127, 209, 44, 82, 43, 244, 84, 193, 46, 64, 27, 91, 78, 40, 227, 252, 225
87
] ]
.into() .into()
), ),
dp: Some( dp: Some(
vec![ vec![
250, 76, 172, 195, 23, 149, 18, 156, 140, 235, 7, 84, 219, 20, 104, 169, 89, 203, 136, 167, 168, 72, 111, 206, 151, 61, 123, 56, 96, 70,
110, 239, 135, 12, 201, 245, 227, 147, 210, 100, 86, 58, 1, 127, 222, 119, 134, 182, 178, 165, 69, 158, 184, 225, 255, 157, 112, 185, 164, 3,
227, 173 117, 57
] ]
.into() .into()
), ),
dq: Some( dq: Some(
vec![ vec![
58, 163, 22, 19, 121, 33, 38, 86, 173, 131, 203, 62, 15, 248, 71, 81, 24, 191, 196, 115, 172, 88, 131, 108, 245, 21, 23, 242, 200, 108, 148,
35, 130, 126, 14, 185, 88, 222, 2, 238, 120, 52, 94, 33, 38, 43, 109 214, 88, 31, 208, 18, 69, 77, 151, 31, 52, 143, 8, 72, 131, 121, 178,
193
] ]
.into() .into()
), ),
qi: Some( qi: Some(
vec![ vec![
218, 108, 192, 105, 42, 251, 35, 80, 247, 188, 59, 78, 133, 181, 138, 105, 216, 80, 28, 127, 8, 25, 113, 95, 44, 67, 39, 103, 155, 127, 77,
75, 223, 189, 16, 180, 71, 41, 176, 7, 207, 135, 97, 159, 128, 210, 8, 224, 169, 231, 56, 18, 193, 9, 45, 39, 105, 102, 202, 92, 84, 27, 67
26
] ]
.into() .into()
) )
}) })
}, },
algorithm: Some(JsonWebAlgorithm::RS256), algorithm: None,
key_id: None, key_id: None,
key_ops: KeyOps::empty(), key_ops: KeyOps::empty(),
key_use: None, key_use: Some(KeyUse::Encryption),
} }
); );
} }
@ -273,10 +298,9 @@ fn p256_private_to_pem() {
assert_eq!( assert_eq!(
jwk.key.to_pem().unwrap(), jwk.key.to_pem().unwrap(),
"-----BEGIN PRIVATE KEY----- "-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgZoKQ9j4dhIBlMRVr MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgZoKQ9j4dhIBlMRVr
v+QG8P/T9sutv3/95eio9MtpgKigCgYIKoZIzj0DAQehRANCAARA4wea/3q1WUm/ v+QG8P/T9sutv3/95eio9MtpgKihRANCAARA4wea/3q1WUm/642qmucNIoiPkCIt
642qmucNIoiPkCItNcpGiZdidq/Q3U42GaB53LWrRBOjQqypl0HSST5zc2RF/JwZ NcpGiZdidq/Q3U42GaB53LWrRBOjQqypl0HSST5zc2RF/JwZmXXtwGOJ
mXXtwGOJ
-----END PRIVATE KEY----- -----END PRIVATE KEY-----
" "
); );