Closed apertureless closed 10 months ago
We have some support for this in the https://docs.rs/jose-jwk/ crate
Namely if you parse your JWK to this type: https://docs.rs/jose-jwk/latest/jose_jwk/struct.Rsa.html#impl-TryFrom%3C%26Rsa%3E-for-RsaPrivateKey
You can use the TryFrom
impl here to decode it to an rsa::RsaPrivateKey
: https://docs.rs/jose-jwk/latest/jose_jwk/struct.Rsa.html#impl-TryFrom%3C%26Rsa%3E-for-RsaPrivateKey
Though I'm afraid there's not a good example of how to do this.
@tarcieri
Hm, but TryFrom
seems to use also from_components
internally, right? So this is basically the way to go?
Here's what I have done:
pub struct JsonWebKeyRSA {
// Algorithm
alg: String,
// modulus
n: String,
// public exponent
e: String,
// private exponent
d: String,
// prime
p: String,
// prime
q: String,
// extractable
ext: bool,
// key id
kty: String,
// key options
key_ops: Option<Vec<KeyOperations>>,
}
impl JsonWebKeyRSA {
pub fn get_components(self) -> (BigUint, BigUint, BigUint, Vec<BigUint>) {
let mut n = Vec::<u8>::new();
let mut e = Vec::<u8>::new();
let mut d = Vec::<u8>::new();
let mut p = Vec::<u8>::new();
let mut q = Vec::<u8>::new();
general_purpose::URL_SAFE_NO_PAD
.decode_vec(&self.n, &mut n)
.expect("Failed to base64 decode modulus n");
general_purpose::URL_SAFE_NO_PAD
.decode_vec(&self.e, &mut e)
.expect("Failed to base64 decode public exponent e");
general_purpose::URL_SAFE_NO_PAD
.decode_vec(&self.d, &mut d)
.expect("Failed to base64 decode private exponent d");
general_purpose::URL_SAFE_NO_PAD
.decode_vec(&self.p, &mut p)
.expect("Failed to base64 decode prime 1");
general_purpose::URL_SAFE_NO_PAD
.decode_vec(&self.q, &mut q)
.expect("Failed to base64 decode prime 2");
(
BigUint::from_bytes_le(&n),
BigUint::from_bytes_le(&e),
BigUint::from_bytes_le(&d),
vec![BigUint::from_bytes_le(&p), BigUint::from_bytes_le(&q)],
)
}
}
And in my main
let private_key: JsonWebKeyRSA = serde_json::from_str(jwk_private.as_str()).unwrap();
let (n, e, d, primes) = private_key.get_components();
let rsa_private_key = RsaPrivateKey::from_components(n, e, d, primes)
.expect("Failed to build RSA key from components");
However decryption using this key fails.
To debug I tried to export it to PEM
let pk = rsa_private_key.to_pkcs8_der().unwrap();
pk.write_pem_file("privatekey.pem", "PRIVATE KEY", rsa::pkcs8::LineEnding::LF)
And compared it to the pem which I exported with web crypto
await window.crypto.subtle.exportKey(
'pkcs8',
pk
)
But they do not match. So I thought my initial idea with from_components
is flawed.
Can you try it with the jose-jwk
crate?
Can you try it with the
jose-jwk
crate?
@tarcieri Not really, because it looks like jose-jwk
does not support RSA-OAEP keys.
https://docs.rs/jose-jwa/0.1.2/jose_jwa/enum.Algorithm.html
Possible types of algorithms that can exist in an “alg” descriptor. Currently only signing algorithms are represented.
If I try to parse it to JWK I am getting the error:
hread 'main' panicked at src/wallet.rs:39:71:
called `Result::unwrap()` on an `Err` value: Error("data did not match any variant of untagged enum Algorithm", line: 1, column: 3206)
I guess because the alg
is RSA-OAEP-256
which is part of the JWE spec.
Okay, I found my mistake. The code I posted is basically working, I just had to change the BigUInt parsing to big endian. So after replacing
BigUint::from_bytes_le(&n),
BigUint::from_bytes_le(&e),
BigUint::from_bytes_le(&d),
with
BigUint::from_bytes_be(&n),
BigUint::from_bytes_be(&e),
BigUint::from_bytes_be(&d),
in my get_components
I could properly use RsaPrivateKey::from_components
Hey there!
I am currently working on a small rust project with rsa to parse and decrypt a json file. Some of the fields of the json file are encrypted with RSA-OAEP with the WebCrypto API and we are using JWKs for the Keypairs. (Private key encrypted with aes-gcm)
The decryption of the base64 encoded private key works, however now I ended up with an untyped json string or my own JWK struct.
However I am stuck how to import it as a RSAPrivateKey. At first I thought
::from_components
would be what I am looking for, as I have all rsa key components in the jwk. But I guess I was wrong, as the keys do not match.