diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f79c7f9..e82f495a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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,4 @@ jobs: - uses: dtolnay/rust-toolchain@master with: toolchain: nightly-2024-10-06 - - run: cargo test --release --features nightly - run: cargo build --benches diff --git a/Cargo.lock b/Cargo.lock index b7d0dd15..4d6c2c68 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,9 +38,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base16ct" @@ -71,24 +71,24 @@ 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" -version = "0.11.0-rc.2" +version = "0.11.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "939c0e62efa052fb0b2db2c0f7c479ad32e364c192c3aab605a7641de265a1a7" +checksum = "3fd016a0ddc7cb13661bf5576073ce07330a693f8608a1320b4e20561cc12cdc" dependencies = [ "hybrid-array", ] [[package]] name = "block-padding" -version = "0.4.0-rc.1" +version = "0.4.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cac2491ec009b98aa75f36cca2b50e3da7d212918fe953886f6a319042f6016" +checksum = "6868e23cd7a5b2e18fb2e9a583910b88b8d645dd21017aafc5d0439cf16ae6d6" dependencies = [ "hybrid-array", ] @@ -132,13 +132,26 @@ checksum = "68ff6be19477a1bd5441f382916a89bc2a0b2c35db6d41e0f6e8538bf6d6463f" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] +[[package]] +name = "crypto-bigint" +version = "0.6.0-rc.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d748d1f5b807ee6d0df5a548d0130417295c3aaed1dcbbb3d6a2e7106e11fcca" +dependencies = [ + "num-traits", + "rand_core", + "serdect 0.3.0-rc.0", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.2.0-rc.1" @@ -150,6 +163,16 @@ dependencies = [ "rand_core", ] +[[package]] +name = "crypto-primes" +version = "0.6.0-pre.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9fad3f7645c77d3e0269f3e74a8dd25746de992b16bcecbb316059836e0b366" +dependencies = [ + "crypto-bigint", + "rand_core", +] + [[package]] name = "ctr" version = "0.10.0-pre.2" @@ -184,19 +207,19 @@ dependencies = [ [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fnv" @@ -242,18 +265,18 @@ dependencies = [ [[package]] name = "hybrid-array" -version = "0.2.0-rc.11" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5a41e5b0754cae5aaf7915f1df1147ba8d316fc6e019cfcc00fbaba96d5e030" +checksum = "45a9a965bb102c1c891fb017c09a05c965186b1265a207640f323ddd009f9deb" dependencies = [ "typenum", ] [[package]] name = "inout" -version = "0.2.0-rc.0" +version = "0.2.0-rc.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbc33218cf9ce7b927426ee4ad3501bcc5d8c26bf5fb4a82849a083715aca427" +checksum = "de49db00f5add6dad75a57946b75de0f26287a6fc95f4f277d48419200422beb" dependencies = [ "block-padding", "hybrid-array", @@ -270,24 +293,21 @@ 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" -version = "0.2.155" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linux-raw-sys" @@ -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.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "opaque-debug" version = "0.3.1" @@ -361,9 +349,9 @@ dependencies = [ [[package]] name = "pem-rfc7468" -version = "1.0.0-rc.1" +version = "1.0.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c1cde4770761bf6bd336f947b9ac1fe700b0a4ec5867cf66cf08597fe89e8c" +checksum = "c2dfbfa5c6f0906884269722c5478e72fd4d6c0e24fe600332c6d62359567ce1" dependencies = [ "base64ct", ] @@ -371,7 +359,7 @@ dependencies = [ [[package]] name = "pkcs1" version = "0.8.0-rc.1" -source = "git+https://github.com/RustCrypto/formats.git#896142c4aa4c3571eded2dbadc6f55a6843424d0" +source = "git+https://github.com/RustCrypto/formats.git#057aa1fe090884d67402cdd4ea37856061e3c64b" dependencies = [ "der", "pkcs8", @@ -398,7 +386,7 @@ dependencies = [ [[package]] name = "pkcs8" version = "0.11.0-rc.1" -source = "git+https://github.com/RustCrypto/formats.git#896142c4aa4c3571eded2dbadc6f55a6843424d0" +source = "git+https://github.com/RustCrypto/formats.git#057aa1fe090884d67402cdd4ea37856061e3c64b" dependencies = [ "der", "pkcs5", @@ -420,15 +408,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.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -461,9 +452,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -509,9 +500,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rsa" @@ -519,11 +510,11 @@ version = "0.10.0-pre.3" dependencies = [ "base64ct", "const-oid", + "crypto-bigint", + "crypto-primes", "digest", "hex-literal", - "num-bigint-dig", - "num-integer", - "num-traits", + "libm", "pkcs1", "pkcs8", "proptest", @@ -533,7 +524,7 @@ dependencies = [ "rand_xorshift", "serde", "serde_test", - "serdect", + "serdect 0.2.0", "sha1", "sha2", "sha3", @@ -545,15 +536,15 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.52.0", ] [[package]] @@ -591,18 +582,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -611,9 +602,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", ] @@ -628,6 +619,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serdect" +version = "0.3.0-rc.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a504c8ee181e3e594d84052f983d60afe023f4d94d050900be18062bbbf7b58" +dependencies = [ + "base16ct", + "serde", +] + [[package]] name = "sha1" version = "0.11.0-pre.4" @@ -670,18 +671,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.1" @@ -694,15 +683,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.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -711,14 +700,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -735,9 +725,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "universal-hash" @@ -773,11 +763,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", @@ -791,51 +790,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 = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +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 e67140dc..c4cdda75 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,18 +13,18 @@ readme = "README.md" rust-version = "1.81" [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.3", default-features = false } -subtle = { version = "2.1.1", 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.1", default-features = false, features = ["alloc"] } zeroize = { version = "1.5", features = ["alloc"] } +crypto-bigint = { version = "0.6.0-rc.6", default-features = false, features = ["zeroize", "alloc"] } +crypto-primes = { version = "0.6.0-pre.2", default-features = false } +libm = "0.2" # optional dependencies sha1 = { version = "=0.11.0-pre.4", optional = true, default-features = false, features = ["oid"] } @@ -32,6 +32,7 @@ serdect = { version = "0.2.0", optional = true } sha2 = { version = "=0.11.0-pre.4", optional = true, default-features = false, features = ["oid"] } serde = { version = "1.0.184", optional = true, default-features = false, features = ["derive"] } + [dev-dependencies] base64ct = { version = "1", features = ["alloc"] } hex-literal = "0.4.1" @@ -49,15 +50,14 @@ 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/rand"] + [package.metadata.docs.rs] features = ["std", "pem", "serde", "hazmat", "sha2"] @@ -66,6 +66,12 @@ rustdoc-args = ["--cfg", "docsrs"] [profile.dev] opt-level = 2 +[profile.bench] +debug = true + [patch.crates-io] pkcs1 = { git = "https://github.com/RustCrypto/formats.git" } pkcs8 = { git = "https://github.com/RustCrypto/formats.git" } + +# 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 db8a2daa..b70e4914 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/benches/key.rs b/benches/key.rs index bc1e4bca..f08df76f 100644 --- a/benches/key.rs +++ b/benches/key.rs @@ -3,8 +3,8 @@ extern crate test; use base64ct::{Base64, Encoding}; -use num_bigint::BigUint; -use num_traits::{FromPrimitive, Num}; +use crypto_bigint::{BoxedUint, Odd}; +use hex_literal::hex; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use rsa::{Pkcs1v15Encrypt, Pkcs1v15Sign, RsaPrivateKey}; use sha2::{Digest, Sha256}; @@ -19,55 +19,23 @@ const DECRYPT_VAL: &str = "\ rLgZ5Gxv5DM4BtV7Z4m85w=="; fn get_key() -> RsaPrivateKey { + // 2048 bits + + let n = hex!("7163c842b2190a8970942b2764aed42d4124647b6f30e09a2da1c0e256aa2ee24e790c40c96a4bd66d75c371a915e0703c476b4e1a06f1bd38c5a3c10ae3bd30f4ef62a5aa4f512ad145a06c48e96469a22ce8e621e052f0669a8c34155512d82e55447f0b7e18da94bd911ac7b3aabe706843668964593ee71b2e5e484bcf0c7834101ab5d61bba1e63e6237af40489ce36a260dab70add4fbec24d659db0f7cac099b0a3aa4549acde7fc858a793a975e6cf65ca276b743525f0883980f6ad069bec346d787797386d50fe0c9734be967c7d84ae5b8f349b094079457c0c0c6fee34c42a0b832603804f71e49f3320081637512c6cbf2bb81b6f6be239846d"); + let d = hex!("4b97dad7216607064b0d721a431f381e2b6d98524a2095bc1e6bd5ec39c6c9ec3450b2d5db9c328ef3a3d7a11b63eaf57d84f2341159f67e25d917d607427e20a34a41c3c6df8b71e0d9159d85f0ed9bc17345eec140374aef11b2cd638e0c901ee382ff5cfebb3c63290b672fcd1c7ef59ad799b0ed90d49a121ee98587df5cc161c584bc5887ae2a15e787e86ab1e803366150561e0b3b3ae28ebdcf32cd46dff317ed3e1b7590cc300d1d57c9288462d06d9fbe097e52b70dc4fca313ae09906e5fab0c24729b54fe35cc38fe1496419a902f35f08460952bd4783e0e930ba8b520f83eafe6fa6589bbab6e4f4bc5c285672c99f5055eec6a2a30b06e786b"); + + let primes = [ + hex!("ba69948f830c296242da6bf9ae3fddb76a63dbf0761ed3f644bca96a2e1eb75fd1bbd9cd93c72330bcc2a97cfafd12ee27bfde0fb6ac152df2ec4ab12b11265b41bcb531e39f347fdf09e9562a6e5a7c020c6534df61c955dd772cc7b9d461fdeea2f3b83663302cfe5656c235d4ac94c81658ad179919cded8ab1be1e9aa369"), + hex!("9bb7d344184526d29c689eddf0141bf65f013477e36b260e32ae42c680b2c5ada9181bff32b9f1bfbdd3c29f59fcc3f4b9ee4ce6766d18ca2fa4fe5c19d24b436c39a781f7a2972e59e616f58cabbb6132084008fe10ff4dddd054fd2e91cd7d043b8f9795a078816cdb5f2e895394e29c37c3e12de41d4f67f17e64baf92c65"), + ]; + RsaPrivateKey::from_components( - BigUint::from_str_radix( - "1431413293124100665099808488927402060891804903267185832598839685\ - 1334124245188214251956198731333464217832226406088020736932173064\ - 7542143290099799440376409121279434889726446974231909555574359107\ - 6769071277846352498366785281901025949969517731311544711611035852\ - 4558307947613422897787329221478860907963827160223559690523660574\ - 3290119275312896557118605046305737666092393325692108313256338401\ - 7468394455366735221967093040859332166137547388514797387908699400\ - 6440025257225431977751512374815915392249179976902953721486040787\ - 7928018498182544654866337918267668730766171167270730778215846767\ - 15609985777563958286637185868165868520557", - 10, - ) - .unwrap(), - BigUint::from_u32(3).unwrap(), - BigUint::from_str_radix( - "9542755287494004433998723259516013739278699355114572217325597900\ - 8894161634588095013041324875556428118881509373920138246214487098\ - 3614288600665329602509394141862899264842979828212730370495727384\ - 5127141852309016655778568546006839666463451542076964744073572349\ - 7055386317422819318582194809859072719758847734823729668476398538\ - 9789061545660559807108818983867672883683301225406598325963853810\ - 7719766738032720239892094196108713378822882383694456030043492571\ - 0634419438471959395497732716946476575496586033656294586102738212\ - 9223264633471761267451999753390105279033427966175417649059304194\ - 1863932308687197618671528035670452762731", - 10, - ) - .unwrap(), + Odd::new(BoxedUint::from_be_slice(&n, 2048).unwrap()).unwrap(), + BoxedUint::from(3u32), + BoxedUint::from_be_slice(&d, 2048).unwrap(), vec![ - BigUint::from_str_radix( - "1309032551829967224267716136060777552955833291350673401529471728\ - 6841580902753737630619317962429887421560827080205434760983677647\ - 3930072411958753044562214537013874103802006369634761074377213995\ - 9838767887180338501537194216954687042766949830326444169308790939\ - 14927146648402139231293035971427838068945045019075433", - 10, - ) - .unwrap(), - BigUint::from_str_radix( - "1093489456104854535775747676525274729242892295382866496612409389\ - 8802036700547572798825343864756095857350615944953879354047282981\ - 5903949343191091817779240101054552748665267574271163617694640513\ - 5496938413378206027265967563510061495188309322612466987663553478\ - 98158548465400674856021497190430791824869615170301029", - 10, - ) - .unwrap(), + BoxedUint::from_be_slice(&primes[0], 1024).unwrap(), + BoxedUint::from_be_slice(&primes[1], 1024).unwrap(), ], ) .unwrap() diff --git a/src/algorithms/generate.rs b/src/algorithms/generate.rs index 7fa8acc1..fd3f479c 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: BoxedUint, + 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: BoxedUint, ) -> Result { if nprimes < 2 { return Err(Error::NprimesTooSmall); @@ -44,7 +42,10 @@ pub(crate) fn generate_multi_prime_key_with_exp( let prime_limit = (1u64 << (bit_size / nprimes) as u64) as f64; // pi aproximates the number of primes less than prime_limit + #[cfg(feature = "std")] let mut pi = prime_limit / (prime_limit.ln() - 1f64); + #[cfg(not(feature = "std"))] + let mut pi = prime_limit / (libm::logf(prime_limit as f32) as f64 - 1f64); // Generated primes start with 0b11, so we can only use a quarter of them. pi /= 4f64; // Use a factor of two to ensure that key generation terminates in a @@ -56,9 +57,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 +79,9 @@ 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; + *prime = generate_prime_with_rng(rng, bits); + todo -= prime.bits() as usize; } // Makes sure that primes is pairwise unequal. @@ -93,14 +95,14 @@ 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. continue 'next; } - if let Ok(d) = compute_private_exponent_euler_totient(&primes, exp) { + if let Ok(d) = compute_private_exponent_euler_totient(&primes, &exp) { n_final = n; d_final = d; break; @@ -109,7 +111,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 +120,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 +127,13 @@ 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"); + let exp = BoxedUint::from(EXP); + 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.clone()); + let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, exp.clone()); + let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, exp.clone()); + let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, exp.clone()); } } @@ -141,11 +142,11 @@ mod tests { #[test] fn $name() { let mut rng = ChaCha8Rng::from_seed([42; 32]); - let exp = BigUint::from_u64(EXP).expect("invalid static exponent"); - + let exp = BoxedUint::from(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.clone()) + .unwrap(); assert_eq!(components.n.bits(), $size); assert_eq!(components.primes.len(), $multi); } @@ -162,5 +163,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..19f1fd85 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}; @@ -19,16 +19,26 @@ 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. +/// In some cases BoxedUint might already have leading zeroes, this function removes them +/// before padding again. #[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> { + let required_bits = input.bits(); + let input = input.shorten(required_bits); + + 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. +/// In some cases BoxedUint might already have leading zeroes, this function removes them +/// before padding again. #[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 required_bits = input.bits(); + let input = input.shorten(required_bits); + 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..e6ce6570 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, 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) + } else { + // We have the precalculated values needed for the CRT. + + let dp = priv_key.dp().expect("precomputed"); + let dq = priv_key.dq().expect("precomputed"); + let qinv = priv_key.qinv().expect("precomputed"); + let p_params = priv_key.p_params().expect("precomputed"); + let q_params = priv_key.q_params().expect("precomputed"); + + 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,179 @@ 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, key.e(), n_params); + // c * r^e (mod n) + let c = mul_mod_params(c, &rpowe, n_params); rpowe.zeroize(); c }; - (c, unblinder) + let ir = ir.expect("loop exited"); + 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.clone()); + (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: &BoxedUint, + 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 <= &BoxedUint::from(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 = 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).expect("adding 1"); + 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).expect("adding one")) + 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)) + .expect("2 is non zero") + .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 primes = primes.iter(); + let mut out = primes.next().expect("must at least be one prime").clone(); + for p in primes { + out = out * p; + } + Odd::new(out).expect("modulus must be odd") } /// 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: &BoxedUint, +) -> 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 = 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 +328,20 @@ 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: &BoxedUint, +) -> Result { + let one = BoxedUint::one(); + let p1 = p - &one; + let q1 = q - &one; + + // LCM inlined + let gcd = p1.gcd(&q1); + let lcm = p1 / NonZero::new(gcd).expect("gcd is non zero") * &q1; + let exp = 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 +350,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 = BoxedUint::from(65_537u64); + 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 d487de39..94c4cb1b 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::{asn1::OctetStringRef, Encode}, Document, EncodePrivateKey, EncodePublicKey, ObjectIdentifier, SecretDocument, @@ -51,13 +52,32 @@ 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)?; + + let bits_e = u32::try_from(pkcs1_key.public_exponent.as_bytes().len()) + .map_err(|_| key_malformed)? + * 8; + let e = BoxedUint::from_be_slice(pkcs1_key.public_exponent.as_bytes(), bits_e) + .map_err(|_| key_malformed)?; + let e = Option::from(e).ok_or(key_malformed)?; + + 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) } } @@ -72,8 +92,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)?; + + let bits_e = u32::try_from(pkcs1_key.public_exponent.as_bytes().len()) + .map_err(|_| key_malformed)? + * 8; + let e = BoxedUint::from_be_slice(pkcs1_key.public_exponent.as_bytes(), bits_e) + .map_err(|_| key_malformed)?; + RsaPublicKey::new(n, e).map_err(|_| pkcs8::spki::Error::KeyMalformed) } } @@ -85,17 +116,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 { @@ -121,8 +161,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 68f34d6e..0db026f4 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,39 @@ 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, + /// Typically `0x10001` (`65537`) + e: BoxedUint, + + 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,10 +61,10 @@ 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, - /// precomputed values to speed up private operations + pub(crate) primes: Vec, + /// Precomputed values to speed up private operations pub(crate) precomputed: Option, } @@ -87,28 +105,27 @@ 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, + /// Montgomery params for `p` + pub(crate) p_params: BoxedMontyParams, + /// Montgomery params for `q` + pub(crate) q_params: BoxedMontyParams, } +impl ZeroizeOnDrop for PrecomputedValues {} + 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(); + // TODO: once these have landed in crypto-bigint + // self.p_params.zeroize(); + // self.q_params.zeroize(); } } @@ -126,20 +143,29 @@ 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: e.clone(), + n_params: n_params.clone(), + } } } impl PublicKeyParts for RsaPublicKey { - fn n(&self) -> &BigUint { + fn n(&self) -> &NonZero { &self.n } - fn e(&self) -> &BigUint { + fn e(&self) -> &BoxedUint { &self.e } + + fn n_params(&self) -> &BoxedMontyParams { + &self.n_params + } } impl RsaPublicKey { @@ -178,15 +204,21 @@ 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: BoxedUint) -> 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)?; - Ok(k) + pub fn new_with_max_size(n: BoxedUint, e: BoxedUint, max_size: usize) -> Result { + check_public_with_max_size(&n, &e, max_size)?; + + let n_odd = Odd::new(n.clone()) + .into_option() + .ok_or(Error::InvalidModulus)?; + let n_params = BoxedMontyParams::new(n_odd); + let n = NonZero::new(n).expect("checked above"); + + Ok(Self { n, e, n_params }) } /// Create a new public key, bypassing checks around the modulus and public @@ -195,19 +227,27 @@ 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: BoxedUint) -> Self { + let n_odd = Odd::new(n.clone()).expect("n must be odd"); + let n_params = BoxedMontyParams::new(n_odd); + let n = NonZero::new(n).expect("odd numbers are non zero"); + + 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 { + fn e(&self) -> &BoxedUint { &self.pubkey_components.e } + + fn n_params(&self) -> &BoxedMontyParams { + &self.pubkey_components.n_params + } } impl RsaPrivateKey { @@ -215,19 +255,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, BoxedUint::from(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: BoxedUint, ) -> 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,24 +286,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: BoxedUint, + d: BoxedUint, + mut primes: Vec, ) -> Result { - if primes.len() < 2 { - if !primes.is_empty() { - return Err(Error::NprimesTooSmall); + let n_params = BoxedMontyParams::new(n.clone()); + let n_c = NonZero::new(n.get()) + .into_option() + .ok_or(Error::InvalidModulus)?; + + match primes.len() { + 0 => { + // 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_c, &e, &d)?; + primes.push(p); + primes.push(q); } - // 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)?; - primes.push(p); - primes.push(q); + 1 => return Err(Error::NprimesTooSmall), + _ => {} } let mut k = RsaPrivateKey { - pubkey_components: RsaPublicKey { n, e }, + pubkey_components: RsaPublicKey { + n: n_c, + e, + n_params, + }, d, primes, precomputed: None, @@ -273,8 +322,8 @@ impl RsaPrivateKey { // Alaways validate the key, to ensure precompute can't fail k.validate()?; - // precompute when possible, ignore error otherwise. - let _ = k.precompute(); + // Precompute when possible, ignore error otherwise. + k.precompute().ok(); Ok(k) } @@ -285,26 +334,34 @@ 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: BoxedUint, + ) -> 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 primes = vec![p, q]; + let n = compute_modulus(&primes); - Self::from_components(n, public_exponent, d, vec![p, q]) + Self::from_components(n, public_exponent, d, primes) } /// 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: BoxedUint, + ) -> Result { if primes.len() < 2 { return Err(Error::NprimesTooSmall); } - // Makes sure that primes is pairwise unequal. + // Makes sure that the primes are pairwise unequal. for (i, prime1) in primes.iter().enumerate() { for prime2 in primes.iter().take(i) { if prime1 == prime2 { @@ -333,41 +390,45 @@ 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]) + let d = &self.d; + let bits = d.bits_precision(); + let p = self.primes[0].widen(bits); + let q = self.primes[1].widen(bits); + + let p_odd = Odd::new(p.clone()) + .into_option() .ok_or(Error::InvalidPrime)?; + let p_params = BoxedMontyParams::new(p_odd); + let q_odd = Odd::new(q.clone()) + .into_option() + .ok_or(Error::InvalidPrime)?; + let q_params = BoxedMontyParams::new(q_odd); - 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 x = NonZero::new(p.wrapping_sub(&BoxedUint::one())) + .into_option() + .ok_or(Error::InvalidPrime)?; + let dp = d.rem_vartime(&x); + + let x = NonZero::new(q.wrapping_sub(&BoxedUint::one())) + .into_option() + .ok_or(Error::InvalidPrime)?; + let dq = d.rem_vartime(&x); + + let qinv = BoxedMontyForm::new(q.clone(), p_params.clone()); + let qinv = qinv.invert().into_option().ok_or(Error::InvalidPrime)?; + + 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(()) @@ -379,8 +440,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. @@ -389,15 +453,16 @@ 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()); + let one = BoxedUint::one(); for prime in &self.primes { // Any primes ≤ 1 will cause divide-by-zero panics later. - if *prime < BigUint::one() { + if prime < &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); } @@ -406,11 +471,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(&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); } } @@ -461,73 +529,85 @@ 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: &BoxedUint, 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() { + if e >= n || n.is_even().into() || n.is_zero().into() { return Err(Error::InvalidModulus); } - if public_key.e().is_even() { + if e.is_even().into() { return Err(Error::InvalidExponent); } - if e < RsaPublicKey::MIN_PUB_EXPONENT { + if e < &BoxedUint::from(RsaPublicKey::MIN_PUB_EXPONENT) { return Err(Error::PublicExponentTooSmall); } - if e > RsaPublicKey::MAX_PUB_EXPONENT { + if e > &BoxedUint::from(RsaPublicKey::MAX_PUB_EXPONENT) { return Err(Error::PublicExponentTooLarge); } Ok(()) } +pub(crate) fn reduce(n: &BoxedUint, p: &BoxedMontyParams) -> BoxedMontyForm { + let bits_precision = p.modulus().bits_precision(); + let modulus = p.modulus().as_nz_ref().clone(); + + 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.clone()) +} + #[cfg(feature = "serde")] impl Serialize for RsaPublicKey { fn serialize(&self, serializer: S) -> core::prelude::v1::Result @@ -576,40 +656,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: BoxedUint::from(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), &BoxedUint::from(200u64)); } 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); @@ -624,11 +709,12 @@ 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 = BoxedUint::from(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.clone()) + .unwrap(); let private_key = RsaPrivateKey::from_components( components.n, components.e, @@ -636,7 +722,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); } @@ -653,21 +739,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(), + BoxedUint::from_le_slice(&[1, 0, 1, 0, 0, 0, 0, 0], 64).unwrap(), + 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(); @@ -687,14 +786,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(), @@ -783,12 +880,16 @@ mod tests { .unwrap(), ]; - let res = 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(), - ); + let e = BoxedUint::from_be_slice(&e, 64).unwrap(); + + 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(); + let res = RsaPrivateKey::from_components(n, e, d, primes); assert_eq!(res, Err(Error::InvalidModulus)); } @@ -820,42 +921,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 = BoxedUint::from(65_537u64); assert_eq!( RsaPublicKey::new(n, e).err().unwrap(), @@ -869,19 +975,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 key = - RsaPrivateKey::from_primes(primes, exp).expect("failed to import key from primes"); + let exp = PublicKeyParts::e(&ref_key); + let key = RsaPrivateKey::from_primes(primes, exp.clone()) + .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] @@ -891,18 +997,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) + let key = RsaPrivateKey::from_p_q(primes[0].clone(), primes[1].clone(), exp.clone()) .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..900da380 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] #![warn(missing_docs)] +#![cfg_attr(not(test), deny(clippy::unwrap_used))] //! # Supported algorithms //! @@ -222,7 +223,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..42765b47 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}; @@ -55,14 +54,17 @@ impl Oaep { /// ``` /// use sha1::Sha1; /// use sha2::Sha256; - /// use rsa::{BigUint, RsaPublicKey, Oaep, }; + /// use rsa::{RsaPublicKey, Oaep}; /// use base64ct::{Base64, Encoding}; + /// use crypto_bigint::BoxedUint; /// - /// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap(); - /// let e = Base64::decode_vec("AQAB").unwrap(); + /// let n_bytes = Base64::decode_vec("seAOhmYFAjH6NOaB54dboqw86uPXV/oK9ayJGV4mVClbvsDBJmF3bVkOaVMp9ogcFJTFFSy5g2HsTZIfHyuQVUJADb+BeRnkYrYhRvNJOKj2pcDbkxYe9XGMx8pIvxkDFnIpusb3gUsuzMUAU5qIstjwQKzuD51c6uJi0HAtQkr6Wmlt34SX7xkD/MfRuTu9uqmHmkiiJaCDHB2reYTPguetSWfuvp1qBJDNgSsp7BjwYANWldyrmZ8cLXEXYMUG5vtsWMxUzl8ertEr6kbnGM0OJghNuEtittW/dfTPvk683R1jj0hNaMzvHK8xYldUlLuwmWCYIIvpHBaA/w+FwQ==").unwrap(); + /// let e_bytes = Base64::decode_vec("AQAB").unwrap(); + /// let n = BoxedUint::from_be_slice(&n_bytes, 2048).unwrap(); + /// let e = BoxedUint::from_be_slice(&e_bytes, 32).unwrap(); /// /// let mut rng = rand::thread_rng(); - /// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap(); + /// let key = RsaPublicKey::new(n, e).unwrap(); /// let padding = Oaep::new::(); /// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap(); /// ``` @@ -92,14 +94,17 @@ impl Oaep { /// ``` /// use sha1::Sha1; /// use sha2::Sha256; - /// use rsa::{BigUint, RsaPublicKey, Oaep, }; + /// use rsa::{RsaPublicKey, Oaep}; /// use base64ct::{Base64, Encoding}; + /// use crypto_bigint::BoxedUint; /// - /// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap(); - /// let e = Base64::decode_vec("AQAB").unwrap(); + /// let n_bytes = Base64::decode_vec("seAOhmYFAjH6NOaB54dboqw86uPXV/oK9ayJGV4mVClbvsDBJmF3bVkOaVMp9ogcFJTFFSy5g2HsTZIfHyuQVUJADb+BeRnkYrYhRvNJOKj2pcDbkxYe9XGMx8pIvxkDFnIpusb3gUsuzMUAU5qIstjwQKzuD51c6uJi0HAtQkr6Wmlt34SX7xkD/MfRuTu9uqmHmkiiJaCDHB2reYTPguetSWfuvp1qBJDNgSsp7BjwYANWldyrmZ8cLXEXYMUG5vtsWMxUzl8ertEr6kbnGM0OJghNuEtittW/dfTPvk683R1jj0hNaMzvHK8xYldUlLuwmWCYIIvpHBaA/w+FwQ==").unwrap(); + /// let e_bytes = Base64::decode_vec("AQAB").unwrap(); + /// let n = BoxedUint::from_be_slice(&n_bytes, 2048).unwrap(); + /// let e = BoxedUint::from_be_slice(&e_bytes, 32).unwrap(); /// /// let mut rng = rand::thread_rng(); - /// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap(); + /// let key = RsaPublicKey::new(n, e).unwrap(); /// let padding = Oaep::new_with_mgf_hash::(); /// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap(); /// ``` @@ -194,7 +199,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 +223,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 +255,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 +291,11 @@ fn decrypt_digest(&mut em, label, priv_key.size()) @@ -289,9 +309,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 +349,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(), + BoxedUint::from(65_537u64), + 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..e4fe716d 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(), + BoxedUint::from(65_537u64), + 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..3200b0a4 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,21 @@ impl TryFrom<&[u8]> for Signature { type Error = signature::Error; fn try_from(bytes: &[u8]) -> signature::Result { - Ok(Self { - inner: BigUint::from_bytes_be(bytes), - len: bytes.len(), - }) + let len = bytes.len(); + let inner = BoxedUint::from_be_slice(bytes, len as u32 * 8); + #[cfg(feature = "std")] + let inner = inner + .map_err(|e| Box::new(e) as Box)?; + #[cfg(not(feature = "std"))] + let inner = inner.map_err(|_| signature::Error::new())?; + + Ok(Self { inner }) } } 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 +107,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 b0da5293..01a84088 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..7c2ccb22 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(), ) } @@ -249,14 +257,13 @@ where }) } -#[cfg(test)] +#[cfg(all(test, feature = "pem"))] mod test { use crate::pss::{BlindedSigningKey, Pss, Signature, SigningKey, VerifyingKey}; 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 c96c4330..d481c04a 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..a95ecfbc 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,22 @@ impl TryFrom<&[u8]> for Signature { type Error = signature::Error; fn try_from(bytes: &[u8]) -> signature::Result { - Ok(Self { - len: bytes.len(), - inner: BigUint::from_bytes_be(bytes), - }) + let len = bytes.len(); + let inner = BoxedUint::from_be_slice(bytes, len as u32 * 8); + + #[cfg(feature = "std")] + let inner = inner + .map_err(|e| Box::new(e) as Box)?; + #[cfg(not(feature = "std"))] + let inner = inner.map_err(|_| signature::Error::new())?; + + Ok(Self { inner }) } } 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 +102,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 16a8f0fa..712e9587 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 8c4af749..c24f0f54 100644 --- a/src/pss/verifying_key.rs +++ b/src/pss/verifying_key.rs @@ -66,7 +66,6 @@ where &self.inner, &digest.finalize(), &signature.inner, - signature.len, self.salt_len, ) .map_err(|e| e.into()) @@ -78,14 +77,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()) } } @@ -98,7 +91,6 @@ where &self.inner, &D::digest(msg), &signature.inner, - signature.len, self.salt_len, ) .map_err(|e| e.into()) @@ -241,7 +233,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..ca871363 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) -> &BoxedUint; /// 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..f78879b2 100644 --- a/tests/pkcs1.rs +++ b/tests/pkcs1.rs @@ -1,11 +1,13 @@ //! PKCS#1 encoding tests +use crypto_bigint::BoxedUint; use hex_literal::hex; use rsa::{ pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey}, traits::{PrivateKeyParts, PublicKeyParts}, RsaPrivateKey, RsaPublicKey, }; +use subtle::ConstantTimeEq; #[cfg(feature = "pem")] use rsa::pkcs1::LineEnding; @@ -51,7 +53,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 +65,10 @@ fn decode_rsa2048_priv_der() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -77,24 +80,29 @@ fn decode_rsa2048_priv_der() { "ABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" "ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBE" "B143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67" - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); + + let expected_prime = BoxedUint::from_be_slice( &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" "8DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B" "02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9" - ) - ); + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); } #[test] @@ -104,7 +112,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 +132,10 @@ fn decode_rsa4096_priv_der() { "F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E" "9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55F" @@ -146,8 +155,7 @@ fn decode_rsa4096_priv_der() { "EF6BE3364969E1337C91B29A07B9A913CDE40CE2D5530C900E73751685E65431" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E8" "2596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD" @@ -157,10 +165,13 @@ fn decode_rsa4096_priv_der() { "1BE60761F19F74672489EAF9F215409F39956E77A82183F1F72BB2FEDDF1B9FB" "FC4AD89EA445809DDBD5BD595277990C0BE9366FBB2ECF7B057CC1C3DC8FB77B" "F8456D07BBC95B3C1815F48E62B81468C3D4D9D96C0F48DAB04993BE8D91EDE5" - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + ), + 2048, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); + + let expected_prime = BoxedUint::from_be_slice( &hex!( "CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB8" "8E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE8" @@ -170,8 +181,11 @@ fn decode_rsa4096_priv_der() { "4A15823F5107C89548EDDCB61DA5308C6CC834D4A0C16DFA6CA1D67B61A65677" "EB1719CD125D0EF0DB8802FB76CFC17577BCB2510AE294E1BF8A9173A2B85C16" "A6B508C98F2D770B7F3DE48D9E720C53E263680B57E7109410015745570652FD" - ) - ); + ), + 2048, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); } #[test] @@ -181,7 +195,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 +208,8 @@ fn decode_rsa2048_pub_der() { ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); } #[test] @@ -204,7 +219,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 +239,8 @@ fn decode_rsa4096_pub_der() { "F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); } #[test] @@ -263,7 +279,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 +291,10 @@ fn decode_rsa2048_priv_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -289,26 +306,29 @@ fn decode_rsa2048_priv_pem() { "ABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" "ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBE" "B143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67" + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" "8DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B" "02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9" - - ) - ); + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); } #[test] @@ -319,7 +339,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 +360,10 @@ fn decode_rsa4096_priv_pem() { ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E" "9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55F" @@ -362,8 +383,7 @@ fn decode_rsa4096_priv_pem() { "EF6BE3364969E1337C91B29A07B9A913CDE40CE2D5530C900E73751685E65431" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E8" "2596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD" @@ -373,10 +393,13 @@ fn decode_rsa4096_priv_pem() { "1BE60761F19F74672489EAF9F215409F39956E77A82183F1F72BB2FEDDF1B9FB" "FC4AD89EA445809DDBD5BD595277990C0BE9366FBB2ECF7B057CC1C3DC8FB77B" "F8456D07BBC95B3C1815F48E62B81468C3D4D9D96C0F48DAB04993BE8D91EDE5" - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + ), + 2048, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); + + let expected_prime = BoxedUint::from_be_slice( &hex!( "CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB8" "8E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE8" @@ -386,8 +409,11 @@ fn decode_rsa4096_priv_pem() { "4A15823F5107C89548EDDCB61DA5308C6CC834D4A0C16DFA6CA1D67B61A65677" "EB1719CD125D0EF0DB8802FB76CFC17577BCB2510AE294E1BF8A9173A2B85C16" "A6B508C98F2D770B7F3DE48D9E720C53E263680B57E7109410015745570652FD" - ) - ); + ), + 2048, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); } #[test] @@ -398,7 +424,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 +436,8 @@ fn decode_rsa2048_pub_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); } #[test] @@ -421,7 +448,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 +468,8 @@ fn decode_rsa4096_pub_pem() { "F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); } #[test] diff --git a/tests/pkcs8.rs b/tests/pkcs8.rs index 8f500728..d86ac1b1 100644 --- a/tests/pkcs8.rs +++ b/tests/pkcs8.rs @@ -1,5 +1,20 @@ //! PKCS#8 encoding tests +use crypto_bigint::BoxedUint; +use hex_literal::hex; +use rsa::{ + pkcs1v15, + pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, + pss, + traits::{PrivateKeyParts, PublicKeyParts}, + RsaPrivateKey, RsaPublicKey, +}; +use sha2::Sha256; +use subtle::ConstantTimeEq; + +#[cfg(feature = "pem")] +use rsa::pkcs8::LineEnding; + /// RSA-2048 PKCS#8 private key encoded as ASN.1 DER const RSA_2048_PRIV_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-priv.der"); @@ -20,26 +35,13 @@ const RSA_2048_PSS_PRIV_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-rfc9 /// RSA-2048 PSS PKCS#8 public key encoded as DER const RSA_2048_PSS_PUB_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-rfc9421-pub.der"); -use hex_literal::hex; -use rsa::{ - pkcs1v15, - pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, - pss, - traits::{PrivateKeyParts, PublicKeyParts}, - RsaPrivateKey, RsaPublicKey, -}; -use sha2::Sha256; - -#[cfg(feature = "pem")] -use rsa::pkcs8::LineEnding; - #[test] fn decode_rsa2048_priv_der() { let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap(); // Note: matches PKCS#1 test vectors assert_eq!( - &key.n().to_bytes_be(), + &key.n().to_be_bytes()[..], &hex!( "B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36" "E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C" @@ -51,9 +53,10 @@ fn decode_rsa2048_priv_der() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 32).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -65,24 +68,29 @@ fn decode_rsa2048_priv_der() { "ABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" "ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBE" "B143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67" - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); + + let expected_prime = BoxedUint::from_be_slice( &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" "8DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B" "02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9" - ) - ); + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); let _ = pkcs1v15::SigningKey::::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap(); } @@ -93,7 +101,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 +113,8 @@ fn decode_rsa2048_pub_der() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); let _ = pkcs1v15::VerifyingKey::::from_public_key_der(RSA_2048_PUB_DER).unwrap(); } @@ -115,7 +124,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 +137,10 @@ fn decode_rsa2048_pss_priv_der() { ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "9407C8A9FA426289954A17C02A7C1FDA50FD234C0A8E41EC0AD64289FE24025C" "10AAA5BA37EB482F76DD391F9559FD10D590480EDA4EF7552B1BBA5A9ECCAB3C" @@ -142,25 +152,29 @@ fn decode_rsa2048_pss_priv_der() { "3783DA6236A07A0F332003D30748EC1C12556D7CA7587E8E07DCE1D95EC4A611" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "E55FBA212239C846821579BE7E4D44336C700167A478F542032BEBF506D39453" "82670B7D5B08D48E1B4A46EB22E54ABE21867FB6AD96444E00B386FF14710CB6" "9D80111E3721CBE65CFA8A141A1492D5434BB7538481EBB27462D54EDD1EA55D" "C2230431EE63C4A3609EC28BA67ABEE0DCA1A12E8E796BB5485A331BD27DC509" + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "C3EC0875ED7B5B96340A9869DD9674B8CF0E52AD4092B57620A6AEA981DA0F10" "13DF610CE1C8B630C111DA7214128E20FF8DA55B4CD8A2E145A8E370BF4F87C8" "EB203E9752A8A442E562E09F455769B8DA35CCBA2A134F5DE274020B6A7620F0" "3DE276FCBFDE2B0356438DD17DD40152AB80C1277B4849A643CB158AA07ADBC3" - ) - ); + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); let _ = pss::SigningKey::::from_pkcs8_der(RSA_2048_PSS_PRIV_DER).unwrap(); } @@ -170,7 +184,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 +196,8 @@ fn decode_rsa2048_pss_pub_der() { "D502F266FB17433A9F4B08D08DE3C576A670CE90557AF94F67579A3273A5C8DB" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); let _ = pss::VerifyingKey::::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap(); } @@ -217,7 +232,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 +244,10 @@ fn decode_rsa2048_priv_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); assert_eq!( - &key.d().to_bytes_be(), + &key.d().to_be_bytes()[..], &hex!( "7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BD" "CFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B7" @@ -243,24 +259,29 @@ fn decode_rsa2048_priv_pem() { "ABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1" ) ); - assert_eq!( - &key.primes()[0].to_bytes_be(), + let expected_prime = BoxedUint::from_be_slice( &hex!( "DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225" "EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422" "ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBE" "B143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67" - ) - ); - assert_eq!( - &key.primes()[1].to_bytes_be(), + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[0].ct_eq(&expected_prime))); + + let expected_prime = BoxedUint::from_be_slice( &hex!( "D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FD" "E65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E422" "8DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B" "02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9" - ) - ); + ), + 1024, + ) + .unwrap(); + assert!(bool::from(key.primes()[1].ct_eq(&expected_prime))); let _ = pkcs1v15::SigningKey::::from_pkcs8_pem(RSA_2048_PRIV_PEM).unwrap(); } @@ -272,7 +293,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 +305,8 @@ fn decode_rsa2048_pub_pem() { "90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F" ) ); - assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + let expected_e = BoxedUint::from_be_slice(&hex!("010001"), 128).unwrap(); + assert!(bool::from(key.e().ct_eq(&expected_e))); 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 = []