diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fde31fd0..13042f36 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: strategy: matrix: rust: - - 1.72.0 # MSRV + - 1.73.0 # MSRV - stable target: - thumbv7em-none-eabi @@ -35,7 +35,7 @@ jobs: strategy: matrix: rust: - - 1.72.0 # MSRV + - 1.73.0 # MSRV - stable steps: - uses: actions/checkout@v4 @@ -44,7 +44,7 @@ jobs: with: toolchain: ${{ matrix.rust }} - uses: RustCrypto/actions/cargo-hack-install@master - - run: cargo hack test --release --feature-powerset --exclude-features nightly,getrandom,serde + - run: cargo hack test --release --feature-powerset --exclude-features getrandom,serde - run: cargo test --release --features getrandom - run: cargo test --release --features serde @@ -66,5 +66,5 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2023-10-01 - - run: cargo test --release --features nightly + - run: cargo test --release - run: cargo build --benches diff --git a/Cargo.lock b/Cargo.lock index 6e7678fb..f5f85b8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,9 +71,9 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "block-buffer" @@ -139,6 +139,19 @@ dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.6.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e43027691f1c055da3da4f7d96af09fcec420d435d5616e51f29afd0811c56a7" +dependencies = [ + "num-traits", + "rand_core", + "serdect", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.2.0-rc.0" @@ -150,6 +163,16 @@ dependencies = [ "rand_core", ] +[[package]] +name = "crypto-primes" +version = "0.6.0-pre.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31bb1382ea4ef18b2da595f36ca284c7b6366d22264ac02f8baee109361cd6b0" +dependencies = [ + "crypto-bigint", + "rand_core", +] + [[package]] name = "ctr" version = "0.10.0-pre.1" @@ -189,7 +212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -270,12 +293,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -295,44 +315,6 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "serde", - "smallvec", - "zeroize", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -343,6 +325,12 @@ dependencies = [ "libm", ] +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -361,9 +349,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "1.0.0-rc.0" +version = "1.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b24c1c4a3b352d47de5ec824193e68317dc0ce041f6279a4771eb550ab7f8c" +checksum = "b6c1cde4770761bf6bd336f947b9ac1fe700b0a4ec5867cf66cf08597fe89e8c" dependencies = [ "base64ct", ] @@ -422,15 +410,18 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -511,9 +502,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "rsa" @@ -521,11 +512,10 @@ version = "0.10.0-pre.2" dependencies = [ "base64ct", "const-oid", + "crypto-bigint", + "crypto-primes", "digest", "hex-literal", - "num-bigint-dig", - "num-integer", - "num-traits", "pkcs1", "pkcs8", "proptest", @@ -555,7 +545,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -593,18 +583,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.206" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "5b3e4cd94123dd520a128bcd11e34d9e9e423e7e3e50425cb1b4b1e3549d0284" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.206" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "fabfb6138d2383ea8208cf98ccf69cdfb1aff4088460681d84189aa259762f97" dependencies = [ "proc-macro2", "quote", @@ -613,9 +603,9 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] @@ -672,18 +662,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spki" version = "0.8.0-rc.0" @@ -696,15 +674,15 @@ dependencies = [ [[package]] name = "subtle" -version = "2.5.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "837a7e8026c6ce912ff01cefbe8cafc2f8010ac49682e2a3d9decc3bce1ecaaf" dependencies = [ "proc-macro2", "quote", @@ -713,14 +691,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -775,11 +754,20 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -793,51 +781,72 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zeroize" diff --git a/Cargo.toml b/Cargo.toml index dbb5a1b1..3f429959 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,21 +10,20 @@ repository = "https://github.com/RustCrypto/RSA" keywords = ["rsa", "encryption", "security", "crypto"] categories = ["cryptography"] readme = "README.md" -rust-version = "1.72" +rust-version = "1.73" [dependencies] -num-bigint = { version = "0.8.2", features = ["i128", "prime", "zeroize"], default-features = false, package = "num-bigint-dig" } -num-traits = { version = "0.2.9", default-features = false, features = ["libm"] } -num-integer = { version = "0.1.39", default-features = false } rand_core = { version = "0.6.4", default-features = false } -const-oid = { version = "0.10.0-rc.0", default-features = false } -subtle = { version = "2.1.1", default-features = false } +const-oid = { version = "=0.10.0-rc.0", default-features = false } +subtle = { version = "2.6.1", default-features = false } digest = { version = "=0.11.0-pre.9", default-features = false, features = ["alloc", "oid"] } -pkcs1 = { version = "0.8.0-rc.0", default-features = false, features = ["alloc", "pkcs8"] } -pkcs8 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc"] } -signature = { version = "=2.3.0-pre.4", default-features = false, features = ["alloc", "digest", "rand_core"] } -spki = { version = "0.8.0-rc.0", default-features = false, features = ["alloc"] } +pkcs1 = { version = "=0.8.0-rc.0", default-features = false, features = ["alloc", "pkcs8"] } +pkcs8 = { version = "=0.11.0-rc.0", default-features = false, features = ["alloc"] } +signature = { version = "=2.3.0-pre.4", default-features = false , features = ["alloc", "digest", "rand_core"] } +spki = { version = "=0.8.0-rc.0", default-features = false, features = ["alloc"] } zeroize = { version = "1.5", features = ["alloc"] } +crypto-bigint = { version = "0.6.0-rc.2", default-features = false, features = ["zeroize", "alloc"] } +crypto-primes = { version = "0.6.0-pre.0" } # optional dependencies sha1 = { version = "=0.11.0-pre.4", optional = true, default-features = false, features = ["oid"] } @@ -49,15 +48,13 @@ sha3 = { version = "=0.11.0-pre.4", default-features = false, features = ["oid"] name = "key" [features] -default = ["std", "pem", "u64_digit"] +default = ["std", "pem"] hazmat = [] -getrandom = ["rand_core/getrandom"] -nightly = ["num-bigint/nightly"] -serde = ["dep:serde", "dep:serdect", "num-bigint/serde"] +getrandom = ["rand_core/getrandom", "crypto-bigint/rand_core"] +serde = ["dep:serde", "dep:serdect", "crypto-bigint/serde"] pem = ["pkcs1/pem", "pkcs8/pem"] pkcs5 = ["pkcs8/encryption"] -u64_digit = ["num-bigint/u64_digit"] -std = ["digest/std", "pkcs1/std", "pkcs8/std", "rand_core/std", "signature/std"] +std = ["digest/std", "pkcs1/std", "pkcs8/std", "rand_core/std", "signature/std", "crypto-bigint/std"] [package.metadata.docs.rs] features = ["std", "pem", "serde", "hazmat", "sha2"] @@ -65,3 +62,10 @@ rustdoc-args = ["--cfg", "docsrs"] [profile.dev] opt-level = 2 + +[profile.bench] +debug = true + +[patch.crates-io] +# crypto-bigint = { git = "https://github.com/RustCrypto/crypto-bigint", branch = "master" } +# crypto-bigint = { path = "../rustcrypto/crypto-bigint" } diff --git a/README.md b/README.md index 7a301a68..f47e549b 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,7 @@ You can follow our work on mitigating this issue in [#390]. ## Minimum Supported Rust Version (MSRV) -This crate supports Rust 1.72 or higher. +This crate supports Rust 1.73 or higher. In the future MSRV can be changed, but it will be done with a minor version bump. @@ -108,7 +108,7 @@ dual licensed as above, without any additional terms or conditions. [doc-link]: https://docs.rs/rsa [build-image]: https://github.com/rustcrypto/RSA/workflows/CI/badge.svg [build-link]: https://github.com/RustCrypto/RSA/actions?query=workflow%3ACI+branch%3Amaster -[msrv-image]: https://img.shields.io/badge/rustc-1.72+-blue.svg +[msrv-image]: https://img.shields.io/badge/rustc-1.73+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260047-RSA [deps-image]: https://deps.rs/repo/github/RustCrypto/RSA/status.svg diff --git a/src/algorithms/generate.rs b/src/algorithms/generate.rs index 7fa8acc1..93f33630 100644 --- a/src/algorithms/generate.rs +++ b/src/algorithms/generate.rs @@ -1,10 +1,8 @@ //! Generate prime components for the RSA Private Key use alloc::vec::Vec; -use num_bigint::{BigUint, RandPrime}; -#[allow(unused_imports)] -use num_traits::Float; -use num_traits::Zero; +use crypto_bigint::{BoxedUint, Odd}; +use crypto_primes::generate_prime_with_rng; use rand_core::CryptoRngCore; use crate::{ @@ -13,10 +11,10 @@ use crate::{ }; pub struct RsaPrivateKeyComponents { - pub n: BigUint, - pub e: BigUint, - pub d: BigUint, - pub primes: Vec, + pub n: Odd, + pub e: u64, + pub d: BoxedUint, + pub primes: Vec, } /// Generates a multi-prime RSA keypair of the given bit size, public exponent, @@ -30,11 +28,11 @@ pub struct RsaPrivateKeyComponents { /// /// [1]: https://patents.google.com/patent/US4405829A/en /// [2]: http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf -pub(crate) fn generate_multi_prime_key_with_exp( +pub(crate) fn generate_multi_prime_key_with_exp( rng: &mut R, nprimes: usize, bit_size: usize, - exp: &BigUint, + exp: u64, ) -> Result { if nprimes < 2 { return Err(Error::NprimesTooSmall); @@ -56,9 +54,9 @@ pub(crate) fn generate_multi_prime_key_with_exp( } } - let mut primes = vec![BigUint::zero(); nprimes]; - let n_final: BigUint; - let d_final: BigUint; + let mut primes = vec![BoxedUint::zero(); nprimes]; + let n_final: Odd; + let d_final: BoxedUint; 'next: loop { let mut todo = bit_size; @@ -78,8 +76,10 @@ pub(crate) fn generate_multi_prime_key_with_exp( } for (i, prime) in primes.iter_mut().enumerate() { - *prime = rng.gen_prime(todo / (nprimes - i)); - todo -= prime.bits(); + let bits = (todo / (nprimes - i)) as u32; + let bits_precision = BoxedUint::zero_with_precision(bits).bits_precision(); + *prime = generate_prime_with_rng(rng, bits, bits_precision); + todo -= prime.bits() as usize; } // Makes sure that primes is pairwise unequal. @@ -93,7 +93,7 @@ pub(crate) fn generate_multi_prime_key_with_exp( let n = compute_modulus(&primes); - if n.bits() != bit_size { + if n.bits() as usize != bit_size { // This should never happen for nprimes == 2 because // gen_prime should set the top two bits in each prime. // For nprimes > 2 we hope it does not happen often. @@ -109,7 +109,7 @@ pub(crate) fn generate_multi_prime_key_with_exp( Ok(RsaPrivateKeyComponents { n: n_final, - e: exp.clone(), + e: exp, d: d_final, primes, }) @@ -118,8 +118,6 @@ pub(crate) fn generate_multi_prime_key_with_exp( #[cfg(test)] mod tests { use super::*; - use num_bigint::BigUint; - use num_traits::FromPrimitive; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; const EXP: u64 = 65537; @@ -127,12 +125,11 @@ mod tests { #[test] fn test_impossible_keys() { let mut rng = ChaCha8Rng::from_seed([42; 32]); - let exp = BigUint::from_u64(EXP).expect("invalid static exponent"); for i in 0..32 { - let _ = generate_multi_prime_key_with_exp(&mut rng, 2, i, &exp); - let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, &exp); - let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, &exp); - let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, &exp); + let _ = generate_multi_prime_key_with_exp(&mut rng, 2, i, EXP); + let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, EXP); + let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, EXP); + let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, EXP); } } @@ -141,11 +138,10 @@ mod tests { #[test] fn $name() { let mut rng = ChaCha8Rng::from_seed([42; 32]); - let exp = BigUint::from_u64(EXP).expect("invalid static exponent"); for _ in 0..10 { let components = - generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap(); + generate_multi_prime_key_with_exp(&mut rng, $multi, $size, EXP).unwrap(); assert_eq!(components.n.bits(), $size); assert_eq!(components.primes.len(), $multi); } @@ -162,5 +158,6 @@ mod tests { key_generation!(key_generation_multi_5_64, 5, 64); key_generation!(key_generation_multi_8_576, 8, 576); - key_generation!(key_generation_multi_16_1024, 16, 1024); + // TODO: reenable, currently slow + // key_generation!(key_generation_multi_16_1024, 16, 1024); } diff --git a/src/algorithms/pad.rs b/src/algorithms/pad.rs index b89c8c2e..9191e4a8 100644 --- a/src/algorithms/pad.rs +++ b/src/algorithms/pad.rs @@ -1,7 +1,7 @@ //! Special handling for converting the BigUint to u8 vectors use alloc::vec::Vec; -use num_bigint::BigUint; +use crypto_bigint::BoxedUint; use zeroize::Zeroizing; use crate::errors::{Error, Result}; @@ -20,15 +20,15 @@ fn left_pad(input: &[u8], padded_len: usize) -> Result> { /// Converts input to the new vector of the given length, using BE and with 0s left padded. #[inline] -pub(crate) fn uint_to_be_pad(input: BigUint, padded_len: usize) -> Result> { - left_pad(&input.to_bytes_be(), padded_len) +pub(crate) fn uint_to_be_pad(input: BoxedUint, padded_len: usize) -> Result> { + left_pad(&input.to_be_bytes(), padded_len) } /// Converts input to the new vector of the given length, using BE and with 0s left padded. #[inline] -pub(crate) fn uint_to_zeroizing_be_pad(input: BigUint, padded_len: usize) -> Result> { +pub(crate) fn uint_to_zeroizing_be_pad(input: BoxedUint, padded_len: usize) -> Result> { let m = Zeroizing::new(input); - let m = Zeroizing::new(m.to_bytes_be()); + let m = Zeroizing::new(m.to_be_bytes()); left_pad(&m, padded_len) } diff --git a/src/algorithms/rsa.rs b/src/algorithms/rsa.rs index 35101526..9e2f37d9 100644 --- a/src/algorithms/rsa.rs +++ b/src/algorithms/rsa.rs @@ -1,15 +1,13 @@ //! Generic RSA implementation -use alloc::borrow::Cow; -use alloc::vec::Vec; -use num_bigint::{BigInt, BigUint, IntoBigInt, IntoBigUint, ModInverse, RandBigInt, ToBigInt}; -use num_integer::{sqrt, Integer}; -use num_traits::{FromPrimitive, One, Pow, Signed, Zero}; +use crypto_bigint::modular::{BoxedMontyForm, BoxedMontyParams}; +use crypto_bigint::{BoxedUint, Gcd, NonZero, Odd, RandomMod, Wrapping}; use rand_core::CryptoRngCore; -use zeroize::{Zeroize, Zeroizing}; +use zeroize::Zeroize; use crate::errors::{Error, Result}; -use crate::traits::{PrivateKeyParts, PublicKeyParts}; +use crate::key::reduce; +use crate::traits::keys::{PrivateKeyParts, PublicKeyParts}; /// ⚠️ Raw RSA encryption of m with the public key. No padding is performed. /// @@ -18,13 +16,14 @@ use crate::traits::{PrivateKeyParts, PublicKeyParts}; /// Use this function with great care! Raw RSA should never be used without an appropriate padding /// or signature scheme. See the [module-level documentation][crate::hazmat] for more information. #[inline] -pub fn rsa_encrypt(key: &K, m: &BigUint) -> Result { - Ok(m.modpow(key.e(), key.n())) +pub fn rsa_encrypt(key: &K, m: &BoxedUint) -> Result { + let res = pow_mod_params(m, &BoxedUint::from(key.e()), key.n_params()); + Ok(res) } /// ⚠️ Performs raw RSA decryption with no padding or error checking. /// -/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed. +/// Returns a plaintext `BoxedUint`. Performs RSA blinding if an `Rng` is passed. /// /// # ☢️️ WARNING: HAZARDOUS API ☢️ /// @@ -34,89 +33,78 @@ pub fn rsa_encrypt(key: &K, m: &BigUint) -> Result { pub fn rsa_decrypt( mut rng: Option<&mut R>, priv_key: &impl PrivateKeyParts, - c: &BigUint, -) -> Result { - if c >= priv_key.n() { - return Err(Error::Decryption); - } + c: &BoxedUint, +) -> Result { + let n = priv_key.n(); + let d = priv_key.d(); - if priv_key.n().is_zero() { + if c >= n.as_ref() { return Err(Error::Decryption); } let mut ir = None; + let n_params = priv_key.n_params(); + let bits = d.bits_precision(); + let c = if let Some(ref mut rng) = rng { - let (blinded, unblinder) = blind(rng, priv_key, c); + let (blinded, unblinder) = blind(rng, priv_key, c, &n_params); ir = Some(unblinder); - Cow::Owned(blinded) + blinded.widen(bits) } else { - Cow::Borrowed(c) + c.widen(bits) }; - let dp = priv_key.dp(); - let dq = priv_key.dq(); - let qinv = priv_key.qinv(); - let crt_values = priv_key.crt_values(); - - let m = match (dp, dq, qinv, crt_values) { - (Some(dp), Some(dq), Some(qinv), Some(crt_values)) => { - // We have the precalculated values needed for the CRT. - - let p = &priv_key.primes()[0]; - let q = &priv_key.primes()[1]; - - let mut m = c.modpow(dp, p).into_bigint().unwrap(); - let mut m2 = c.modpow(dq, q).into_bigint().unwrap(); - - m -= &m2; - - let mut primes: Vec<_> = priv_key - .primes() - .iter() - .map(ToBigInt::to_bigint) - .map(Option::unwrap) - .collect(); - - while m.is_negative() { - m += &primes[0]; - } - m *= qinv; - m %= &primes[0]; - m *= &primes[1]; - m += &m2; - - let mut c = c.into_owned().into_bigint().unwrap(); - for (i, value) in crt_values.iter().enumerate() { - let prime = &primes[2 + i]; - m2 = c.modpow(&value.exp, prime); - m2 -= &m; - m2 *= &value.coeff; - m2 %= prime; - while m2.is_negative() { - m2 += prime; - } - m2 *= &value.r; - m += &m2; - } - - // clear tmp values - for prime in primes.iter_mut() { - prime.zeroize(); - } - primes.clear(); - c.zeroize(); - m2.zeroize(); - - m.into_biguint().expect("failed to decrypt") - } - _ => c.modpow(priv_key.d(), priv_key.n()), + let has_precomputes = priv_key.dp().is_some(); + let is_multiprime = priv_key.primes().len() > 2; + + let m = if is_multiprime || !has_precomputes { + // c^d (mod n) + pow_mod_params(&c, d, n_params.clone()) + } else { + // We have the precalculated values needed for the CRT. + + let dp = priv_key.dp().unwrap(); + let dq = priv_key.dq().unwrap(); + let qinv = priv_key.qinv().unwrap(); + let p_params = priv_key.p_params().unwrap(); + let q_params = priv_key.q_params().unwrap(); + + let _p = &priv_key.primes()[0]; + let q = &priv_key.primes()[1]; + + // precomputed: dP = (1/e) mod (p-1) = d mod (p-1) + // precomputed: dQ = (1/e) mod (q-1) = d mod (q-1) + + // m1 = c^dP mod p + let cp = BoxedMontyForm::new(c.clone(), p_params.clone()); + let mut m1 = cp.pow(dp); + // m2 = c^dQ mod q + let cq = BoxedMontyForm::new(c, q_params.clone()); + let m2 = cq.pow(dq).retrieve(); + + // (m1 - m2) mod p = (m1 mod p) - (m2 mod p) mod p + let m2r = BoxedMontyForm::new(m2.clone(), p_params.clone()); + m1 -= &m2r; + + // precomputed: qInv = (1/q) mod p + + // h = qInv.(m1 - m2) mod p + let mut m: Wrapping = Wrapping(qinv.mul(&m1).retrieve()); + + // m = m2 + h.q + m *= Wrapping(q.clone()); + m += Wrapping(m2); + m.0 }; + // Ensure output precision matches input precision + let m = m.shorten(n_params.bits_precision()); match ir { Some(ref ir) => { // unblind - Ok(unblind(priv_key, &m, ir)) + let res = unblind(&m, ir, n_params); + Ok(res) } None => Ok(m), } @@ -124,7 +112,7 @@ pub fn rsa_decrypt( /// ⚠️ Performs raw RSA decryption with no padding. /// -/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed. This will also +/// Returns a plaintext `BoxedUint`. Performs RSA blinding if an `Rng` is passed. This will also /// check for errors in the CRT computation. /// /// # ☢️️ WARNING: HAZARDOUS API ☢️ @@ -135,8 +123,8 @@ pub fn rsa_decrypt( pub fn rsa_decrypt_and_check( priv_key: &impl PrivateKeyParts, rng: Option<&mut R>, - c: &BigUint, -) -> Result { + c: &BoxedUint, +) -> Result { let m = rsa_decrypt(rng, priv_key, c)?; // In order to defend against errors in the CRT computation, m^e is @@ -154,126 +142,176 @@ pub fn rsa_decrypt_and_check( fn blind( rng: &mut R, key: &K, - c: &BigUint, -) -> (BigUint, BigUint) { + c: &BoxedUint, + n_params: &BoxedMontyParams, +) -> (BoxedUint, BoxedUint) { // Blinding involves multiplying c by r^e. // Then the decryption operation performs (m^e * r^e)^d mod n // which equals mr mod n. The factor of r can then be removed // by multiplying by the multiplicative inverse of r. - - let mut r: BigUint; - let mut ir: Option; - let unblinder; - loop { - r = rng.gen_biguint_below(key.n()); - if r.is_zero() { - r = BigUint::one(); + debug_assert_eq!(&key.n().clone().get(), n_params.modulus()); + let bits = key.n_bits_precision(); + + let mut r: BoxedUint = BoxedUint::one_with_precision(bits); + let mut ir: Option = None; + while ir.is_none() { + r = BoxedUint::random_mod(rng, key.n()); + if r.is_zero().into() { + r = BoxedUint::one_with_precision(bits); } - ir = r.clone().mod_inverse(key.n()); - if let Some(ir) = ir { - if let Some(ub) = ir.into_biguint() { - unblinder = ub; - break; - } - } - } - let c = { - let mut rpowe = r.modpow(key.e(), key.n()); // N != 0 - let mut c = c * &rpowe; - c %= key.n(); + // r^-1 (mod n) + ir = r.inv_mod(key.n()).into(); + } + let blinded = { + // r^e (mod n) + let mut rpowe = pow_mod_params(&r, &BoxedUint::from(key.e()), n_params.clone()); + // c * r^e (mod n) + let c = mul_mod_params(c, &rpowe, n_params.clone()); rpowe.zeroize(); c }; - (c, unblinder) + let ir = ir.unwrap(); + debug_assert_eq!(blinded.bits_precision(), bits); + debug_assert_eq!(ir.bits_precision(), bits); + + (blinded, ir) } /// Given an m and and unblinding factor, unblind the m. -fn unblind(key: &impl PublicKeyParts, m: &BigUint, unblinder: &BigUint) -> BigUint { - (m * unblinder) % key.n() +fn unblind(m: &BoxedUint, unblinder: &BoxedUint, n_params: BoxedMontyParams) -> BoxedUint { + // m * r^-1 (mod n) + debug_assert_eq!( + m.bits_precision(), + unblinder.bits_precision(), + "invalid unblinder" + ); + + debug_assert_eq!( + m.bits_precision(), + n_params.bits_precision(), + "invalid n_params" + ); + + mul_mod_params(m, unblinder, n_params) +} + +/// Computes `base.pow_mod(exp, n)` with precomputed `n_params`. +fn pow_mod_params(base: &BoxedUint, exp: &BoxedUint, n_params: BoxedMontyParams) -> BoxedUint { + let base = reduce(base, n_params); + base.pow(exp).retrieve() +} + +/// Computes `lhs.mul_mod(rhs, n)` with precomputed `n_params`. +fn mul_mod_params(lhs: &BoxedUint, rhs: &BoxedUint, n_params: BoxedMontyParams) -> BoxedUint { + // TODO: nicer api in crypto-bigint? + let lhs = BoxedMontyForm::new(lhs.clone(), n_params.clone()); + let rhs = BoxedMontyForm::new(rhs.clone(), n_params); + (lhs * rhs).retrieve() } /// The following (deterministic) algorithm also recovers the prime factors `p` and `q` of a modulus `n`, given the /// public exponent `e` and private exponent `d` using the method described in /// [NIST 800-56B Appendix C.2](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf). -pub fn recover_primes(n: &BigUint, e: &BigUint, d: &BigUint) -> Result<(BigUint, BigUint)> { +pub fn recover_primes( + n: &NonZero, + e: u64, + d: &BoxedUint, +) -> Result<(BoxedUint, BoxedUint)> { // Check precondition - let two = BigUint::from_u8(2).unwrap(); - if e <= &two.pow(16u32) || e >= &two.pow(256u32) { + + // Note: because e is at most u64::MAX, it is already + // known to be < 2**256 + if e <= 2u64.pow(16) { return Err(Error::InvalidArguments); } // 1. Let a = (de – 1) × GCD(n – 1, de – 1). - let one = BigUint::one(); - let a = Zeroizing::new((d * e - &one) * (n - &one).gcd(&(d * e - &one))); + let bits = d.bits_precision() * 2; + let one = BoxedUint::one().widen(bits); + let e = BoxedUint::from(e).widen(bits); + let d = d.widen(bits); + let n = n.as_ref().widen(bits); + + let a1 = &d * &e - &one; + let a2 = (&n - &one).gcd(&a1); + let a = a1 * a2; + let n = n.widen(a.bits_precision()); // 2. Let m = floor(a /n) and r = a – m n, so that a = m n + r and 0 ≤ r < n. - let m = Zeroizing::new(&*a / n); - let r = Zeroizing::new(&*a - &*m * n); + let m = &a / NonZero::new(n.clone()).expect("checked"); + let r = a - &m * &n; // 3. Let b = ( (n – r)/(m + 1) ) + 1; if b is not an integer or b^2 ≤ 4n, then output an error indicator, // and exit without further processing. - let modulus_check = Zeroizing::new((n - &*r) % (&*m + &one)); - if !modulus_check.is_zero() { + let modulus_check = (&n - &r) % NonZero::new(&m + &one).unwrap(); + if (!modulus_check.is_zero()).into() { return Err(Error::InvalidArguments); } - let b = Zeroizing::new((n - &*r) / (&*m + &one) + one); + let b = ((&n - &r) / NonZero::new(&m + &one).unwrap()) + one; - let four = BigUint::from_u8(4).unwrap(); - let four_n = Zeroizing::new(n * four); - let b_squared = Zeroizing::new(b.pow(2u32)); - if *b_squared <= *four_n { + let four = BoxedUint::from(4u32); + let four_n = &n * four; + let b_squared = b.square(); + + if b_squared <= four_n { return Err(Error::InvalidArguments); } - let b_squared_minus_four_n = Zeroizing::new(&*b_squared - &*four_n); + let b_squared_minus_four_n = b_squared - four_n; // 4. Let ϒ be the positive square root of b^2 – 4n; if ϒ is not an integer, // then output an error indicator, and exit without further processing. - let y = Zeroizing::new(sqrt((*b_squared_minus_four_n).clone())); + let y = b_squared_minus_four_n.sqrt(); - let y_squared = Zeroizing::new(y.pow(2u32)); + let y_squared = y.square(); let sqrt_is_whole_number = y_squared == b_squared_minus_four_n; if !sqrt_is_whole_number { return Err(Error::InvalidArguments); } - let p = (&*b + &*y) / &two; - let q = (&*b - &*y) / two; + + let bits = core::cmp::max(b.bits_precision(), y.bits_precision()); + let two = NonZero::new(BoxedUint::from(2u64)).unwrap().widen(bits); + let p = (&b + &y) / &two; + let q = (b - y) / two; Ok((p, q)) } /// Compute the modulus of a key from its primes. -pub(crate) fn compute_modulus(primes: &[BigUint]) -> BigUint { - primes.iter().product() +pub(crate) fn compute_modulus(primes: &[BoxedUint]) -> Odd { + let mut out = primes[0].clone(); + for p in &primes[1..] { + out = out * p; + } + Odd::new(out).unwrap() } /// Compute the private exponent from its primes (p and q) and public exponent /// This uses Euler's totient function #[inline] pub(crate) fn compute_private_exponent_euler_totient( - primes: &[BigUint], - exp: &BigUint, -) -> Result { + primes: &[BoxedUint], + exp: u64, +) -> Result { if primes.len() < 2 { return Err(Error::InvalidPrime); } - - let mut totient = BigUint::one(); + let bits = primes[0].bits_precision(); + let mut totient = BoxedUint::one_with_precision(bits); for prime in primes { - totient *= prime - BigUint::one(); + totient = totient * (prime - &BoxedUint::one()); } + let exp = BoxedUint::from(exp).widen(totient.bits_precision()); // NOTE: `mod_inverse` checks if `exp` evenly divides `totient` and returns `None` if so. // This ensures that `exp` is not a factor of any `(prime - 1)`. - if let Some(d) = exp.mod_inverse(totient) { - Ok(d.to_biguint().unwrap()) - } else { - // `exp` evenly divides `totient` - Err(Error::InvalidPrime) + match exp.inv_mod(&totient).into_option() { + Some(res) => Ok(res), + None => Err(Error::InvalidPrime), } } @@ -287,16 +325,19 @@ pub(crate) fn compute_private_exponent_euler_totient( /// make Euler's totiem unreliable. #[inline] pub(crate) fn compute_private_exponent_carmicheal( - p: &BigUint, - q: &BigUint, - exp: &BigUint, -) -> Result { - let p1 = p - BigUint::one(); - let q1 = q - BigUint::one(); - - let lcm = p1.lcm(&q1); - if let Some(d) = exp.mod_inverse(lcm) { - Ok(d.to_biguint().unwrap()) + p: &BoxedUint, + q: &BoxedUint, + exp: u64, +) -> Result { + let p1 = p - &BoxedUint::one(); + let q1 = q - &BoxedUint::one(); + + // LCM inlined + let gcd = p1.gcd(&q1); + let lcm = p1 / NonZero::new(gcd).unwrap() * &q1; + let exp = BoxedUint::from(exp).widen(lcm.bits_precision()); + if let Some(d) = exp.inv_mod(&lcm).into() { + Ok(d) } else { // `exp` evenly divides `lcm` Err(Error::InvalidPrime) @@ -305,19 +346,19 @@ pub(crate) fn compute_private_exponent_carmicheal( #[cfg(test)] mod tests { - use num_traits::FromPrimitive; - use super::*; #[test] fn recover_primes_works() { - let n = BigUint::parse_bytes(b"00d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 16).unwrap(); - let e = BigUint::from_u64(65537).unwrap(); - let d = BigUint::parse_bytes(b"00c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 16).unwrap(); - let p = BigUint::parse_bytes(b"00f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61",16).unwrap(); - let q = BigUint::parse_bytes(b"00da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 16).unwrap(); + let bits = 2048; + + let n = BoxedUint::from_be_hex("d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", bits).unwrap(); + let e = 65537; + let d = BoxedUint::from_be_hex("c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", bits).unwrap(); + let p = BoxedUint::from_be_hex("f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61", bits / 2).unwrap(); + let q = BoxedUint::from_be_hex("da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", bits / 2).unwrap(); - let (mut p1, mut q1) = recover_primes(&n, &e, &d).unwrap(); + let (mut p1, mut q1) = recover_primes(&NonZero::new(n).unwrap(), e, &d).unwrap(); if p1 < q1 { std::mem::swap(&mut p1, &mut q1); diff --git a/src/encoding.rs b/src/encoding.rs index 51d5032d..0084ac13 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -5,9 +5,10 @@ use crate::{ traits::{PrivateKeyParts, PublicKeyParts}, - BigUint, RsaPrivateKey, RsaPublicKey, + RsaPrivateKey, RsaPublicKey, }; use core::convert::{TryFrom, TryInto}; +use crypto_bigint::{BoxedUint, NonZero, Odd}; use pkcs8::{ der::Encode, Document, EncodePrivateKey, EncodePublicKey, ObjectIdentifier, SecretDocument, }; @@ -50,13 +51,31 @@ impl TryFrom> for RsaPrivateKey { return Err(pkcs1::Error::Version.into()); } - let n = BigUint::from_bytes_be(pkcs1_key.modulus.as_bytes()); - let e = BigUint::from_bytes_be(pkcs1_key.public_exponent.as_bytes()); - let d = BigUint::from_bytes_be(pkcs1_key.private_exponent.as_bytes()); - let prime1 = BigUint::from_bytes_be(pkcs1_key.prime1.as_bytes()); - let prime2 = BigUint::from_bytes_be(pkcs1_key.prime2.as_bytes()); + let key_malformed = pkcs8::Error::KeyMalformed; + + let bits = + u32::try_from(pkcs1_key.modulus.as_bytes().len()).map_err(|_| key_malformed)? * 8; + + let n = BoxedUint::from_be_slice(pkcs1_key.modulus.as_bytes(), bits) + .map_err(|_| key_malformed)?; + let n = Option::from(Odd::new(n)).ok_or(key_malformed)?; + + // exponent potentially needs padding + let mut e_slice = [0u8; 8]; + let raw_e_slice = pkcs1_key.public_exponent.as_bytes(); + e_slice[8 - raw_e_slice.len()..].copy_from_slice(raw_e_slice); + let e = u64::from_be_bytes(e_slice); + + let d = BoxedUint::from_be_slice(pkcs1_key.private_exponent.as_bytes(), bits) + .map_err(|_| key_malformed)?; + + let prime1 = BoxedUint::from_be_slice(pkcs1_key.prime1.as_bytes(), bits) + .map_err(|_| key_malformed)?; + let prime2 = BoxedUint::from_be_slice(pkcs1_key.prime2.as_bytes(), bits) + .map_err(|_| key_malformed)?; let primes = vec![prime1, prime2]; - RsaPrivateKey::from_components(n, e, d, primes).map_err(|_| pkcs8::Error::KeyMalformed) + + RsaPrivateKey::from_components(n, e, d, primes).map_err(|_| key_malformed) } } @@ -71,8 +90,19 @@ impl TryFrom> for RsaPublicKey { .as_bytes() .ok_or(pkcs8::spki::Error::KeyMalformed)?, )?; - let n = BigUint::from_bytes_be(pkcs1_key.modulus.as_bytes()); - let e = BigUint::from_bytes_be(pkcs1_key.public_exponent.as_bytes()); + + let key_malformed = pkcs8::spki::Error::KeyMalformed; + let bits = + u32::try_from(pkcs1_key.modulus.as_bytes().len()).map_err(|_| key_malformed)? * 8; + let n = BoxedUint::from_be_slice(pkcs1_key.modulus.as_bytes(), bits) + .map_err(|_| key_malformed)?; + + // exponent potentially needs padding + let mut e_slice = [0u8; 8]; + let raw_e_slice = pkcs1_key.public_exponent.as_bytes(); + e_slice[8 - raw_e_slice.len()..].copy_from_slice(raw_e_slice); + let e = u64::from_be_bytes(e_slice); + RsaPublicKey::new(n, e).map_err(|_| pkcs8::spki::Error::KeyMalformed) } } @@ -84,17 +114,26 @@ impl EncodePrivateKey for RsaPrivateKey { return Err(pkcs1::Error::Version.into()); } - let modulus = self.n().to_bytes_be(); - let public_exponent = self.e().to_bytes_be(); - let private_exponent = Zeroizing::new(self.d().to_bytes_be()); - let prime1 = Zeroizing::new(self.primes[0].to_bytes_be()); - let prime2 = Zeroizing::new(self.primes[1].to_bytes_be()); - let exponent1 = Zeroizing::new((self.d() % (&self.primes[0] - 1u8)).to_bytes_be()); - let exponent2 = Zeroizing::new((self.d() % (&self.primes[1] - 1u8)).to_bytes_be()); + let modulus = self.n().to_be_bytes(); + let public_exponent = self.e().to_be_bytes(); + let private_exponent = Zeroizing::new(self.d().to_be_bytes()); + let prime1 = Zeroizing::new(self.primes[0].to_be_bytes()); + let prime2 = Zeroizing::new(self.primes[1].to_be_bytes()); + + let bits = self.d().bits_precision(); + + let exponent1 = Zeroizing::new( + (self.d() % NonZero::new(&self.primes[0].widen(bits) - &BoxedUint::one()).unwrap()) + .to_be_bytes(), + ); + let exponent2 = Zeroizing::new( + (self.d() % NonZero::new(&self.primes[1].widen(bits) - &BoxedUint::one()).unwrap()) + .to_be_bytes(), + ); let coefficient = Zeroizing::new( self.crt_coefficient() .ok_or(pkcs1::Error::Crypto)? - .to_bytes_be(), + .to_be_bytes(), ); let private_key = pkcs1::RsaPrivateKey { @@ -116,8 +155,8 @@ impl EncodePrivateKey for RsaPrivateKey { impl EncodePublicKey for RsaPublicKey { fn to_public_key_der(&self) -> pkcs8::spki::Result { - let modulus = self.n().to_bytes_be(); - let public_exponent = self.e().to_bytes_be(); + let modulus = self.n().to_be_bytes(); + let public_exponent = self.e().to_be_bytes(); let subject_public_key = pkcs1::RsaPublicKey { modulus: pkcs1::UintRef::new(&modulus)?, diff --git a/src/errors.rs b/src/errors.rs index 7a0116bd..50ea15ed 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -66,6 +66,9 @@ pub enum Error { /// Invalid arguments. InvalidArguments, + + /// Decoding error. + Decode(crypto_bigint::DecodeError), } #[cfg(feature = "std")] @@ -95,6 +98,7 @@ impl core::fmt::Display for Error { Error::LabelTooLong => write!(f, "label too long"), Error::InvalidPadLen => write!(f, "invalid padding length"), Error::InvalidArguments => write!(f, "invalid arguments"), + Error::Decode(err) => write!(f, "{:?}", err), } } } @@ -110,6 +114,11 @@ impl From for Error { Error::Pkcs8(err) } } +impl From for Error { + fn from(err: crypto_bigint::DecodeError) -> Error { + Error::Decode(err) + } +} #[cfg(feature = "std")] impl From for signature::Error { diff --git a/src/key.rs b/src/key.rs index b7747d6f..b962ae22 100644 --- a/src/key.rs +++ b/src/key.rs @@ -1,10 +1,8 @@ use alloc::vec::Vec; +use core::cmp::Ordering; use core::hash::{Hash, Hasher}; -use num_bigint::traits::ModInverse; -use num_bigint::Sign::Plus; -use num_bigint::{BigInt, BigUint}; -use num_integer::Integer; -use num_traits::{FromPrimitive, One, ToPrimitive}; +use crypto_bigint::modular::{BoxedMontyForm, BoxedMontyParams}; +use crypto_bigint::{BoxedUint, Integer, NonZero, Odd}; use rand_core::CryptoRngCore; use zeroize::{Zeroize, ZeroizeOnDrop}; #[cfg(feature = "serde")] @@ -22,19 +20,38 @@ use crate::algorithms::rsa::{ use crate::dummy_rng::DummyRng; use crate::errors::{Error, Result}; -use crate::traits::{PaddingScheme, PrivateKeyParts, PublicKeyParts, SignatureScheme}; -use crate::CrtValue; +use crate::traits::keys::{CrtValue, PrivateKeyParts, PublicKeyParts}; +use crate::traits::{PaddingScheme, SignatureScheme}; /// Represents the public part of an RSA key. -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct RsaPublicKey { /// Modulus: product of prime numbers `p` and `q` - n: BigUint, + n: NonZero, /// Public exponent: power to which a plaintext message is raised in /// order to encrypt it. /// /// Typically 0x10001 (65537) - e: BigUint, + e: u64, + + n_params: BoxedMontyParams, +} + +impl Eq for RsaPublicKey {} +impl PartialEq for RsaPublicKey { + #[inline] + fn eq(&self, other: &RsaPublicKey) -> bool { + self.n == other.n && self.e == other.e + } +} + +impl Hash for RsaPublicKey { + fn hash(&self, state: &mut H) { + // Domain separator for RSA private keys + state.write(b"RsaPublicKey"); + Hash::hash(&self.n, state); + Hash::hash(&self.e, state); + } } /// Represents a whole RSA key, public and private parts. @@ -43,9 +60,9 @@ pub struct RsaPrivateKey { /// Public components of the private key. pubkey_components: RsaPublicKey, /// Private exponent - pub(crate) d: BigUint, + pub(crate) d: BoxedUint, /// Prime factors of N, contains >= 2 elements. - pub(crate) primes: Vec, + pub(crate) primes: Vec, /// precomputed values to speed up private operations pub(crate) precomputed: Option, } @@ -87,28 +104,20 @@ impl ZeroizeOnDrop for RsaPrivateKey {} #[derive(Debug, Clone)] pub(crate) struct PrecomputedValues { /// D mod (P-1) - pub(crate) dp: BigUint, + pub(crate) dp: BoxedUint, /// D mod (Q-1) - pub(crate) dq: BigUint, + pub(crate) dq: BoxedUint, /// Q^-1 mod P - pub(crate) qinv: BigInt, + pub(crate) qinv: BoxedMontyForm, - /// CRTValues is used for the 3rd and subsequent primes. Due to a - /// historical accident, the CRT for the first two primes is handled - /// differently in PKCS#1 and interoperability is sufficiently - /// important that we mirror this. - pub(crate) crt_values: Vec, + pub(crate) p_params: BoxedMontyParams, + pub(crate) q_params: BoxedMontyParams, } impl Zeroize for PrecomputedValues { fn zeroize(&mut self) { self.dp.zeroize(); self.dq.zeroize(); - self.qinv.zeroize(); - for val in self.crt_values.iter_mut() { - val.zeroize(); - } - self.crt_values.clear(); } } @@ -126,19 +135,28 @@ impl From for RsaPublicKey { impl From<&RsaPrivateKey> for RsaPublicKey { fn from(private_key: &RsaPrivateKey) -> Self { - let n = private_key.n().clone(); - let e = private_key.e().clone(); - RsaPublicKey { n, e } + let n = PublicKeyParts::n(private_key); + let e = PublicKeyParts::e(private_key); + let n_params = PublicKeyParts::n_params(private_key); + RsaPublicKey { + n: n.clone(), + e, + n_params, + } } } impl PublicKeyParts for RsaPublicKey { - fn n(&self) -> &BigUint { + fn n(&self) -> &NonZero { &self.n } - fn e(&self) -> &BigUint { - &self.e + fn e(&self) -> u64 { + self.e + } + + fn n_params(&self) -> BoxedMontyParams { + self.n_params.clone() } } @@ -178,14 +196,20 @@ impl RsaPublicKey { /// /// This function accepts public keys with a modulus size up to 4096-bits, /// i.e. [`RsaPublicKey::MAX_SIZE`]. - pub fn new(n: BigUint, e: BigUint) -> Result { + pub fn new(n: BoxedUint, e: u64) -> Result { Self::new_with_max_size(n, e, Self::MAX_SIZE) } /// Create a new public key from its components. - pub fn new_with_max_size(n: BigUint, e: BigUint, max_size: usize) -> Result { - let k = Self { n, e }; - check_public_with_max_size(&k, max_size)?; + pub fn new_with_max_size(n: BoxedUint, e: u64, max_size: usize) -> Result { + check_public_with_max_size(&n, e, max_size)?; + + let n_odd = Odd::new(n.clone()).unwrap(); + let n_params = BoxedMontyParams::new(n_odd); + let n = NonZero::new(n).unwrap(); + + let k = Self { n, e, n_params }; + Ok(k) } @@ -195,18 +219,25 @@ impl RsaPublicKey { /// This method is not recommended, and only intended for unusual use cases. /// Most applications should use [`RsaPublicKey::new`] or /// [`RsaPublicKey::new_with_max_size`] instead. - pub fn new_unchecked(n: BigUint, e: BigUint) -> Self { - Self { n, e } + pub fn new_unchecked(n: BoxedUint, e: u64) -> Self { + let n_odd = Odd::new(n.clone()).unwrap(); + let n_params = BoxedMontyParams::new(n_odd); + let n = NonZero::new(n).unwrap(); + Self { n, e, n_params } } } impl PublicKeyParts for RsaPrivateKey { - fn n(&self) -> &BigUint { + fn n(&self) -> &NonZero { &self.pubkey_components.n } - fn e(&self) -> &BigUint { - &self.pubkey_components.e + fn e(&self) -> u64 { + self.pubkey_components.e + } + + fn n_params(&self) -> BoxedMontyParams { + self.pubkey_components.n_params.clone() } } @@ -215,19 +246,18 @@ impl RsaPrivateKey { const EXP: u64 = 65537; /// Generate a new Rsa key pair of the given bit size using the passed in `rng`. - pub fn new(rng: &mut R, bit_size: usize) -> Result { - let exp = BigUint::from_u64(Self::EXP).expect("invalid static exponent"); - Self::new_with_exp(rng, bit_size, &exp) + pub fn new(rng: &mut R, bit_size: usize) -> Result { + Self::new_with_exp(rng, bit_size, Self::EXP) } /// Generate a new RSA key pair of the given bit size and the public exponent /// using the passed in `rng`. /// /// Unless you have specific needs, you should use `RsaPrivateKey::new` instead. - pub fn new_with_exp( + pub fn new_with_exp( rng: &mut R, bit_size: usize, - exp: &BigUint, + exp: u64, ) -> Result { let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?; RsaPrivateKey::from_components(components.n, components.e, components.d, components.primes) @@ -247,26 +277,34 @@ impl RsaPrivateKey { /// /// [NIST SP 800-56B Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf pub fn from_components( - n: BigUint, - e: BigUint, - d: BigUint, - mut primes: Vec, + n: Odd, + e: u64, + d: BoxedUint, + mut primes: Vec, ) -> Result { + let n_params = BoxedMontyParams::new(n.clone()); + let n_c = NonZero::new(n.as_ref().clone()).unwrap(); + let mut should_validate = false; + if primes.len() < 2 { if !primes.is_empty() { return Err(Error::NprimesTooSmall); } // Recover `p` and `q` from `d`. // See method in Appendix C.2: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf - let (p, q) = recover_primes(&n, &e, &d)?; + let (p, q) = recover_primes(&n_c, e, &d)?; primes.push(p); primes.push(q); should_validate = true; } let mut k = RsaPrivateKey { - pubkey_components: RsaPublicKey { n, e }, + pubkey_components: RsaPublicKey { + n: n_c, + e, + n_params, + }, d, primes, precomputed: None, @@ -289,13 +327,13 @@ impl RsaPrivateKey { /// /// Private exponent will be rebuilt using the method defined in /// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47). - pub fn from_p_q(p: BigUint, q: BigUint, public_exponent: BigUint) -> Result { + pub fn from_p_q(p: BoxedUint, q: BoxedUint, public_exponent: u64) -> Result { if p == q { return Err(Error::InvalidPrime); } let n = compute_modulus(&[p.clone(), q.clone()]); - let d = compute_private_exponent_carmicheal(&p, &q, &public_exponent)?; + let d = compute_private_exponent_carmicheal(&p, &q, public_exponent)?; Self::from_components(n, public_exponent, d, vec![p, q]) } @@ -303,7 +341,7 @@ impl RsaPrivateKey { /// Constructs an RSA key pair from its primes. /// /// This will rebuild the private exponent and the modulus. - pub fn from_primes(primes: Vec, public_exponent: BigUint) -> Result { + pub fn from_primes(primes: Vec, public_exponent: u64) -> Result { if primes.len() < 2 { return Err(Error::NprimesTooSmall); } @@ -318,7 +356,7 @@ impl RsaPrivateKey { } let n = compute_modulus(&primes); - let d = compute_private_exponent_euler_totient(&primes, &public_exponent)?; + let d = compute_private_exponent_euler_totient(&primes, public_exponent)?; Self::from_components(n, public_exponent, d, primes) } @@ -337,41 +375,43 @@ impl RsaPrivateKey { return Ok(()); } - let dp = &self.d % (&self.primes[0] - BigUint::one()); - let dq = &self.d % (&self.primes[1] - BigUint::one()); - let qinv = self.primes[1] - .clone() - .mod_inverse(&self.primes[0]) - .ok_or(Error::InvalidPrime)?; - - let mut r: BigUint = &self.primes[0] * &self.primes[1]; - let crt_values: Vec = { - let mut values = Vec::with_capacity(self.primes.len() - 2); - for prime in &self.primes[2..] { - let res = CrtValue { - exp: BigInt::from_biguint(Plus, &self.d % (prime - BigUint::one())), - r: BigInt::from_biguint(Plus, r.clone()), - coeff: BigInt::from_biguint( - Plus, - r.clone() - .mod_inverse(prime) - .ok_or(Error::InvalidCoefficient)? - .to_biguint() - .unwrap(), - ), - }; - r *= prime; - - values.push(res); - } - values - }; + let d = &self.d; + let bits = d.bits_precision(); + let p = self.primes[0].widen(bits); + let q = self.primes[1].widen(bits); + + // TODO: error handling + + let p_odd = Odd::new(p.clone()).unwrap(); + let p_params = BoxedMontyParams::new(p_odd); + let q_odd = Odd::new(q.clone()).unwrap(); + let q_params = BoxedMontyParams::new(q_odd); + + let x = NonZero::new(p.wrapping_sub(&BoxedUint::one())).unwrap(); + let dp = d.rem_vartime(&x); + + let x = NonZero::new(q.wrapping_sub(&BoxedUint::one())).unwrap(); + let dq = d.rem_vartime(&x); + + let qinv = BoxedMontyForm::new(q.clone(), p_params.clone()); + let qinv = qinv.invert(); + if qinv.is_none().into() { + return Err(Error::InvalidPrime); + } + let qinv = qinv.unwrap(); + + debug_assert_eq!(dp.bits_precision(), bits); + debug_assert_eq!(dq.bits_precision(), bits); + debug_assert_eq!(qinv.bits_precision(), bits); + debug_assert_eq!(p_params.bits_precision(), bits); + debug_assert_eq!(q_params.bits_precision(), bits); self.precomputed = Some(PrecomputedValues { dp, dq, qinv, - crt_values, + p_params, + q_params, }); Ok(()) @@ -383,8 +423,11 @@ impl RsaPrivateKey { } /// Compute CRT coefficient: `(1/q) mod p`. - pub fn crt_coefficient(&self) -> Option { - (&self.primes[1]).mod_inverse(&self.primes[0])?.to_biguint() + pub fn crt_coefficient(&self) -> Option { + let p = &self.primes[0]; + let q = &self.primes[1]; + + Option::from(q.inv_mod(p)) } /// Performs basic sanity checks on the key. @@ -393,15 +436,15 @@ impl RsaPrivateKey { check_public(self)?; // Check that Πprimes == n. - let mut m = BigUint::one(); + let mut m = BoxedUint::one_with_precision(self.pubkey_components.n.bits_precision()); for prime in &self.primes { // Any primes ≤ 1 will cause divide-by-zero panics later. - if *prime < BigUint::one() { + if prime < &BoxedUint::one() { return Err(Error::InvalidPrime); } - m *= prime; + m = m.wrapping_mul(prime); } - if m != self.pubkey_components.n { + if m != *self.pubkey_components.n { return Err(Error::InvalidModulus); } @@ -410,11 +453,14 @@ impl RsaPrivateKey { // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required. - let mut de = self.e().clone(); - de *= self.d.clone(); + let d = self.d.widen(2 * self.d.bits_precision()); + let de = d.wrapping_mul(&BoxedUint::from(self.pubkey_components.e)); + for prime in &self.primes { - let congruence: BigUint = &de % (prime - BigUint::one()); - if !congruence.is_one() { + let prime = prime.widen(d.bits_precision()); + let x = NonZero::new(prime.wrapping_sub(&BoxedUint::one())).unwrap(); + let congruence = de.rem_vartime(&x); + if !bool::from(congruence.is_one()) { return Err(Error::InvalidExponent); } } @@ -465,59 +511,58 @@ impl RsaPrivateKey { } impl PrivateKeyParts for RsaPrivateKey { - fn d(&self) -> &BigUint { + fn d(&self) -> &BoxedUint { &self.d } - fn primes(&self) -> &[BigUint] { + fn primes(&self) -> &[BoxedUint] { &self.primes } - fn dp(&self) -> Option<&BigUint> { + fn dp(&self) -> Option<&BoxedUint> { self.precomputed.as_ref().map(|p| &p.dp) } - fn dq(&self) -> Option<&BigUint> { + fn dq(&self) -> Option<&BoxedUint> { self.precomputed.as_ref().map(|p| &p.dq) } - fn qinv(&self) -> Option<&BigInt> { + fn qinv(&self) -> Option<&BoxedMontyForm> { self.precomputed.as_ref().map(|p| &p.qinv) } fn crt_values(&self) -> Option<&[CrtValue]> { - /* for some reason the standard self.precomputed.as_ref().map() doesn't work */ - if let Some(p) = &self.precomputed { - Some(p.crt_values.as_slice()) - } else { - None - } + None + } + + fn p_params(&self) -> Option<&BoxedMontyParams> { + self.precomputed.as_ref().map(|p| &p.p_params) + } + + fn q_params(&self) -> Option<&BoxedMontyParams> { + self.precomputed.as_ref().map(|p| &p.q_params) } } /// Check that the public key is well formed and has an exponent within acceptable bounds. #[inline] pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> { - check_public_with_max_size(public_key, RsaPublicKey::MAX_SIZE) + check_public_with_max_size(public_key.n(), public_key.e(), RsaPublicKey::MAX_SIZE) } /// Check that the public key is well formed and has an exponent within acceptable bounds. #[inline] -fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize) -> Result<()> { - if public_key.n().bits() > max_size { +fn check_public_with_max_size(n: &BoxedUint, e: u64, max_size: usize) -> Result<()> { + if n.bits_precision() as usize > max_size { return Err(Error::ModulusTooLarge); } - let e = public_key - .e() - .to_u64() - .ok_or(Error::PublicExponentTooLarge)?; - - if public_key.e() >= public_key.n() || public_key.n().is_even() { + let eb = BoxedUint::from(e); // TODO: avoid + if &eb >= n || n.is_even().into() { return Err(Error::InvalidModulus); } - if public_key.e().is_even() { + if eb.is_even().into() { return Err(Error::InvalidExponent); } @@ -532,6 +577,20 @@ fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize) Ok(()) } +pub(crate) fn reduce(n: &BoxedUint, p: BoxedMontyParams) -> BoxedMontyForm { + let bits_precision = p.modulus().bits_precision(); + let modulus = NonZero::new(p.modulus().as_ref().clone()).unwrap(); + + let n = match n.bits_precision().cmp(&bits_precision) { + Ordering::Less => n.widen(bits_precision), + Ordering::Equal => n.clone(), + Ordering::Greater => n.shorten(bits_precision), + }; + + let n_reduced = n.rem_vartime(&modulus).widen(p.bits_precision()); + BoxedMontyForm::new(n_reduced, p) +} + #[cfg(feature = "serde")] impl Serialize for RsaPublicKey { fn serialize(&self, serializer: S) -> core::prelude::v1::Result @@ -580,40 +639,45 @@ impl<'de> Deserialize<'de> for RsaPrivateKey { mod tests { use super::*; use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt}; + use crate::traits::{PrivateKeyParts, PublicKeyParts}; use hex_literal::hex; - use num_traits::{FromPrimitive, ToPrimitive}; use pkcs8::DecodePrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; #[test] fn test_from_into() { + let raw_n = BoxedUint::from(101u64); + let n_odd = Odd::new(raw_n.clone()).unwrap(); let private_key = RsaPrivateKey { pubkey_components: RsaPublicKey { - n: BigUint::from_u64(100).unwrap(), - e: BigUint::from_u64(200).unwrap(), + n: NonZero::new(raw_n.clone()).unwrap(), + e: 200u64, + n_params: BoxedMontyParams::new(n_odd), }, - d: BigUint::from_u64(123).unwrap(), + d: BoxedUint::from(123u64), primes: vec![], precomputed: None, }; let public_key: RsaPublicKey = private_key.into(); - assert_eq!(public_key.n().to_u64(), Some(100)); - assert_eq!(public_key.e().to_u64(), Some(200)); + let n_limbs: &[u64] = PublicKeyParts::n(&public_key).as_ref().as_ref(); + assert_eq!(n_limbs, &[101u64]); + assert_eq!(PublicKeyParts::e(&public_key), 200); } fn test_key_basics(private_key: &RsaPrivateKey) { private_key.validate().expect("invalid private key"); assert!( - private_key.d() < private_key.n(), + PrivateKeyParts::d(private_key) < PublicKeyParts::n(private_key).as_ref(), "private exponent too large" ); let pub_key: RsaPublicKey = private_key.clone().into(); - let m = BigUint::from_u64(42).expect("invalid 42"); + let m = BoxedUint::from(42u64); let c = rsa_encrypt(&pub_key, &m).expect("encryption successfull"); + let m2 = rsa_decrypt_and_check::(private_key, None, &c) .expect("unable to decrypt without blinding"); assert_eq!(m, m2); @@ -628,11 +692,11 @@ mod tests { #[test] fn $name() { let mut rng = ChaCha8Rng::from_seed([42; 32]); - let exp = BigUint::from_u64(RsaPrivateKey::EXP).expect("invalid static exponent"); + let exp = RsaPrivateKey::EXP; for _ in 0..10 { let components = - generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap(); + generate_multi_prime_key_with_exp(&mut rng, $multi, $size, exp).unwrap(); let private_key = RsaPrivateKey::from_components( components.n, components.e, @@ -640,7 +704,7 @@ mod tests { components.primes, ) .unwrap(); - assert_eq!(private_key.n().bits(), $size); + assert_eq!(PublicKeyParts::n(&private_key).bits(), $size); test_key_basics(&private_key); } @@ -657,21 +721,34 @@ mod tests { key_generation!(key_generation_multi_5_64, 5, 64); key_generation!(key_generation_multi_8_576, 8, 576); - key_generation!(key_generation_multi_16_1024, 16, 1024); + // TODO: reenable, currently slow + // key_generation!(key_generation_multi_16_1024, 16, 1024); #[test] fn test_negative_decryption_value() { + let bits = 128; let private_key = RsaPrivateKey::from_components( - BigUint::from_bytes_le(&[ - 99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180, - ]), - BigUint::from_bytes_le(&[1, 0, 1]), - BigUint::from_bytes_le(&[ - 81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65, - ]), + Odd::new( + BoxedUint::from_le_slice( + &[ + 99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180, + ], + bits, + ) + .unwrap(), + ) + .unwrap(), + u64::from_le_bytes([1, 0, 1, 0, 0, 0, 0, 0]), + BoxedUint::from_le_slice( + &[ + 81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65, + ], + bits, + ) + .unwrap(), vec![ - BigUint::from_bytes_le(&[105, 101, 60, 173, 19, 153, 3, 192]), - BigUint::from_bytes_le(&[235, 65, 160, 134, 32, 136, 6, 241]), + BoxedUint::from_le_slice(&[105, 101, 60, 173, 19, 153, 3, 192], bits).unwrap(), + BoxedUint::from_le_slice(&[235, 65, 160, 134, 32, 136, 6, 241], bits).unwrap(), ], ) .unwrap(); @@ -691,14 +768,12 @@ mod tests { let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); let priv_tokens = [Token::Str( - "3054020100300d06092a864886f70d01010105000440303e020100020900cc6c\ - 6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d4\ - 6b68cb02046d9a09f102047b4e3a4f020500f45065cc", + "3054020100300d06092a864886f70d01010105000440303e020100020900aaadacc31e2e5119020301000102087e1710295cb2ba81020500b21fdf97020500f54c6acf02040b862461020463ed8f8d0205008bb00f5f", )]; assert_tokens(&priv_key.clone().readable(), &priv_tokens); let priv_tokens = [Token::Str( - "3024300d06092a864886f70d01010105000313003010020900cc6c6130e35b46bf0203010001", + "3024300d06092a864886f70d01010105000313003010020900aaadacc31e2e51190203010001", )]; assert_tokens( &RsaPublicKey::from(priv_key.clone()).readable(), @@ -787,13 +862,18 @@ mod tests { .unwrap(), ]; - RsaPrivateKey::from_components( - BigUint::from_bytes_be(&n), - BigUint::from_bytes_be(&e), - BigUint::from_bytes_be(&d), - primes.iter().map(|p| BigUint::from_bytes_be(p)).collect(), - ) - .unwrap(); + let mut e_raw = [0u8; 8]; + e_raw[..e.len()].copy_from_slice(&e); + let e = u64::from_be_bytes(e_raw); + + let bits = 4096; + let n = Odd::new(BoxedUint::from_be_slice(&n, bits).unwrap()).unwrap(); + let d = BoxedUint::from_be_slice(&d, bits).unwrap(); + let primes = primes + .iter() + .map(|p| BoxedUint::from_be_slice(p, bits / 2).unwrap()) + .collect(); + RsaPrivateKey::from_components(n, e, d, primes).unwrap(); } #[test] @@ -824,42 +904,47 @@ mod tests { // mQIDAQAB // -----END PUBLIC KEY----- - let n = BigUint::from_bytes_be(&hex!( - "90c06207caac3555c0b0947a5e8b681f5af6aed665ff1cd42b6b487f2f7d68f1" - "38f3dbbee6d2f10908507fe6bcf75e7cbd20e9af6ff1c202bcc3dbb45e9bb69b" - "b5d12a354c4b463a50820d16879373ceeb5574fdd9272be3b90d55c1a64855de" - "cf80520e94be2caa56c1737ed0042ef9c99c7ddb6cc76f3ada211ba90beae0fc" - "0a19024e74e474ca5747f0ee327892bf6eebc83974478dbfbebed40d0ffc626c" - "518071df5626abda386eed72585b676efb99b3ba111fb2f4b8fb0323bccb0c9b" - "5aa35e1da54f1cccac3e14fb1d4588d7b9b9f62d4ea6e570c049efcc34101147" - "fd7798549a42d86f9a90cee7fa0dd9f1ff4e10242280824872afd09782757abc" - "46773cab6989c08747193b7aa4c49a0065830a87e6f7e54455758b2c10317267" - "b9187358e41a5e5fef6fcbf81c8bc5e136ad1192aa7f3a5bc9270b22261b3c40" - "211d729d64c776cd8f219126e27227de3c0a40666b8da40c71243673a6187baf" - "8943eadf0c3d3fd150076dad97e286a68185db8523a61e548cba7a6834e4ce98" - "5af954c9eafb9d819a3d14b526a0f8d2fef13ad99ee48f10c3a00f8853d7853a" - "812b7a1c72bed38066f75779690bc12af9eb0d1eb8e2f7c4757c84e415725629" - "d15c4d68c18213f18a86d4ccc08552b3c80c97165de073ac0440af253e8578c4" - "8857f396e5eba6cd01ed1250feb2c32d77939f8be8bd47874151daed87e8c963" - "32f697ea7950bee7a2c12bb484200bcbd08de5aeae6f22ff9922e38075b56026" - "2472f039de08e9362cfdd19c0f0cd0749ebd85bddc3882fb887f9789ed8e388e" - "7e2eb2455399f166d5c9767ff378f8ebea465a0be2d2e3326fe6ed80e5e3050b" - "fb6c6a9dc8731ce4baa4e5b17b131113c79d6f290318095e37e7571a4ba697ab" - "5ea56190131e06d300310064776ba0330907e1cc41acdef4eeaa53964ef30c71" - "023c3cf71af2d1d9e83900ffc80e07ec2442a3dbd50e957686a22f1d8f512364" - "fb71e936f24990a4abcdbef2bea2f98cd77f1d1ca5625942c79347c146dee6e3" - "043eb622f63e627f4ebf20d6056133a4bd0f55dd13dcf429e0e73830969f543c" - "b31d86d9a878ca79d841444359cc0e31c0283fa6dd27b702b7ee05dad12c30f7" - "f84bf1309678efb8da108efcedc423da8587bd127ca082d417c8726f7889fb80" - "326c3fa6fddd507ac7841b2f2e5c8780d486a0d68229ee2957a8ec24e00e4ab4" - "de3fc811a4b5047c2b7920d071e9f2f9b61638dc15fb84cca46cad28e1ef539d" - "bcf249876f2647757b9a5e4f0b2ea6e7aabdf47dae826e9e259428bdb07e5a2a" - "68b98f141f5537be7a590cb3ba15b0bb15824652e8da8f70eb847240058a336a" - "1b6db7f88268aaf89f0b33b905d72c25338b13e61a51873c2d427021a3f29207" - "179ad32f423793f0c090dda025ce41df0e94afbc80ab5eda9b1a268aa2553a99" - )); - - let e = BigUint::from_u64(65537).unwrap(); + let n = BoxedUint::from_be_slice( + &hex!( + " + 90c06207caac3555c0b0947a5e8b681f5af6aed665ff1cd42b6b487f2f7d68f1 + 38f3dbbee6d2f10908507fe6bcf75e7cbd20e9af6ff1c202bcc3dbb45e9bb69b + b5d12a354c4b463a50820d16879373ceeb5574fdd9272be3b90d55c1a64855de + cf80520e94be2caa56c1737ed0042ef9c99c7ddb6cc76f3ada211ba90beae0fc + 0a19024e74e474ca5747f0ee327892bf6eebc83974478dbfbebed40d0ffc626c + 518071df5626abda386eed72585b676efb99b3ba111fb2f4b8fb0323bccb0c9b + 5aa35e1da54f1cccac3e14fb1d4588d7b9b9f62d4ea6e570c049efcc34101147 + fd7798549a42d86f9a90cee7fa0dd9f1ff4e10242280824872afd09782757abc + 46773cab6989c08747193b7aa4c49a0065830a87e6f7e54455758b2c10317267 + b9187358e41a5e5fef6fcbf81c8bc5e136ad1192aa7f3a5bc9270b22261b3c40 + 211d729d64c776cd8f219126e27227de3c0a40666b8da40c71243673a6187baf + 8943eadf0c3d3fd150076dad97e286a68185db8523a61e548cba7a6834e4ce98 + 5af954c9eafb9d819a3d14b526a0f8d2fef13ad99ee48f10c3a00f8853d7853a + 812b7a1c72bed38066f75779690bc12af9eb0d1eb8e2f7c4757c84e415725629 + d15c4d68c18213f18a86d4ccc08552b3c80c97165de073ac0440af253e8578c4 + 8857f396e5eba6cd01ed1250feb2c32d77939f8be8bd47874151daed87e8c963 + 32f697ea7950bee7a2c12bb484200bcbd08de5aeae6f22ff9922e38075b56026 + 2472f039de08e9362cfdd19c0f0cd0749ebd85bddc3882fb887f9789ed8e388e + 7e2eb2455399f166d5c9767ff378f8ebea465a0be2d2e3326fe6ed80e5e3050b + fb6c6a9dc8731ce4baa4e5b17b131113c79d6f290318095e37e7571a4ba697ab + 5ea56190131e06d300310064776ba0330907e1cc41acdef4eeaa53964ef30c71 + 023c3cf71af2d1d9e83900ffc80e07ec2442a3dbd50e957686a22f1d8f512364 + fb71e936f24990a4abcdbef2bea2f98cd77f1d1ca5625942c79347c146dee6e3 + 043eb622f63e627f4ebf20d6056133a4bd0f55dd13dcf429e0e73830969f543c + b31d86d9a878ca79d841444359cc0e31c0283fa6dd27b702b7ee05dad12c30f7 + f84bf1309678efb8da108efcedc423da8587bd127ca082d417c8726f7889fb80 + 326c3fa6fddd507ac7841b2f2e5c8780d486a0d68229ee2957a8ec24e00e4ab4 + de3fc811a4b5047c2b7920d071e9f2f9b61638dc15fb84cca46cad28e1ef539d + bcf249876f2647757b9a5e4f0b2ea6e7aabdf47dae826e9e259428bdb07e5a2a + 68b98f141f5537be7a590cb3ba15b0bb15824652e8da8f70eb847240058a336a + 1b6db7f88268aaf89f0b33b905d72c25338b13e61a51873c2d427021a3f29207 + 179ad32f423793f0c090dda025ce41df0e94afbc80ab5eda9b1a268aa2553a99" + ), + 8192, + ) + .unwrap(); + + let e = 65537; assert_eq!( RsaPublicKey::new(n, e).err().unwrap(), @@ -873,19 +958,19 @@ mod tests { let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap(); assert_eq!(ref_key.validate(), Ok(())); - let primes = ref_key.primes().to_vec(); + let primes = PrivateKeyParts::primes(&ref_key).to_vec(); - let exp = ref_key.e().clone(); + let exp = PublicKeyParts::e(&ref_key); let key = RsaPrivateKey::from_primes(primes, exp).expect("failed to import key from primes"); assert_eq!(key.validate(), Ok(())); - assert_eq!(key.n(), ref_key.n()); + assert_eq!(PublicKeyParts::n(&key), PublicKeyParts::n(&ref_key)); - assert_eq!(key.dp(), ref_key.dp()); - assert_eq!(key.dq(), ref_key.dq()); + assert_eq!(PrivateKeyParts::dp(&key), PrivateKeyParts::dp(&ref_key)); + assert_eq!(PrivateKeyParts::dq(&key), PrivateKeyParts::dq(&ref_key)); - assert_eq!(key.d(), ref_key.d()); + assert_eq!(PrivateKeyParts::d(&key), PrivateKeyParts::d(&ref_key)); } #[test] @@ -895,18 +980,18 @@ mod tests { let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_SP800_PRIV_DER).unwrap(); assert_eq!(ref_key.validate(), Ok(())); - let primes = ref_key.primes().to_vec(); - let exp = ref_key.e().clone(); + let primes = PrivateKeyParts::primes(&ref_key).to_vec(); + let exp = PublicKeyParts::e(&ref_key); let key = RsaPrivateKey::from_p_q(primes[0].clone(), primes[1].clone(), exp) .expect("failed to import key from primes"); assert_eq!(key.validate(), Ok(())); - assert_eq!(key.n(), ref_key.n()); + assert_eq!(PublicKeyParts::n(&key), PublicKeyParts::n(&ref_key)); - assert_eq!(key.dp(), ref_key.dp()); - assert_eq!(key.dq(), ref_key.dq()); + assert_eq!(PrivateKeyParts::dp(&key), PrivateKeyParts::dp(&ref_key)); + assert_eq!(PrivateKeyParts::dq(&key), PrivateKeyParts::dq(&ref_key)); - assert_eq!(key.d(), ref_key.d()); + assert_eq!(PrivateKeyParts::d(&key), PrivateKeyParts::d(&ref_key)); } } diff --git a/src/lib.rs b/src/lib.rs index 2232f37a..f15480d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -222,7 +222,6 @@ extern crate alloc; #[cfg(feature = "std")] extern crate std; -pub use num_bigint::BigUint; pub use rand_core; pub use signature; diff --git a/src/oaep.rs b/src/oaep.rs index 31c07059..4fd30297 100644 --- a/src/oaep.rs +++ b/src/oaep.rs @@ -13,11 +13,10 @@ use alloc::boxed::Box; use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::fmt; +use crypto_bigint::BoxedUint; use digest::{Digest, DynDigest, FixedOutputReset}; -use num_bigint::BigUint; use rand_core::CryptoRngCore; -use zeroize::Zeroizing; use crate::algorithms::oaep::*; use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad}; @@ -194,7 +193,10 @@ fn encrypt( let em = oaep_encrypt(rng, msg, digest, mgf_digest, label, pub_key.size())?; - let int = Zeroizing::new(BigUint::from_bytes_be(&em)); + let int = BoxedUint::from_be_slice( + &em, + crate::traits::keys::PublicKeyParts::n_bits_precision(pub_key), + )?; uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size()) } @@ -215,7 +217,10 @@ fn encrypt_digest(rng, msg, label, pub_key.size())?; - let int = Zeroizing::new(BigUint::from_bytes_be(&em)); + let int = BoxedUint::from_be_slice( + &em, + crate::traits::keys::PublicKeyParts::n_bits_precision(pub_key), + )?; uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size()) } @@ -244,7 +249,12 @@ fn decrypt( return Err(Error::Decryption); } - let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?; + let ciphertext = BoxedUint::from_be_slice( + ciphertext, + crate::traits::keys::PublicKeyParts::n_bits_precision(priv_key), + )?; + + let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext)?; let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?; oaep_decrypt(&mut em, digest, mgf_digest, label, priv_key.size()) @@ -275,7 +285,11 @@ fn decrypt_digest(&mut em, label, priv_key.size()) @@ -289,9 +303,8 @@ mod tests { use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor}; use alloc::string::String; + use crypto_bigint::{BoxedUint, Odd}; use digest::{Digest, DynDigest, FixedOutputReset}; - use num_bigint::BigUint; - use num_traits::FromPrimitive; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaCha8Rng, @@ -330,12 +343,12 @@ mod tests { // -----END RSA PRIVATE KEY----- RsaPrivateKey::from_components( - BigUint::parse_bytes(b"00d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 16).unwrap(), - BigUint::from_u64(65537).unwrap(), - BigUint::parse_bytes(b"00c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 16).unwrap(), + Odd::new(BoxedUint::from_be_hex("d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 2048).unwrap()).unwrap(), + 65537, + BoxedUint::from_be_hex("c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 2048).unwrap(), vec![ - BigUint::parse_bytes(b"00f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61",16).unwrap(), - BigUint::parse_bytes(b"00da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 16).unwrap() + BoxedUint::from_be_hex("f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61", 1024).unwrap(), + BoxedUint::from_be_hex("da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 1024).unwrap() ], ).unwrap() } diff --git a/src/oaep/decrypting_key.rs b/src/oaep/decrypting_key.rs index 83ab2824..02d4e08c 100644 --- a/src/oaep/decrypting_key.rs +++ b/src/oaep/decrypting_key.rs @@ -126,7 +126,7 @@ mod tests { let tokens = [ Token::Struct { name: "DecryptingKey", len: 4 }, Token::Str("inner"), - Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc"), + Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900aaadacc31e2e5119020301000102087e1710295cb2ba81020500b21fdf97020500f54c6acf02040b862461020463ed8f8d0205008bb00f5f"), Token::Str("label"), Token::None, Token::Str("phantom"), diff --git a/src/oaep/encrypting_key.rs b/src/oaep/encrypting_key.rs index 9a9ae290..ec35d952 100644 --- a/src/oaep/encrypting_key.rs +++ b/src/oaep/encrypting_key.rs @@ -97,7 +97,7 @@ mod tests { }, Token::Str("inner"), Token::Str( - "3024300d06092a864886f70d01010105000313003010020900cc6c6130e35b46bf0203010001", + "3024300d06092a864886f70d01010105000313003010020900aaadacc31e2e51190203010001", ), Token::Str("label"), Token::None, diff --git a/src/pkcs1v15.rs b/src/pkcs1v15.rs index aa572c5e..b0f17dd4 100644 --- a/src/pkcs1v15.rs +++ b/src/pkcs1v15.rs @@ -19,11 +19,10 @@ pub use self::{ use alloc::{boxed::Box, vec::Vec}; use core::fmt::Debug; +use crypto_bigint::BoxedUint; use digest::Digest; -use num_bigint::BigUint; use pkcs8::AssociatedOid; use rand_core::CryptoRngCore; -use zeroize::Zeroizing; use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad}; use crate::algorithms::pkcs1v15::*; @@ -127,8 +126,7 @@ impl SignatureScheme for Pkcs1v15Sign { pub_key, self.prefix.as_ref(), hashed, - &BigUint::from_bytes_be(sig), - sig.len(), + &BoxedUint::from_be_slice(sig, sig.len() as u32 * 8)?, ) } } @@ -145,7 +143,10 @@ fn encrypt( key::check_public(pub_key)?; let em = pkcs1v15_encrypt_pad(rng, msg, pub_key.size())?; - let int = Zeroizing::new(BigUint::from_bytes_be(&em)); + let int = BoxedUint::from_be_slice( + &em, + crate::traits::keys::PublicKeyParts::n_bits_precision(pub_key), + )?; uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size()) } @@ -166,7 +167,11 @@ fn decrypt( ) -> Result> { key::check_public(priv_key)?; - let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?; + let ciphertext = BoxedUint::from_be_slice( + ciphertext, + crate::traits::keys::PublicKeyParts::n_bits_precision(priv_key), + )?; + let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext)?; let em = uint_to_zeroizing_be_pad(em, priv_key.size())?; pkcs1v15_encrypt_unpad(em, priv_key.size()) @@ -194,22 +199,18 @@ fn sign( ) -> Result> { let em = pkcs1v15_sign_pad(prefix, hashed, priv_key.size())?; - uint_to_zeroizing_be_pad( - rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(&em))?, - priv_key.size(), - ) + let em = BoxedUint::from_be_slice( + &em, + crate::traits::keys::PublicKeyParts::n_bits_precision(priv_key), + )?; + uint_to_zeroizing_be_pad(rsa_decrypt_and_check(priv_key, rng, &em)?, priv_key.size()) } /// Verifies an RSA PKCS#1 v1.5 signature. #[inline] -fn verify( - pub_key: &RsaPublicKey, - prefix: &[u8], - hashed: &[u8], - sig: &BigUint, - sig_len: usize, -) -> Result<()> { - if sig >= pub_key.n() || sig_len != pub_key.size() { +fn verify(pub_key: &RsaPublicKey, prefix: &[u8], hashed: &[u8], sig: &BoxedUint) -> Result<()> { + let n = crate::traits::keys::PublicKeyParts::n(pub_key); + if sig >= n.as_ref() || sig.bits_precision() != pub_key.n_bits_precision() { return Err(Error::Verification); } @@ -269,10 +270,8 @@ mod tests { SignatureEncoding, Signer, Verifier, }; use base64ct::{Base64, Encoding}; + use crypto_bigint::Odd; use hex_literal::hex; - use num_bigint::BigUint; - use num_traits::FromPrimitive; - use num_traits::Num; use rand_chacha::{ rand_core::{RngCore, SeedableRng}, ChaCha8Rng, @@ -299,12 +298,12 @@ mod tests { // -----END RSA PRIVATE KEY----- RsaPrivateKey::from_components( - BigUint::from_str_radix("9353930466774385905609975137998169297361893554149986716853295022578535724979677252958524466350471210367835187480748268864277464700638583474144061408845077", 10).unwrap(), - BigUint::from_u64(65537).unwrap(), - BigUint::from_str_radix("7266398431328116344057699379749222532279343923819063639497049039389899328538543087657733766554155839834519529439851673014800261285757759040931985506583861", 10).unwrap(), + Odd::new(BoxedUint::from_be_hex("B2990F49C47DFA8CD400AE6A4D1B8A3B6A13642B23F28B003BFB97790ADE9A4CC82B8B2A81747DDEC08B6296E53A08C331687EF25C4BF4936BA1C0E6041E9D15", 512).unwrap()).unwrap(), + 65537, + BoxedUint::from_be_hex("8ABD6A69F4D1A4B487F0AB8D7AAEFD38609405C999984E30F567E1E8AEEFF44E8B18BDB1EC78DFA31A55E32A48D7FB131F5AF1F44D7D6B2CED2A9DF5E5AE4535", 512).unwrap(), vec![ - BigUint::from_str_radix("98920366548084643601728869055592650835572950932266967461790948584315647051443",10).unwrap(), - BigUint::from_str_radix("94560208308847015747498523884063394671606671904944666360068158221458669711639", 10).unwrap() + BoxedUint::from_be_hex("DAB2F18048BAA68DE7DF04D2D35D5D80E60E2DFA42D50A9B04219032715E46B3", 256).unwrap(), + BoxedUint::from_be_hex("D10F2E66B1D0C13F10EF9927BF5324A379CA218146CBF9CAFC795221F16A3117", 256).unwrap() ], ).unwrap() } diff --git a/src/pkcs1v15/decrypting_key.rs b/src/pkcs1v15/decrypting_key.rs index 78aee178..6ff0e850 100644 --- a/src/pkcs1v15/decrypting_key.rs +++ b/src/pkcs1v15/decrypting_key.rs @@ -69,7 +69,7 @@ mod tests { let tokens = [ Token::Struct { name: "DecryptingKey", len: 1 }, Token::Str("inner"), - Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc"), + Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900aaadacc31e2e5119020301000102087e1710295cb2ba81020500b21fdf97020500f54c6acf02040b862461020463ed8f8d0205008bb00f5f"), Token::StructEnd, ]; assert_tokens(&decrypting_key.readable(), &tokens); diff --git a/src/pkcs1v15/encrypting_key.rs b/src/pkcs1v15/encrypting_key.rs index 2850f79d..d12f2b66 100644 --- a/src/pkcs1v15/encrypting_key.rs +++ b/src/pkcs1v15/encrypting_key.rs @@ -51,7 +51,7 @@ mod tests { }, Token::Str("inner"), Token::Str( - "3024300d06092a864886f70d01010105000313003010020900cc6c6130e35b46bf0203010001", + "3024300d06092a864886f70d01010105000313003010020900aaadacc31e2e51190203010001", ), Token::StructEnd, ]; diff --git a/src/pkcs1v15/signature.rs b/src/pkcs1v15/signature.rs index 679911fc..2604f730 100644 --- a/src/pkcs1v15/signature.rs +++ b/src/pkcs1v15/signature.rs @@ -1,10 +1,10 @@ //! `RSASSA-PKCS1-v1_5` signatures. -use crate::algorithms::pad::uint_to_be_pad; use ::signature::SignatureEncoding; -use alloc::{boxed::Box, string::ToString}; +use alloc::boxed::Box; use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex}; -use num_bigint::BigUint; +use crypto_bigint::BoxedUint; + #[cfg(feature = "serde")] use serdect::serde::{de, Deserialize, Serialize}; use spki::{ @@ -15,10 +15,9 @@ use spki::{ /// `RSASSA-PKCS1-v1_5` signatures as described in [RFC8017 § 8.2]. /// /// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2 -#[derive(Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Signature { - pub(super) inner: BigUint, - pub(super) len: usize, + pub(super) inner: BoxedUint, } impl SignatureEncoding for Signature { @@ -35,26 +34,17 @@ impl TryFrom<&[u8]> for Signature { type Error = signature::Error; fn try_from(bytes: &[u8]) -> signature::Result { + let len = bytes.len(); Ok(Self { - inner: BigUint::from_bytes_be(bytes), - len: bytes.len(), + // TODO: how to convert error? + inner: BoxedUint::from_be_slice(bytes, len as u32 * 8).unwrap(), }) } } impl From for Box<[u8]> { fn from(signature: Signature) -> Box<[u8]> { - uint_to_be_pad(signature.inner, signature.len) - .expect("RSASSA-PKCS1-v1_5 length invariants should've been enforced") - .into_boxed_slice() - } -} - -impl Debug for Signature { - fn fmt(&self, fmt: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { - fmt.debug_tuple("Signature") - .field(&self.to_string()) - .finish() + signature.inner.to_be_bytes() } } @@ -113,11 +103,10 @@ mod tests { use super::*; use serde_test::{assert_tokens, Configure, Token}; let signature = Signature { - inner: BigUint::new(Vec::from([42])), - len: 1, + inner: BoxedUint::from(42u32), }; - let tokens = [Token::Str("2a")]; + let tokens = [Token::Str("000000000000002a")]; assert_tokens(&signature.readable(), &tokens); } } diff --git a/src/pkcs1v15/signing_key.rs b/src/pkcs1v15/signing_key.rs index 8914479d..ced45995 100644 --- a/src/pkcs1v15/signing_key.rs +++ b/src/pkcs1v15/signing_key.rs @@ -49,7 +49,7 @@ where } /// Generate a new signing key with a prefix for the digest `D`. - pub fn random(rng: &mut R, bit_size: usize) -> Result { + pub fn random(rng: &mut R, bit_size: usize) -> Result { Ok(Self { inner: RsaPrivateKey::new(rng, bit_size)?, prefix: pkcs1v15_generate_prefix::(), @@ -65,10 +65,7 @@ where /// Generate a new signing key with a prefix for the digest `D`. #[deprecated(since = "0.9.0", note = "use SigningKey::random instead")] - pub fn random_with_prefix( - rng: &mut R, - bit_size: usize, - ) -> Result { + pub fn random_with_prefix(rng: &mut R, bit_size: usize) -> Result { Self::random(rng, bit_size) } } @@ -91,10 +88,7 @@ where } /// Generate a new signing key with an empty prefix. - pub fn random_unprefixed( - rng: &mut R, - bit_size: usize, - ) -> Result { + pub fn random_unprefixed(rng: &mut R, bit_size: usize) -> Result { Ok(Self { inner: RsaPrivateKey::new(rng, bit_size)?, prefix: Vec::new(), @@ -315,7 +309,7 @@ mod tests { let signing_key = SigningKey::::new(priv_key); let tokens = [ - Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc") + Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900aaadacc31e2e5119020301000102087e1710295cb2ba81020500b21fdf97020500f54c6acf02040b862461020463ed8f8d0205008bb00f5f") ]; assert_tokens(&signing_key.readable(), &tokens); diff --git a/src/pkcs1v15/verifying_key.rs b/src/pkcs1v15/verifying_key.rs index fa23e8f7..c74ca372 100644 --- a/src/pkcs1v15/verifying_key.rs +++ b/src/pkcs1v15/verifying_key.rs @@ -85,7 +85,6 @@ where &self.prefix, &digest.finalize(), &signature.inner, - signature.len, ) .map_err(|e| e.into()) } @@ -96,14 +95,7 @@ where D: Digest, { fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> { - verify( - &self.inner, - &self.prefix, - prehash, - &signature.inner, - signature.len, - ) - .map_err(|e| e.into()) + verify(&self.inner, &self.prefix, prehash, &signature.inner).map_err(|e| e.into()) } } @@ -117,7 +109,6 @@ where &self.prefix.clone(), &D::digest(msg), &signature.inner, - signature.len, ) .map_err(|e| e.into()) } @@ -265,7 +256,7 @@ mod tests { let verifying_key = VerifyingKey::::new(pub_key); let tokens = [Token::Str( - "3024300d06092a864886f70d01010105000313003010020900cc6c6130e35b46bf0203010001", + "3024300d06092a864886f70d01010105000313003010020900aaadacc31e2e51190203010001", )]; assert_tokens(&verifying_key.readable(), &tokens); diff --git a/src/pss.rs b/src/pss.rs index 0ae5a7e5..6b40b3a9 100644 --- a/src/pss.rs +++ b/src/pss.rs @@ -21,10 +21,10 @@ pub use self::{ use alloc::{boxed::Box, vec::Vec}; use core::fmt::{self, Debug}; +use crypto_bigint::BoxedUint; use const_oid::AssociatedOid; use digest::{Digest, DynDigest, FixedOutputReset}; -use num_bigint::BigUint; use pkcs1::RsaPssParams; use pkcs8::spki::{der::Any, AlgorithmIdentifierOwned}; use rand_core::CryptoRngCore; @@ -106,7 +106,7 @@ impl SignatureScheme for Pss { verify( pub_key, hashed, - &BigUint::from_bytes_be(sig), + &BoxedUint::from_be_slice(sig, sig.len() as u32 * 8)?, sig.len(), &mut *self.digest, self.salt_len, @@ -127,7 +127,7 @@ impl Debug for Pss { pub(crate) fn verify( pub_key: &RsaPublicKey, hashed: &[u8], - sig: &BigUint, + sig: &BoxedUint, sig_len: usize, digest: &mut dyn DynDigest, salt_len: usize, @@ -138,26 +138,26 @@ pub(crate) fn verify( let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?; - emsa_pss_verify(hashed, &mut em, salt_len, digest, pub_key.n().bits()) + emsa_pss_verify(hashed, &mut em, salt_len, digest, pub_key.n().bits() as _) } pub(crate) fn verify_digest( pub_key: &RsaPublicKey, hashed: &[u8], - sig: &BigUint, - sig_len: usize, + sig: &BoxedUint, salt_len: usize, ) -> Result<()> where D: Digest + FixedOutputReset, { - if sig >= pub_key.n() || sig_len != pub_key.size() { + let n = crate::traits::keys::PublicKeyParts::n(pub_key); + if sig >= n.as_ref() || sig.bits_precision() != pub_key.n_bits_precision() { return Err(Error::Verification); } let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?; - emsa_pss_verify_digest::(hashed, &mut em, salt_len, pub_key.n().bits()) + emsa_pss_verify_digest::(hashed, &mut em, salt_len, pub_key.n().bits() as _) } /// SignPSS calculates the signature of hashed using RSASSA-PSS. @@ -205,10 +205,14 @@ fn sign_pss_with_salt( digest: &mut dyn DynDigest, ) -> Result> { let em_bits = priv_key.n().bits() - 1; - let em = emsa_pss_encode(hashed, em_bits, salt, digest)?; + let em = emsa_pss_encode(hashed, em_bits as _, salt, digest)?; + let em = BoxedUint::from_be_slice( + &em, + crate::traits::keys::PublicKeyParts::n_bits_precision(priv_key), + )?; uint_to_zeroizing_be_pad( - rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?, + rsa_decrypt_and_check(priv_key, blind_rng, &em)?, priv_key.size(), ) } @@ -220,10 +224,14 @@ fn sign_pss_with_salt_digest Result> { let em_bits = priv_key.n().bits() - 1; - let em = emsa_pss_encode_digest::(hashed, em_bits, salt)?; + let em = emsa_pss_encode_digest::(hashed, em_bits as _, salt)?; + let em = BoxedUint::from_be_slice( + &em, + crate::traits::keys::PublicKeyParts::n_bits_precision(priv_key), + )?; uint_to_zeroizing_be_pad( - rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?, + rsa_decrypt_and_check(priv_key, blind_rng, &em)?, priv_key.size(), ) } @@ -255,8 +263,7 @@ mod test { use crate::{RsaPrivateKey, RsaPublicKey}; use hex_literal::hex; - use num_bigint::BigUint; - use num_traits::{FromPrimitive, Num}; + use pkcs1::DecodeRsaPrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use sha1::{Digest, Sha1}; use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner}; @@ -274,36 +281,18 @@ mod test { // tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V // -----END RSA PRIVATE KEY----- - RsaPrivateKey::from_components( - BigUint::from_str_radix( - "9353930466774385905609975137998169297361893554149986716853295022\ - 5785357249796772529585244663504712103678351874807482688642774647\ - 00638583474144061408845077", - 10, - ) - .unwrap(), - BigUint::from_u64(65537).unwrap(), - BigUint::from_str_radix( - "7266398431328116344057699379749222532279343923819063639497049039\ - 3898993285385430876577337665541558398345195294398516730148002612\ - 85757759040931985506583861", - 10, - ) - .unwrap(), - vec![ - BigUint::from_str_radix( - "98920366548084643601728869055592650835572950932266967461790948584315647051443", - 10, - ) - .unwrap(), - BigUint::from_str_radix( - "94560208308847015747498523884063394671606671904944666360068158221458669711639", - 10, - ) - .unwrap(), - ], - ) - .unwrap() + let pem = r#" +-----BEGIN RSA PRIVATE KEY----- +MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0 +fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu +/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu +RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/ +EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A +IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS +tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V +-----END RSA PRIVATE KEY-----"#; + + RsaPrivateKey::from_pkcs1_pem(pem).unwrap() } #[test] @@ -333,6 +322,7 @@ mod test { for (text, sig, expected) in &tests { let digest = Sha1::digest(text.as_bytes()).to_vec(); let result = pub_key.verify(Pss::new::(), &digest, sig); + match expected { true => result.expect("failed to verify"), false => { diff --git a/src/pss/blinded_signing_key.rs b/src/pss/blinded_signing_key.rs index 9f990125..85ca5e31 100644 --- a/src/pss/blinded_signing_key.rs +++ b/src/pss/blinded_signing_key.rs @@ -56,13 +56,13 @@ where /// Create a new random RSASSA-PSS signing key which produces "blinded" /// signatures. /// Digest output size is used as a salt length. - pub fn random(rng: &mut R, bit_size: usize) -> Result { + pub fn random(rng: &mut R, bit_size: usize) -> Result { Self::random_with_salt_len(rng, bit_size, ::output_size()) } /// Create a new random RSASSA-PSS signing key which produces "blinded" /// signatures with a salt of the given length. - pub fn random_with_salt_len( + pub fn random_with_salt_len( rng: &mut R, bit_size: usize, salt_len: usize, @@ -267,7 +267,7 @@ mod tests { ); let tokens = [ - Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc") + Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900aaadacc31e2e5119020301000102087e1710295cb2ba81020500b21fdf97020500f54c6acf02040b862461020463ed8f8d0205008bb00f5f") ]; assert_tokens(&signing_key.readable(), &tokens); } diff --git a/src/pss/signature.rs b/src/pss/signature.rs index ea3d1ce9..065424b9 100644 --- a/src/pss/signature.rs +++ b/src/pss/signature.rs @@ -1,10 +1,10 @@ //! `RSASSA-PSS` signatures. -use crate::algorithms::pad::uint_to_be_pad; use ::signature::SignatureEncoding; -use alloc::{boxed::Box, string::ToString}; +use alloc::boxed::Box; use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex}; -use num_bigint::BigUint; +use crypto_bigint::BoxedUint; + #[cfg(feature = "serde")] use serdect::serde::{de, Deserialize, Serialize}; use spki::{ @@ -15,10 +15,9 @@ use spki::{ /// `RSASSA-PSS` signatures as described in [RFC8017 § 8.1]. /// /// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1 -#[derive(Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct Signature { - pub(super) inner: BigUint, - pub(super) len: usize, + pub(super) inner: BoxedUint, } impl SignatureEncoding for Signature { @@ -35,26 +34,17 @@ impl TryFrom<&[u8]> for Signature { type Error = signature::Error; fn try_from(bytes: &[u8]) -> signature::Result { + let len = bytes.len(); Ok(Self { - len: bytes.len(), - inner: BigUint::from_bytes_be(bytes), + // TODO: how to convert the error? + inner: BoxedUint::from_be_slice(bytes, len as u32 * 8).unwrap(), }) } } impl From for Box<[u8]> { fn from(signature: Signature) -> Box<[u8]> { - uint_to_be_pad(signature.inner, signature.len) - .expect("RSASSA-PKCS1-v1_5 length invariants should've been enforced") - .into_boxed_slice() - } -} - -impl Debug for Signature { - fn fmt(&self, fmt: &mut Formatter<'_>) -> core::result::Result<(), core::fmt::Error> { - fmt.debug_tuple("Signature") - .field(&self.to_string()) - .finish() + signature.inner.to_be_bytes() } } @@ -107,11 +97,10 @@ mod tests { use super::*; use serde_test::{assert_tokens, Configure, Token}; let signature = Signature { - inner: BigUint::new(Vec::from([42])), - len: 1, + inner: BoxedUint::from(42u32), }; - let tokens = [Token::Str("2a")]; + let tokens = [Token::Str("000000000000002a")]; assert_tokens(&signature.readable(), &tokens); } } diff --git a/src/pss/signing_key.rs b/src/pss/signing_key.rs index 0ed526bd..b4b25f0b 100644 --- a/src/pss/signing_key.rs +++ b/src/pss/signing_key.rs @@ -63,12 +63,12 @@ where /// Generate a new random RSASSA-PSS signing key. /// Digest output size is used as a salt length. - pub fn random(rng: &mut R, bit_size: usize) -> Result { + pub fn random(rng: &mut R, bit_size: usize) -> Result { Self::random_with_salt_len(rng, bit_size, ::output_size()) } /// Generate a new random RSASSA-PSS signing key with a salt of the given length. - pub fn random_with_salt_len( + pub fn random_with_salt_len( rng: &mut R, bit_size: usize, salt_len: usize, @@ -291,7 +291,7 @@ mod tests { let signing_key = SigningKey::::new(priv_key); let tokens = [ - Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900cc6c6130e35b46bf0203010001020863de1ac858580019020500f65cff5d020500d46b68cb02046d9a09f102047b4e3a4f020500f45065cc") + Token::Str("3054020100300d06092a864886f70d01010105000440303e020100020900aaadacc31e2e5119020301000102087e1710295cb2ba81020500b21fdf97020500f54c6acf02040b862461020463ed8f8d0205008bb00f5f") ]; assert_tokens(&signing_key.readable(), &tokens); diff --git a/src/pss/verifying_key.rs b/src/pss/verifying_key.rs index 2fd62d37..f6e4d75b 100644 --- a/src/pss/verifying_key.rs +++ b/src/pss/verifying_key.rs @@ -61,7 +61,6 @@ where &self.inner, &digest.finalize(), &signature.inner, - signature.len, self.salt_len, ) .map_err(|e| e.into()) @@ -73,14 +72,8 @@ where D: Digest + FixedOutputReset, { fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> { - verify_digest::( - &self.inner, - prehash, - &signature.inner, - signature.len, - self.salt_len, - ) - .map_err(|e| e.into()) + verify_digest::(&self.inner, prehash, &signature.inner, self.salt_len) + .map_err(|e| e.into()) } } @@ -93,7 +86,6 @@ where &self.inner, &D::digest(msg), &signature.inner, - signature.len, self.salt_len, ) .map_err(|e| e.into()) @@ -236,7 +228,7 @@ mod tests { let verifying_key = VerifyingKey::::new(pub_key); let tokens = [Token::Str( - "3024300d06092a864886f70d01010105000313003010020900cc6c6130e35b46bf0203010001", + "3024300d06092a864886f70d01010105000313003010020900aaadacc31e2e51190203010001", )]; assert_tokens(&verifying_key.readable(), &tokens); diff --git a/src/traits/keys.rs b/src/traits/keys.rs index b218c896..adc78172 100644 --- a/src/traits/keys.rs +++ b/src/traits/keys.rs @@ -1,53 +1,70 @@ //! Traits related to the key components -use num_bigint::{BigInt, BigUint}; +use crypto_bigint::{ + modular::{BoxedMontyForm, BoxedMontyParams}, + BoxedUint, NonZero, +}; use zeroize::Zeroize; /// Components of an RSA public key. pub trait PublicKeyParts { /// Returns the modulus of the key. - fn n(&self) -> &BigUint; + fn n(&self) -> &NonZero; /// Returns the public exponent of the key. - fn e(&self) -> &BigUint; + fn e(&self) -> u64; /// Returns the modulus size in bytes. Raw signatures and ciphertexts for /// or by this public key will have the same size. fn size(&self) -> usize { - (self.n().bits() + 7) / 8 + (self.n().bits() as usize + 7) / 8 + } + + /// Returns the parameters for montgomery operations. + fn n_params(&self) -> BoxedMontyParams; + + /// Returns precision (in bits) of `n`. + fn n_bits_precision(&self) -> u32 { + self.n().bits_precision() } } /// Components of an RSA private key. pub trait PrivateKeyParts: PublicKeyParts { /// Returns the private exponent of the key. - fn d(&self) -> &BigUint; + fn d(&self) -> &BoxedUint; /// Returns the prime factors. - fn primes(&self) -> &[BigUint]; + fn primes(&self) -> &[BoxedUint]; /// Returns the precomputed dp value, D mod (P-1) - fn dp(&self) -> Option<&BigUint>; + fn dp(&self) -> Option<&BoxedUint>; /// Returns the precomputed dq value, D mod (Q-1) - fn dq(&self) -> Option<&BigUint>; + fn dq(&self) -> Option<&BoxedUint>; /// Returns the precomputed qinv value, Q^-1 mod P - fn qinv(&self) -> Option<&BigInt>; + fn qinv(&self) -> Option<&BoxedMontyForm>; /// Returns an iterator over the CRT Values fn crt_values(&self) -> Option<&[CrtValue]>; + + /// Returns the params for `p` if precomupted. + fn p_params(&self) -> Option<&BoxedMontyParams>; + + /// Returns the params for `q` if precomupted. + fn q_params(&self) -> Option<&BoxedMontyParams>; } /// Contains the precomputed Chinese remainder theorem values. #[derive(Debug, Clone)] pub struct CrtValue { /// D mod (prime - 1) - pub(crate) exp: BigInt, + pub(crate) exp: BoxedUint, /// R·Coeff ≡ 1 mod Prime. - pub(crate) coeff: BigInt, + pub(crate) coeff: BoxedUint, /// product of primes prior to this (inc p and q) - pub(crate) r: BigInt, + pub(crate) r: BoxedUint, } impl Zeroize for CrtValue { diff --git a/tests/pkcs1.rs b/tests/pkcs1.rs index 6790e137..9bc2c2d8 100644 --- a/tests/pkcs1.rs +++ b/tests/pkcs1.rs @@ -51,7 +51,7 @@ fn decode_rsa2048_priv_der() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-priv.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -63,9 +63,9 @@ fn decode_rsa2048_priv_der() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -78,7 +78,7 @@ fn decode_rsa2048_priv_der() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" @@ -87,7 +87,7 @@ fn decode_rsa2048_priv_der() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" @@ -104,7 +104,7 @@ fn decode_rsa4096_priv_der() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-priv.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0" "BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375" @@ -124,9 +124,9 @@ fn decode_rsa4096_priv_der() { "F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E" "9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55F" @@ -147,7 +147,7 @@ fn decode_rsa4096_priv_der() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E8" "2596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD" @@ -160,7 +160,7 @@ fn decode_rsa4096_priv_der() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB8" "8E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE8" @@ -181,7 +181,7 @@ fn decode_rsa2048_pub_der() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-pub.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -194,7 +194,7 @@ fn decode_rsa2048_pub_der() { ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); } #[test] @@ -204,7 +204,7 @@ fn decode_rsa4096_pub_der() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-pub.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0" "BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375" @@ -224,7 +224,7 @@ fn decode_rsa4096_pub_der() { "F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); } #[test] @@ -263,7 +263,7 @@ fn decode_rsa2048_priv_pem() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-priv.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -275,9 +275,9 @@ fn decode_rsa2048_priv_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -290,7 +290,7 @@ fn decode_rsa2048_priv_pem() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" @@ -300,7 +300,7 @@ fn decode_rsa2048_priv_pem() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" @@ -319,7 +319,7 @@ fn decode_rsa4096_priv_pem() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-priv.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0" "BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375" @@ -340,9 +340,9 @@ fn decode_rsa4096_priv_pem() { ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E" "9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55F" @@ -363,7 +363,7 @@ fn decode_rsa4096_priv_pem() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E8" "2596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD" @@ -376,7 +376,7 @@ fn decode_rsa4096_priv_pem() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB8" "8E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE8" @@ -398,7 +398,7 @@ fn decode_rsa2048_pub_pem() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-pub.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -410,7 +410,7 @@ fn decode_rsa2048_pub_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); } #[test] @@ -421,7 +421,7 @@ fn decode_rsa4096_pub_pem() { // Extracted using: // $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-pub.pem assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0" "BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375" @@ -441,7 +441,7 @@ fn decode_rsa4096_pub_pem() { "F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); } #[test] diff --git a/tests/pkcs8.rs b/tests/pkcs8.rs index 8f500728..2140bd3b 100644 --- a/tests/pkcs8.rs +++ b/tests/pkcs8.rs @@ -39,7 +39,7 @@ fn decode_rsa2048_priv_der() { // Note: matches PKCS#1 test vectors assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -51,9 +51,9 @@ fn decode_rsa2048_priv_der() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -66,7 +66,7 @@ fn decode_rsa2048_priv_der() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" @@ -75,7 +75,7 @@ fn decode_rsa2048_priv_der() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" @@ -93,7 +93,7 @@ fn decode_rsa2048_pub_der() { // Note: matches PKCS#1 test vectors assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -105,7 +105,7 @@ fn decode_rsa2048_pub_der() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); let _ = pkcs1v15::VerifyingKey::::from_public_key_der(RSA_2048_PUB_DER).unwrap(); } @@ -115,7 +115,7 @@ fn decode_rsa2048_pss_priv_der() { let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PSS_PRIV_DER).unwrap(); assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "AF8B669B7AF6D1677F3DBAAF3F5B36F9012DBE9B91695F18AB8D208D447CCB64" "63C5AE9DA46D865C76CF7EF32CF1CB7E2E1D461F8E71DBC470DD1CB9DE69BEA0" @@ -128,9 +128,9 @@ fn decode_rsa2048_pss_priv_der() { ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "9407C8A9FA426289954A17C02A7C1FDA50FD234C0A8E41EC0AD64289FE24025C" "10AAA5BA37EB482F76DD391F9559FD10D590480EDA4EF7552B1BBA5A9ECCAB3C" @@ -143,7 +143,7 @@ fn decode_rsa2048_pss_priv_der() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "E55FBA212239C846821579BE7E4D44336C700167A478F542032BEBF506D39453" "82670B7D5B08D48E1B4A46EB22E54ABE21867FB6AD96444E00B386FF14710CB6" @@ -153,7 +153,7 @@ fn decode_rsa2048_pss_priv_der() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "C3EC0875ED7B5B96340A9869DD9674B8CF0E52AD4092B57620A6AEA981DA0F10" "13DF610CE1C8B630C111DA7214128E20FF8DA55B4CD8A2E145A8E370BF4F87C8" @@ -170,7 +170,7 @@ fn decode_rsa2048_pss_pub_der() { let key = RsaPublicKey::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap(); assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "AF8B669B7AF6D1677F3DBAAF3F5B36F9012DBE9B91695F18AB8D208D447CCB64" "63C5AE9DA46D865C76CF7EF32CF1CB7E2E1D461F8E71DBC470DD1CB9DE69BEA0" @@ -182,7 +182,7 @@ fn decode_rsa2048_pss_pub_der() { "D502F266FB17433A9F4B08D08DE3C576A670CE90557AF94F67579A3273A5C8DB" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); let _ = pss::VerifyingKey::::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap(); } @@ -217,7 +217,7 @@ fn decode_rsa2048_priv_pem() { // Note: matches PKCS#1 test vectors assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -229,9 +229,9 @@ fn decode_rsa2048_priv_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -244,7 +244,7 @@ fn decode_rsa2048_priv_pem() { ) ); assert_eq!( - &key.primes()[0].to_bytes_be(), + &key.primes()[0].to_be_bytes()[..], &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" @@ -253,7 +253,7 @@ fn decode_rsa2048_priv_pem() { ) ); assert_eq!( - &key.primes()[1].to_bytes_be(), + &key.primes()[1].to_be_bytes()[..], &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" @@ -272,7 +272,7 @@ fn decode_rsa2048_pub_pem() { // Note: matches PKCS#1 test vectors assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -284,7 +284,7 @@ fn decode_rsa2048_pub_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.e().to_be_bytes()[..], &hex!("010001")); let _ = pkcs1v15::VerifyingKey::::from_public_key_pem(RSA_2048_PUB_PEM).unwrap(); } diff --git a/tests/proptests.proptest-regressions b/tests/proptests.proptest-regressions new file mode 100644 index 00000000..145a36aa --- /dev/null +++ b/tests/proptests.proptest-regressions @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +cc 6eb8993a76d99005d1cb0f3d848d5390c3e0f4f2de4a7517eccfb477f74e13a0 # shrinks to private_key = RsaPrivateKey { pubkey_components: RsaPublicKey { n: NonZero(BoxedUint(0x8347C96BF9CDBB267650CB931400D5091139DB988E11C5AAF9EAC86BA5D4EA3EEBA0569077555B3FA4CE0D41300461BF8926A34B7993A48B1F3F69CAB3158DFB)), e: 65537, n_params: BoxedMontyParams { modulus: Odd(BoxedUint(0x8347C96BF9CDBB267650CB931400D5091139DB988E11C5AAF9EAC86BA5D4EA3EEBA0569077555B3FA4CE0D41300461BF8926A34B7993A48B1F3F69CAB3158DFB)), one: BoxedUint(0x7CB83694063244D989AF346CEBFF2AF6EEC6246771EE3A55061537945A2B15C1145FA96F88AAA4C05B31F2BECFFB9E4076D95CB4866C5B74E0C096354CEA7205), r2: BoxedUint(0x70E018F6DD63DB9D8182776C303A6B688E9D44CEE054FF801E11E9DEA040862E9E8EC3E4CC0FF3B0D573D09C381621AB35B7C6CDC49098E583F643AAC2238D65), r3: BoxedUint(0x1ADF6E5E9A880615C0CC586BB70BA0D657CF3F1624A68671A192471E75F4CD56A401C11B483909871F0FA8554275EA17ABA04BE17F88AF9B749F44D591277079), mod_neg_inv: Limb(0xD0EBDD5E695C8ACD) } }, d: BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000002F08B129763E3726F88CC9E2CFEFDC637B40776498C1D5480472118C3FC5A08694CCAE7DCBFD25B7850C79332F5F100111BEED9DC0A7B8D8C37EB657E4985081), primes: [BoxedUint(0x981BE188EF711A1E2C840EC3CE9A7F3B7F5BB8E81F09A5A13E00EF2F895F4213), BoxedUint(0xDCF20F8FD566A26BC0FD581259F9A2AABF0ADB6C01F2A5ADD2AEFA0DEAA5C179)], precomputed: Some(PrecomputedValues { dp: BoxedUint(0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053084D3A51F2BC9E2210C87A8CCA7B8FBFFB12D9EB2F79F1A6061E8B2583116F), dq: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007056BB46DCB044A1190D373C8D76FA186AEE7046686F218251FF19B0FDBFADB1), qinv: BoxedMontyForm { montgomery_form: BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000682511332F037EAFDE67A19620CFDC9961A7FF261F4F185D49E5EF21E2686753), params: BoxedMontyParams { modulus: Odd(BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000981BE188EF711A1E2C840EC3CE9A7F3B7F5BB8E81F09A5A13E00EF2F895F4213)), one: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006BB5F6A9EDD4349E0EF3418B86FD1D88DAF170653B6F050CAD2062140743E1EE), r2: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003C67CD14A702D9D3E7D7790AE0DB96B7E2DA351552A50382262CF0D0BB51E17D), r3: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C83D6B4CE99FAFBB23D7586BA520C62B5206D43755A767BEBB5764A015BF27D), mod_neg_inv: Limb(0xC61D8CFC698327E5) } }, p_params: BoxedMontyParams { modulus: Odd(BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000981BE188EF711A1E2C840EC3CE9A7F3B7F5BB8E81F09A5A13E00EF2F895F4213)), one: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006BB5F6A9EDD4349E0EF3418B86FD1D88DAF170653B6F050CAD2062140743E1EE), r2: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003C67CD14A702D9D3E7D7790AE0DB96B7E2DA351552A50382262CF0D0BB51E17D), r3: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C83D6B4CE99FAFBB23D7586BA520C62B5206D43755A767BEBB5764A015BF27D), mod_neg_inv: Limb(0xC61D8CFC698327E5) }, q_params: BoxedMontyParams { modulus: Odd(BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000DCF20F8FD566A26BC0FD581259F9A2AABF0ADB6C01F2A5ADD2AEFA0DEAA5C179)), one: BoxedUint(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007FFB34771D54239EC9DEDC1D2108D7D70D73B05E764B8E38EEE1014C49C29BF5), r2: BoxedUint(0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000A29B3272D65244B833205BCB2F0670190F04A5C945B416487C3F470C9A6126F6), r3: BoxedUint(0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000033E334261962415DBDE417A3E2844C84E5252176396B638A3873E3B5A75352DE), mod_neg_inv: Limb(0x6092436DE4BA2737) } }) }, msg = []