From fc03d35e94aace103d5a53aac7f1e6d6e3071575 Mon Sep 17 00:00:00 2001 From: avery <305482686@qq.com> Date: Fri, 29 Sep 2023 14:47:51 +0800 Subject: [PATCH 1/2] Add A Secp256k1 key --- Cargo.lock | 109 ++++++++++++++++++++++++++++++ jose-jwk/Cargo.toml | 34 ++++++++-- jose-jwk/src/crypto/key.rs | 16 +++++ jose-jwk/src/crypto/kind.rs | 24 +++++++ jose-jwk/src/crypto/mod.rs | 1 + jose-jwk/src/crypto/p256k.rs | 125 +++++++++++++++++++++++++++++++++++ 6 files changed, 302 insertions(+), 7 deletions(-) create mode 100644 jose-jwk/src/crypto/p256k.rs diff --git a/Cargo.lock b/Cargo.lock index e363085..17a0f94 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,12 +35,27 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "const-oid" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "crypto-bigint" version = "0.5.2" @@ -82,6 +97,21 @@ dependencies = [ "block-buffer", "const-oid", "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", ] [[package]] @@ -96,6 +126,7 @@ dependencies = [ "ff", "generic-array", "group", + "pkcs8", "rand_core", "sec1", "subtle", @@ -132,6 +163,17 @@ dependencies = [ "zeroize", ] +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "group" version = "0.13.0" @@ -143,6 +185,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "idna" version = "0.4.0" @@ -188,6 +239,7 @@ version = "0.1.2" dependencies = [ "jose-b64", "jose-jwa", + "k256", "p256", "p384", "rsa", @@ -213,6 +265,20 @@ dependencies = [ name = "jose-jwt" version = "0.0.0" +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -222,6 +288,12 @@ dependencies = [ "spin", ] +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + [[package]] name = "libm" version = "0.2.7" @@ -276,6 +348,12 @@ dependencies = [ "libm", ] +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + [[package]] name = "p256" version = "0.13.2" @@ -381,6 +459,19 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] [[package]] name = "rsa" @@ -419,6 +510,7 @@ dependencies = [ "base16ct", "der", "generic-array", + "pkcs8", "subtle", "zeroize", ] @@ -454,6 +546,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signature" version = "2.1.0" @@ -563,6 +666,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "zeroize" version = "1.6.0" diff --git a/jose-jwk/Cargo.toml b/jose-jwk/Cargo.toml index 3c5f1db..c1a7150 100644 --- a/jose-jwk/Cargo.toml +++ b/jose-jwk/Cargo.toml @@ -10,7 +10,12 @@ RFC7517 """ documentation = "https://docs.rs/jose-jwk" repository = "https://github.com/RustCrypto/JOSE/tree/master/jose-jwk" -categories = ["cryptography", "data-structures", "encoding", "parser-implementations"] +categories = [ + "cryptography", + "data-structures", + "encoding", + "parser-implementations", +] keywords = ["json", "jose"] readme = "README.md" edition = "2021" @@ -18,19 +23,34 @@ rust-version = "1.65" [features] default = ["crypto"] -crypto = ["p256", "p384", "rsa"] +crypto = ["p256", "p384", "rsa", "k256"] [dependencies] -jose-b64 = { version = "0.1", default-features = false, features = ["secret"], path = "../jose-b64" } +jose-b64 = { version = "0.1", default-features = false, features = [ + "secret", +], path = "../jose-b64" } jose-jwa = { version = "0.1", path = "../jose-jwa" } -serde = { version = "1.0.185", default-features = false, features = ["alloc", "derive"] } +serde = { version = "1.0.185", default-features = false, features = [ + "alloc", + "derive", +] } 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"] } +p256 = { version = "0.13.2", default-features = false, optional = true, features = [ + "arithmetic", +] } +p384 = { version = "0.13.0", default-features = false, optional = true, features = [ + "arithmetic", +] } + +k256 = { version = "0.13.1", default-features = false, optional = true, features = [ + "default", +] } rsa = { version = "0.9", default-features = false, optional = true } -url = { version = "2.4.1", default-features = false, optional = true, features = ["serde"] } +url = { version = "2.4.1", default-features = false, optional = true, features = [ + "serde", +] } [dev-dependencies] serde_json = "1.0.96" diff --git a/jose-jwk/src/crypto/key.rs b/jose-jwk/src/crypto/key.rs index cfe590d..b02fab7 100644 --- a/jose-jwk/src/crypto/key.rs +++ b/jose-jwk/src/crypto/key.rs @@ -34,6 +34,10 @@ pub enum Key { /// A P-384 key. #[cfg(feature = "p384")] P384(super::Kind), + + /// A Secp256k1 key. + #[cfg(feature = "k256")] + P256K(super::Kind), } impl KeyInfo for Key { @@ -49,6 +53,9 @@ impl KeyInfo for Key { #[cfg(feature = "p384")] Self::P384(k) => k.strength(), + + #[cfg(feature = "k256")] + Self::P256K(k) => k.strength(), } } @@ -64,6 +71,9 @@ impl KeyInfo for Key { #[cfg(feature = "p384")] Self::P384(k) => k.is_supported(algo), + + #[cfg(feature = "k256")] + Self::P256K(k) => k.is_supported(algo), } } } @@ -211,6 +221,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 = "k256")] + Key::P256K(kind) => match kind { + super::Kind::Public(public) => Self::Ec(public.into()), + super::Kind::Secret(secret) => Self::Ec(secret.into()), + }, } } } diff --git a/jose-jwk/src/crypto/kind.rs b/jose-jwk/src/crypto/kind.rs index 7adf905..cffe138 100644 --- a/jose-jwk/src/crypto/kind.rs +++ b/jose-jwk/src/crypto/kind.rs @@ -98,3 +98,27 @@ impl TryFrom<&crate::Ec> for Kind { } } } + + +#[cfg(feature = "k256")] +impl From<&Kind> for crate::Ec { + fn from(value: &Kind) -> Self { + match value { + Kind::Public(key) => key.into(), + Kind::Secret(key) => key.into(), + } + } +} + +#[cfg(feature = "k256")] +impl TryFrom<&crate::Ec> for Kind { + type Error = super::Error; + + fn try_from(value: &crate::Ec) -> Result { + if value.d.is_none() { + Ok(Kind::Public(value.try_into()?)) + } else { + Ok(Kind::Secret(value.try_into()?)) + } + } +} diff --git a/jose-jwk/src/crypto/mod.rs b/jose-jwk/src/crypto/mod.rs index 2228e42..830cb33 100644 --- a/jose-jwk/src/crypto/mod.rs +++ b/jose-jwk/src/crypto/mod.rs @@ -7,6 +7,7 @@ mod key; mod keyinfo; mod kind; mod p256; +mod p256k; mod p384; mod rsa; diff --git a/jose-jwk/src/crypto/p256k.rs b/jose-jwk/src/crypto/p256k.rs new file mode 100644 index 0000000..be666dd --- /dev/null +++ b/jose-jwk/src/crypto/p256k.rs @@ -0,0 +1,125 @@ +#![cfg(feature = "k256")] + +use crate::{Ec, EcCurves}; + +use super::Error; +use super::KeyInfo; +use jose_jwa::{Algorithm, Algorithm::Signing, Signing::*}; +use k256::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint}; +use k256::{EncodedPoint, FieldBytes, PublicKey, SecretKey}; + +impl KeyInfo for PublicKey { + fn strength(&self) -> usize { + todo!() + } + + fn is_supported(&self, algo: &Algorithm) -> bool { + matches!(algo, Signing(Es256K)) + } +} + +impl KeyInfo for SecretKey { + fn strength(&self) -> usize { + todo!() + } + + fn is_supported(&self, algo: &Algorithm) -> bool { + matches!(algo, Signing(Es256)) + } +} + +impl From<&PublicKey> for Ec { + fn from(pk: &PublicKey) -> Self { + let ep = pk.to_encoded_point(false); + Self { + crv: EcCurves::P256K, + x: ep.x().expect("unreachable").to_vec().into(), + y: ep.y().expect("unreachable").to_vec().into(), + d: None, + } + } +} + + +impl From for Ec { + fn from(sk: PublicKey) -> Self { + (&sk).into() + } +} + + +impl TryFrom<&Ec> for PublicKey { + type Error = Error; + + fn try_from(value: &Ec) -> Result { + if value.crv != EcCurves::P256K { + 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 for PublicKey { + type Error = Error; + + fn try_from(value: Ec) -> Result { + (&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 for Ec { + fn from(sk: SecretKey) -> Self { + (&sk).into() + } +} + + +impl TryFrom<&Ec> for SecretKey { + type Error = Error; + + fn try_from(value: &Ec) -> Result { + if value.crv != EcCurves::P256 { + 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 for SecretKey { + type Error = Error; + + fn try_from(value: Ec) -> Result { + (&value).try_into() + } +} + From 2f768f31dd2d5b464b0cdb01dc07d538ad7a2217 Mon Sep 17 00:00:00 2001 From: avery <305482686@qq.com> Date: Fri, 29 Sep 2023 15:06:23 +0800 Subject: [PATCH 2/2] A Secp256k1 key --- jose-jwk/src/crypto/p256k.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jose-jwk/src/crypto/p256k.rs b/jose-jwk/src/crypto/p256k.rs index be666dd..783190d 100644 --- a/jose-jwk/src/crypto/p256k.rs +++ b/jose-jwk/src/crypto/p256k.rs @@ -10,7 +10,7 @@ use k256::{EncodedPoint, FieldBytes, PublicKey, SecretKey}; impl KeyInfo for PublicKey { fn strength(&self) -> usize { - todo!() + 128 } fn is_supported(&self, algo: &Algorithm) -> bool { @@ -20,7 +20,7 @@ impl KeyInfo for PublicKey { impl KeyInfo for SecretKey { fn strength(&self) -> usize { - todo!() + 128 } fn is_supported(&self, algo: &Algorithm) -> bool {