Skip to content

Commit

Permalink
feat: added support for p521 analogously to p256 and p384
Browse files Browse the repository at this point in the history
  • Loading branch information
JoHaHu committed Nov 17, 2023
1 parent 51d40dc commit 8b4625a
Show file tree
Hide file tree
Showing 7 changed files with 211 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
/target/
**/*.rs.bk
.idea/
20 changes: 16 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion jose-jwk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rust-version = "1.65"

[features]
default = ["crypto"]
crypto = ["p256", "p384", "rsa"]
crypto = ["p256", "p384", "p521", "rsa"]

[dependencies]
jose-b64 = { version = "0.1", default-features = false, features = ["secret"], path = "../jose-b64" }
Expand All @@ -29,6 +29,7 @@ zeroize = { version = "1.6.0", default-features = false, features = ["alloc"] }
# optional dependencies
p256 = { version = "0.13.2", default-features = false, optional = true, features = ["arithmetic"] }
p384 = { version = "0.13.0", default-features = false, optional = true, features = ["arithmetic"] }
p521 = { version = "0.13.3", default-features = false, optional = true, features = ["arithmetic"]}
rsa = { version = "0.9", default-features = false, optional = true }
url = { version = "2.4.1", default-features = false, optional = true, features = ["serde"] }

Expand Down
46 changes: 44 additions & 2 deletions jose-jwk/src/crypto/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ pub enum Key {
/// A P-384 key.
#[cfg(feature = "p384")]
P384(super::Kind<p384::PublicKey, p384::SecretKey>),

/// A P-521 key
#[cfg(feature = "p521")]
P521(super::Kind<p521::PublicKey, p521::SecretKey>),

}

impl KeyInfo for Key {
Expand All @@ -49,6 +54,9 @@ impl KeyInfo for Key {

#[cfg(feature = "p384")]
Self::P384(k) => k.strength(),

#[cfg(feature = "p521")]
Self::P521(k) => k.strength(),
}
}

Expand All @@ -64,6 +72,9 @@ impl KeyInfo for Key {

#[cfg(feature = "p384")]
Self::P384(k) => k.is_supported(algo),

#[cfg(feature = "p521")]
Self::P521(k) => k.is_supported(algo)
}
}
}
Expand Down Expand Up @@ -137,6 +148,28 @@ impl From<p384::SecretKey> for Key {
}
}

#[cfg(feature = "p521")]
impl From<super::Kind<p521::PublicKey, p521::SecretKey>> for Key {
fn from(value: super::Kind<p521::PublicKey, p521::SecretKey>) -> Self {
Self::P521(value)
}
}

#[cfg(feature = "p521")]
impl From<p521::PublicKey> for Key {
fn from(value: p521::PublicKey) -> Self {
Self::P521(super::Kind::Public(value))
}
}

#[cfg(feature = "p521")]
impl From<p521::SecretKey> for Key {
fn from(value: p521::SecretKey) -> Self {
Self::P521(super::Kind::Secret(value))
}
}


impl From<&crate::Oct> for Key {
fn from(value: &crate::Oct) -> Self {
Self::Oct(value.k.to_vec().into_boxed_slice().into())
Expand All @@ -152,7 +185,7 @@ impl TryFrom<&crate::Rsa> for Key {
}
}

#[cfg(any(feature = "p256", feature = "p384"))]
#[cfg(any(feature = "p256", feature = "p384", feature = "p521"))]
impl TryFrom<&crate::Ec> for Key {
type Error = super::Error;

Expand All @@ -164,6 +197,9 @@ impl TryFrom<&crate::Ec> for Key {
#[cfg(feature = "p384")]
crate::EcCurves::P384 => Ok(Self::P384(value.try_into()?)),

#[cfg(feature = "p521")]
crate::EcCurves::P521 => Ok(Self::P521(value.try_into()?)),

_ => Err(super::Error::Unsupported),
}
}
Expand All @@ -179,7 +215,7 @@ impl TryFrom<&crate::Key> for Key {
#[cfg(feature = "rsa")]
crate::Key::Rsa(rsa) => rsa.try_into(),

#[cfg(any(feature = "p256", feature = "p384"))]
#[cfg(any(feature = "p256", feature = "p384", feature = "p521"))]
crate::Key::Ec(ec) => ec.try_into(),

_ => Err(super::Error::Unsupported),
Expand Down Expand Up @@ -211,6 +247,12 @@ impl From<&Key> for crate::Key {
super::Kind::Public(public) => Self::Ec(public.into()),
super::Kind::Secret(secret) => Self::Ec(secret.into()),
},

#[cfg(feature = "p521")]
Key::P521(kind) => match kind {
super::Kind::Public(public) => Self::Ec(public.into()),
super::Kind::Secret(secret) => Self::Ec(secret.into()),
},
}
}
}
23 changes: 23 additions & 0 deletions jose-jwk/src/crypto/kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,26 @@ impl TryFrom<&crate::Ec> for Kind<p384::PublicKey, p384::SecretKey> {
}
}
}

#[cfg(feature = "p521")]
impl From<&Kind<p521::PublicKey, p521::SecretKey>> for crate::Ec {
fn from(value: &Kind<p521::PublicKey, p521::SecretKey>) -> Self {
match value {
Kind::Public(key) => key.into(),
Kind::Secret(key) => key.into(),
}
}
}

#[cfg(feature = "p521")]
impl TryFrom<&crate::Ec> for Kind<p521::PublicKey, p521::SecretKey> {
type Error = super::Error;

fn try_from(value: &crate::Ec) -> Result<Self, Self::Error> {
if value.d.is_none() {
Ok(Kind::Public(value.try_into()?))
} else {
Ok(Kind::Secret(value.try_into()?))
}
}
}
1 change: 1 addition & 0 deletions jose-jwk/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod kind;
mod p256;
mod p384;
mod rsa;
mod p521;

pub use key::Key;
pub use keyinfo::KeyInfo;
Expand Down
124 changes: 124 additions & 0 deletions jose-jwk/src/crypto/p521.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: 2022 Profian Inc. <[email protected]>
// SPDX-License-Identifier: Apache-2.0 OR MIT

#![cfg(feature = "p521")]

use p521::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
use p521::{EncodedPoint, FieldBytes, PublicKey, SecretKey};

use jose_jwa::{Algorithm, Algorithm::Signing, Signing::*};

use super::Error;
use super::KeyInfo;
use crate::{Ec, EcCurves};

impl KeyInfo for PublicKey {
fn strength(&self) -> usize {
32
}

fn is_supported(&self, algo: &Algorithm) -> bool {
matches!(algo, Signing(Es384))
}
}

impl KeyInfo for SecretKey {
fn strength(&self) -> usize {
32
}

fn is_supported(&self, algo: &Algorithm) -> bool {
matches!(algo, Signing(Es384))
}
}

impl From<&PublicKey> for Ec {
fn from(pk: &PublicKey) -> Self {
let ep = pk.to_encoded_point(false);

Self {
crv: EcCurves::P521,
x: ep.x().expect("unreachable").to_vec().into(),
y: ep.y().expect("unreachable").to_vec().into(),
d: None,
}
}
}

impl From<PublicKey> for Ec {
fn from(sk: PublicKey) -> Self {
(&sk).into()
}
}

impl TryFrom<&Ec> for PublicKey {
type Error = Error;

fn try_from(value: &Ec) -> Result<Self, Self::Error> {
if value.crv != EcCurves::P521 {
return Err(Error::AlgMismatch);
}

let mut x = FieldBytes::default();
if value.x.len() != x.len() {
return Err(Error::Invalid);
}

let mut y = FieldBytes::default();
if value.y.len() != y.len() {
return Err(Error::Invalid);
}

x.copy_from_slice(&value.x);
y.copy_from_slice(&value.y);

let ep = EncodedPoint::from_affine_coordinates(&x, &y, false);
Option::from(Self::from_encoded_point(&ep)).ok_or(Error::Invalid)
}
}

impl TryFrom<Ec> for PublicKey {
type Error = Error;

fn try_from(value: Ec) -> Result<Self, Self::Error> {
(&value).try_into()
}
}

impl From<&SecretKey> for Ec {
fn from(sk: &SecretKey) -> Self {
let mut key: Self = sk.public_key().into();
key.d = Some(sk.to_bytes().to_vec().into());
key
}
}

impl From<SecretKey> for Ec {
fn from(sk: SecretKey) -> Self {
(&sk).into()
}
}

impl TryFrom<&Ec> for SecretKey {
type Error = Error;

fn try_from(value: &Ec) -> Result<Self, Self::Error> {
if value.crv != EcCurves::P521 {
return Err(Error::AlgMismatch);
}

if let Some(d) = value.d.as_ref() {
return Self::from_slice(d).map_err(|_| Error::Invalid);
}

Err(Error::NotPrivate)
}
}

impl TryFrom<Ec> for SecretKey {
type Error = Error;

fn try_from(value: Ec) -> Result<Self, Self::Error> {
(&value).try_into()
}
}

0 comments on commit 8b4625a

Please sign in to comment.