chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

1
vendor/rsa/.cargo-checksum.json vendored Normal file

File diff suppressed because one or more lines are too long

6
vendor/rsa/.cargo_vcs_info.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"git": {
"sha1": "da2af9a0ff814762957c428460e4098720f394a6"
},
"path_in_vcs": ""
}

12
vendor/rsa/.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: cargo
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: monthly
open-pull-requests-limit: 10

80
vendor/rsa/.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,80 @@
name: CI
on:
pull_request:
push:
branches:
- master
env:
RUSTFLAGS: "-Dwarnings"
RUSTDOCFLAGS: "-Dwarnings"
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.65.0 # MSRV
- stable
target:
- thumbv7em-none-eabi
- wasm32-unknown-unknown
steps:
- uses: actions/checkout@v4
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
targets: ${{ matrix.target }}
- run: cargo build --no-default-features --target ${{ matrix.target }}
test:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.65.0 # MSRV
- stable
steps:
- uses: actions/checkout@v4
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
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 test --release --features getrandom
- run: cargo test --release --features serde
doc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
- run: cargo doc --all-features
minimal-versions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@nightly
- run: cargo update -Z minimal-versions
- uses: dtolnay/rust-toolchain@stable
- run: cargo test --release --features getrandom,serde,pkcs5
nightly:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2023-10-01
- run: cargo test --release --features nightly
- run: cargo build --benches

249
vendor/rsa/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,249 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.9.10 (2026-01-06)
### Fixed
- do not panic on a prime being 1 when loading a secret key ([#624])
[#624]: https://github.com/RustCrypto/RSA/pull/624
## 0.9.9 (2025-11-13)
### Fixed
- Support for cryptographic operations with larger keys ([#594])
[#594]: https://github.com/RustCrypto/RSA/pull/594
## 0.9.8 (2025-03-12)
### Added
- Doc comments to specify the `rand` version ([#473])
[#473]: https://github.com/RustCrypto/RSA/pull/473
## 0.9.7 (2024-11-26)
### Fixed
- always validate keys in from_components
- do not crash when handling tiny keys in PKCS1v15
## 0.9.6 (2023-12-01)
### Added
- expose a `pss::get_default_pss_signature_algo_id` helper ([#393])
- expose `pkcs1v15::RsaSignatureAssociatedOid` ([#392])
[#392]: https://github.com/RustCrypto/RSA/pull/392
[#393]: https://github.com/RustCrypto/RSA/pull/393
## 0.9.5 (2023-11-27)
### Added
- Adds `RsaPrivateKey::from_primes` and `RsaPrivateKey::from_p_q` methods ([#386])
[#386]: https://github.com/RustCrypto/RSA/pull/386
## 0.9.4 (2023-11-20)
### Added
- Deterministic implementation of prime factors recovery ([#380])
[#380]: https://github.com/RustCrypto/RSA/pull/380
## 0.9.3 (2023-10-26)
### Added
- PKCS#8/SPKI decoding trait impls for `pkcs1v15` keys ([#346])
- `hazmat` feature as a replacement for `expose-internals` ([#352])
### Changed
- Bump `serde` dependency to 1.0.184 ([#360])
### Removed
- Unused dependencies ([#357])
[#346]: https://github.com/RustCrypto/RSA/pull/346
[#352]: https://github.com/RustCrypto/RSA/pull/352
[#357]: https://github.com/RustCrypto/RSA/pull/357
[#360]: https://github.com/RustCrypto/RSA/pull/360
## 0.9.2 (2023-05-08)
### Fixed
- pkcs1v15: have `fmt` impls call `SignatureEncoding::to_bytes` ([#330])
[#330]: https://github.com/RustCrypto/RSA/pull/330
## 0.9.1 (2023-05-03)
### Fixed
- Left pad signatures when encoding ([#325])
[#325]: https://github.com/RustCrypto/RSA/pull/325
## 0.9.0 (2023-04-27)
### Added
- Function to get salt length from RSA PSS keys ([#277])
- `AssociatedAlgorithmIdentifier` implementation ([#278])
- Random key generation for `pss::BlindedSigningKey` ([#295])
- Impl `Signer` for `pss::SigningKey` ([#297])
- Impl `core::hash::Hash` for `RsaPrivateKey` ([#308])
- Impl `ZeroizeOnDrop` for `RsaPrivateKey`, `SigningKey`, `DecryptingKey` ([#311])
- `u64_digit` feature; on-by-default ([#313])
- `AsRef<RsaPublicKey>` impl on `RsaPrivateKey` ([#317])
### Changed
- Use namespaced features for `serde` ([#268])
- Bump `pkcs1` to v0.7, `pkcs8` to v0.10; MSRV 1.65 ([#270])
- Rename PKCS#1v1.5 `*_with_prefix` methods ([#290])
- `SigningKey::new` => `SigningKey::new_unprefixed`
- `SigningKey::new_with_prefix` => `SigningKey::new`
- `VerifyingKey::new` => `VerifyingKey::new_unprefixed`
- `VerifyingKey::new_with_prefix` => `VerifyingKey::new`
- Rename `Pkcs1v15Sign::new_raw` to `Pkcs1v15Sign::new_unprefixed` ([#293])
- Use digest output size as default PSS salt length ([#294])
- Specify `salt_len` when verifying PSS signatures ([#294])
- Ensure signatures have the expected length and don't overflow the modulus ([#306])
- Improved public key checks ([#307])
- Rename `CRTValue` => `CrtValue` ([#314])
- Traits under `padding` module now located under `traits` module ([#315])
- `PublicKeyParts`/`PrivateKeyParts` now located under `traits` module ([#315])
### Removed
- "Unsalted" PSS support ([#294])
- `EncryptionPrimitive`/`DecriptionPrimitive` traits ([#300])
- `PublicKey`/`PrivateKey` traits ([#300])
- `Zeroize` impl on `RsaPrivateKey`; automatically zeroized on drop ([#311])
- `Deref<Target=RsaPublicKey>` impl on `RsaPrivateKey`; use `AsRef` instead ([#317])
- `expose-internals` feature and public access to all functions it gated ([#304])
[#268]: https://github.com/RustCrypto/RSA/pull/268
[#270]: https://github.com/RustCrypto/RSA/pull/270
[#277]: https://github.com/RustCrypto/RSA/pull/277
[#278]: https://github.com/RustCrypto/RSA/pull/278
[#290]: https://github.com/RustCrypto/RSA/pull/290
[#293]: https://github.com/RustCrypto/RSA/pull/293
[#294]: https://github.com/RustCrypto/RSA/pull/294
[#295]: https://github.com/RustCrypto/RSA/pull/295
[#297]: https://github.com/RustCrypto/RSA/pull/297
[#300]: https://github.com/RustCrypto/RSA/pull/300
[#306]: https://github.com/RustCrypto/RSA/pull/306
[#307]: https://github.com/RustCrypto/RSA/pull/307
[#308]: https://github.com/RustCrypto/RSA/pull/308
[#311]: https://github.com/RustCrypto/RSA/pull/311
[#313]: https://github.com/RustCrypto/RSA/pull/313
[#314]: https://github.com/RustCrypto/RSA/pull/314
[#315]: https://github.com/RustCrypto/RSA/pull/315
[#317]: https://github.com/RustCrypto/RSA/pull/317
## 0.8.2 (2023-03-01)
### Added
- Encryption-related traits ([#259])
### Fixed
- Possible panic in `internals::left_pad` ([#262])
- Correct PSS sign/verify when key length is multiple of 8+1 bits ([#263])
[#259]: https://github.com/RustCrypto/RSA/pull/259
[#262]: https://github.com/RustCrypto/RSA/pull/262
[#263]: https://github.com/RustCrypto/RSA/pull/263
## 0.8.1 (2023-01-20)
### Added
- `sha2` feature with `oid` subfeature enabled ([#255])
[#255]: https://github.com/RustCrypto/RSA/pull/255
## 0.8.0 (2023-01-17)
### Changed
- Bump `signature` crate dependency to v2 ([#217], [#249])
- Switch to `CryptoRngCore` marker trait ([#237])
- Make `padding` module private ([#243])
- Refactor `PaddingScheme` into a trait ([#244])
### Fixed
- Benchmark build ([#225])
[#217]: https://github.com/RustCrypto/RSA/pull/217
[#225]: https://github.com/RustCrypto/RSA/pull/225
[#237]: https://github.com/RustCrypto/RSA/pull/237
[#243]: https://github.com/RustCrypto/RSA/pull/243
[#244]: https://github.com/RustCrypto/RSA/pull/244
[#249]: https://github.com/RustCrypto/RSA/pull/249
## 0.7.2 (2022-11-14)
### Added
- Public accessor methods for `PrecomputedValues` ([#221])
- Re-export `signature` crate ([#223])
[#221]: https://github.com/RustCrypto/RSA/pull/221
[#223]: https://github.com/RustCrypto/RSA/pull/223
## 0.7.1 (2022-10-31)
### Added
- Documentation improvements ([#216])
### Changed
- Ensure `PaddingScheme` is `Send` and `Sync` ([#215])
[#215]: https://github.com/RustCrypto/RSA/pull/215
[#216]: https://github.com/RustCrypto/RSA/pull/216
## 0.7.0 (2022-10-10) [YANKED]
NOTE: when computing signatures with this release, make sure to enable the
`oid` crate feature of the digest crate you are using when computing the
signature (e.g. `sha2`, `sha3`). If the `oid` feature doesn't exist, make sure
you're using the latest versions.
### Added
- `pkcs1v15` and `pss` modules with `SigningKey`/`VerifyingKey` types
([#174], [#195], [#202], [#207], [#208])
- 4096-bit default max `RsaPublicKey` size ([#176])
- `RsaPublicKey::new_with_max_size` ([#176])
- `RsaPublicKey::new_unchecked` ([#206])
### Changed
- MSRV 1.57 ([#162])
- Bump `pkcs1` to 0.4 ([#162])
- Bump `pkcs8` to 0.9 ([#162])
- `RsaPrivateKey::from_components` is now fallible ([#167])
- pkcs1v15: use `AssociatedOid` for getting the RSA prefix ([#183])
### Removed
- `rng` member from PSS padding scheme ([#173])
- `Hash` removed in favor of using OIDs defined in digest crates ([#183])
[#162]: https://github.com/RustCrypto/RSA/pull/162
[#167]: https://github.com/RustCrypto/RSA/pull/167
[#173]: https://github.com/RustCrypto/RSA/pull/173
[#174]: https://github.com/RustCrypto/RSA/pull/174
[#176]: https://github.com/RustCrypto/RSA/pull/176
[#183]: https://github.com/RustCrypto/RSA/pull/183
[#195]: https://github.com/RustCrypto/RSA/pull/195
[#202]: https://github.com/RustCrypto/RSA/pull/202
[#206]: https://github.com/RustCrypto/RSA/pull/206
[#207]: https://github.com/RustCrypto/RSA/pull/207
[#208]: https://github.com/RustCrypto/RSA/pull/208
## 0.6.1 (2022-04-11)
## 0.6.0 (2022-04-08)
## 0.5.0 (2021-07-27)
## 0.4.1 (2021-07-26)
## 0.4.0 (2021-03-28)
## 0.3.0 (2020-06-11)
## 0.2.0 (2019-12-11)
## 0.1.4 (2019-10-13)
## 0.1.3 (2019-03-26)
## 0.1.2 (2019-02-25)
## 0.1.1 (2019-02-20)
## 0.1.0 (2018-12-05)

765
vendor/rsa/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,765 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aes"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bit-set"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
"bit-vec",
]
[[package]]
name = "bit-vec"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "block-padding"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93"
dependencies = [
"generic-array",
]
[[package]]
name = "cbc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [
"cipher",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "const-oid"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
[[package]]
name = "cpufeatures"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "der"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
dependencies = [
"const-oid",
"pem-rfc7468",
"zeroize",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"const-oid",
"crypto-common",
"subtle",
]
[[package]]
name = "errno"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f258a7194e7f7c2a7837a8913aeab7fd8c383457034fa20ce4dd3dcb813e8eb8"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hex-literal"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46"
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"block-padding",
"generic-array",
]
[[package]]
name = "keccak"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940"
dependencies = [
"cpufeatures",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
dependencies = [
"spin",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libm"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "linux-raw-sys"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "969488b55f8ac402214f3f5fd243ebb7206cf82de60d3172994707a4bcc2b829"
[[package]]
name = "num-bigint-dig"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
dependencies = [
"lazy_static",
"libm",
"num-integer",
"num-iter",
"num-traits",
"rand",
"serde",
"smallvec",
"zeroize",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
"libm",
]
[[package]]
name = "pbkdf2"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
dependencies = [
"digest",
"hmac",
]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
dependencies = [
"base64ct",
]
[[package]]
name = "pkcs1"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
dependencies = [
"der",
"pkcs8",
"spki",
]
[[package]]
name = "pkcs5"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6"
dependencies = [
"aes",
"cbc",
"der",
"pbkdf2",
"scrypt",
"sha2",
"spki",
]
[[package]]
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"pkcs5",
"rand_core",
"spki",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "proptest"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf"
dependencies = [
"bit-set",
"bit-vec",
"bitflags 2.4.1",
"lazy_static",
"num-traits",
"rand",
"rand_chacha",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
"tempfile",
"unarray",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_xorshift"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f"
dependencies = [
"rand_core",
]
[[package]]
name = "redox_syscall"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags 1.3.2",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rsa"
version = "0.9.10"
dependencies = [
"base64ct",
"const-oid",
"digest",
"hex-literal",
"num-bigint-dig",
"num-integer",
"num-traits",
"pkcs1",
"pkcs8",
"proptest",
"rand",
"rand_chacha",
"rand_core",
"rand_xorshift",
"serde",
"serde_test",
"sha1",
"sha2",
"sha3",
"signature",
"spki",
"subtle",
"zeroize",
]
[[package]]
name = "rustix"
version = "0.38.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc99bc2d4f1fed22595588a013687477aedf3cdcfb26558c559edb67b4d9b22e"
dependencies = [
"bitflags 2.4.1",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rusty-fork"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
dependencies = [
"fnv",
"quick-error",
"tempfile",
"wait-timeout",
]
[[package]]
name = "salsa20"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213"
dependencies = [
"cipher",
]
[[package]]
name = "scrypt"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f"
dependencies = [
"pbkdf2",
"salsa20",
"sha2",
]
[[package]]
name = "serde"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_test"
version = "1.0.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha3"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
dependencies = [
"digest",
"keccak",
]
[[package]]
name = "signature"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest",
"rand_core",
]
[[package]]
name = "smallvec"
version = "1.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der",
]
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tempfile"
version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
dependencies = [
"cfg-if",
"fastrand",
"redox_syscall",
"rustix",
"windows-sys",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unarray"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wait-timeout"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
dependencies = [
"libc",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "zeroize"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"

234
vendor/rsa/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,234 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.65"
name = "rsa"
version = "0.9.10"
authors = [
"RustCrypto Developers",
"dignifiedquire <dignifiedquire@gmail.com>",
]
build = false
autolib = false
autobins = false
autoexamples = false
autotests = false
autobenches = false
description = "Pure Rust RSA implementation"
documentation = "https://docs.rs/rsa"
readme = "README.md"
keywords = [
"rsa",
"encryption",
"security",
"crypto",
]
categories = ["cryptography"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/RustCrypto/RSA"
[package.metadata.docs.rs]
features = [
"std",
"pem",
"serde",
"hazmat",
"sha2",
]
rustdoc-args = [
"--cfg",
"docsrs",
]
[features]
default = [
"std",
"pem",
"u64_digit",
]
getrandom = ["rand_core/getrandom"]
hazmat = []
nightly = ["num-bigint/nightly"]
pem = [
"pkcs1/pem",
"pkcs8/pem",
]
pkcs5 = ["pkcs8/encryption"]
serde = [
"dep:serde",
"num-bigint/serde",
]
std = [
"digest/std",
"pkcs1/std",
"pkcs8/std",
"rand_core/std",
"signature/std",
]
u64_digit = ["num-bigint/u64_digit"]
[lib]
name = "rsa"
path = "src/lib.rs"
[[test]]
name = "pkcs1"
path = "tests/pkcs1.rs"
[[test]]
name = "pkcs1v15"
path = "tests/pkcs1v15.rs"
[[test]]
name = "pkcs8"
path = "tests/pkcs8.rs"
[[test]]
name = "proptests"
path = "tests/proptests.rs"
[[bench]]
name = "key"
path = "benches/key.rs"
[dependencies.const-oid]
version = "0.9"
default-features = false
[dependencies.digest]
version = "0.10.5"
features = [
"alloc",
"oid",
]
default-features = false
[dependencies.num-bigint]
version = "0.8.6"
features = [
"i128",
"prime",
"zeroize",
]
default-features = false
package = "num-bigint-dig"
[dependencies.num-integer]
version = "0.1.39"
default-features = false
[dependencies.num-traits]
version = "0.2.9"
features = ["libm"]
default-features = false
[dependencies.pkcs1]
version = "0.7.5"
features = [
"alloc",
"pkcs8",
]
default-features = false
[dependencies.pkcs8]
version = "0.10.2"
features = ["alloc"]
default-features = false
[dependencies.rand_core]
version = "0.6.4"
default-features = false
[dependencies.serde]
version = "1.0.184"
features = ["derive"]
optional = true
default-features = false
[dependencies.sha1]
version = "0.10.5"
features = ["oid"]
optional = true
default-features = false
[dependencies.sha2]
version = "0.10.6"
features = ["oid"]
optional = true
default-features = false
[dependencies.signature]
version = ">2.0, <2.3"
features = [
"alloc",
"digest",
"rand_core",
]
default-features = false
[dependencies.spki]
version = "0.7.3"
features = ["alloc"]
default-features = false
[dependencies.subtle]
version = "2.1.1"
default-features = false
[dependencies.zeroize]
version = "1.5"
features = ["alloc"]
[dev-dependencies.base64ct]
version = "1"
features = ["alloc"]
[dev-dependencies.hex-literal]
version = "0.4.1"
[dev-dependencies.proptest]
version = "1"
[dev-dependencies.rand]
version = "0.8"
[dev-dependencies.rand_chacha]
version = "0.3"
[dev-dependencies.rand_core]
version = "0.6"
default-features = false
[dev-dependencies.rand_xorshift]
version = "0.3"
[dev-dependencies.serde_test]
version = "1.0.89"
[dev-dependencies.sha1]
version = "0.10.5"
features = ["oid"]
default-features = false
[dev-dependencies.sha2]
version = "0.10.6"
features = ["oid"]
default-features = false
[dev-dependencies.sha3]
version = "0.10.7"
features = ["oid"]
default-features = false
[profile.dev]
opt-level = 2

201
vendor/rsa/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

23
vendor/rsa/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,23 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

126
vendor/rsa/README.md vendored Normal file
View File

@@ -0,0 +1,126 @@
# [RustCrypto]: RSA
[![crates.io][crate-image]][crate-link]
[![Documentation][doc-image]][doc-link]
[![Build Status][build-image]][build-link]
[![dependency status][deps-image]][deps-link]
![MSRV][msrv-image]
[![Project Chat][chat-image]][chat-link]
A portable RSA implementation in pure Rust.
## Example
```rust
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
let mut rng = rand::thread_rng(); // rand@0.8
let bits = 2048;
let priv_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
let pub_key = RsaPublicKey::from(&priv_key);
// Encrypt
let data = b"hello world";
let enc_data = pub_key.encrypt(&mut rng, Pkcs1v15Encrypt, &data[..]).expect("failed to encrypt");
assert_ne!(&data[..], &enc_data[..]);
// Decrypt
let dec_data = priv_key.decrypt(Pkcs1v15Encrypt, &enc_data).expect("failed to decrypt");
assert_eq!(&data[..], &dec_data[..]);
```
> **Note:** If you encounter unusually slow key generation time while using `RsaPrivateKey::new` you can try to compile in release mode or add the following to your `Cargo.toml`. Key generation is much faster when building with higher optimization levels, but this will increase the compile time a bit.
> ```toml
> [profile.debug]
> opt-level = 3
> ```
> If you don't want to turn on optimizations for all dependencies,
> you can only optimize the `num-bigint-dig` dependency. This should
> give most of the speedups.
> ```toml
> [profile.dev.package.num-bigint-dig]
> opt-level = 3
> ```
## Status
Currently at Phase 1 (v) 🚧
There will be three phases before `1.0` 🚢 can be released.
1. 🚧 Make it work
- [x] Prime generation ✅
- [x] Key generation ✅
- [x] PKCS1v1.5: Encryption & Decryption ✅
- [x] PKCS1v1.5: Sign & Verify ✅
- [ ] PKCS1v1.5 (session key): Encryption & Decryption
- [x] OAEP: Encryption & Decryption
- [x] PSS: Sign & Verify
- [x] Key import & export
2. 🚀 Make it fast
- [x] Benchmarks ✅
- [ ] compare to other implementations 🚧
- [ ] optimize 🚧
3. 🔐 Make it secure
- [ ] Fuzz testing
- [ ] Security Audits
## ⚠Security Warning
This crate has received one [security audit by Include Security][audit], with
only one minor finding which has since been addressed.
See the [open security issues] on our issue tracker for other known problems.
~~Notably the implementation of [modular exponentiation is not constant time],
but timing variability is masked using [random blinding], a commonly used
technique.~~ This crate is vulnerable to the [Marvin Attack] which could enable
private key recovery by a network attacker (see [RUSTSEC-2023-0071]).
You can follow our work on mitigating this issue in [#390].
## Minimum Supported Rust Version (MSRV)
All crates in this repository support Rust 1.65 or higher.
In the future MSRV can be changed, but it will be done with a minor version bump.
## License
Licensed under either of
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
* [MIT license](http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
dual licensed as above, without any additional terms or conditions.
[//]: # (badges)
[crate-image]: https://buildstats.info/crate/rsa
[crate-link]: https://crates.io/crates/rsa
[doc-image]: https://docs.rs/rsa/badge.svg
[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.65+-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
[deps-link]: https://deps.rs/repo/github/RustCrypto/RSA
[//]: # (links)
[RustCrypto]: https://github.com/RustCrypto/
[audit]: https://www.opentech.fund/results/security-safety-audits/deltachat/
[open security issues]: https://github.com/RustCrypto/RSA/issues?q=is%3Aissue+is%3Aopen+label%3Asecurity
[modular exponentiation is not constant time]: https://github.com/RustCrypto/RSA/issues/19
[random blinding]: https://en.wikipedia.org/wiki/Blinding_(cryptography)
[Marvin Attack]: https://people.redhat.com/~hkario/marvin/
[RUSTSEC-2023-0071]: https://rustsec.org/advisories/RUSTSEC-2023-0071.html
[#390]: https://github.com/RustCrypto/RSA/issues/390

17
vendor/rsa/SECURITY.md vendored Normal file
View File

@@ -0,0 +1,17 @@
# Security Policy
## Supported Versions
Security updates are applied only to the most recent release.
## Reporting a Vulnerability
If you have discovered a security vulnerability in this project, please report
it privately. **Do not disclose it as a public issue.** This gives us time to
work with you to fix the issue before public exposure, reducing the chance that
the exploit will be used before a patch is released.
Please disclose it at [security advisory](https://github.com/RustCrypto/RSA/security/advisories/new).
This project is maintained by a team of volunteers on a reasonable-effort basis.
As such, please give us at least 90 days to work on a fix before public exposure.

51
vendor/rsa/benches/key.rs vendored Normal file
View File

@@ -0,0 +1,51 @@
#![feature(test)]
extern crate test;
use base64ct::{Base64, Encoding};
use num_bigint::BigUint;
use num_traits::{FromPrimitive, Num};
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use rsa::{Pkcs1v15Encrypt, Pkcs1v15Sign, RsaPrivateKey};
use sha2::{Digest, Sha256};
use test::Bencher;
const DECRYPT_VAL: &'static str =
"XW4qfrpQDarEMBfPyIYE9UvuOFkbBi0tiGYbIOJPLMNe/LWuPD0BQ7ceqlOlPPcKLinYz0DlnqW3It/V7ae59zw9afA3YIWdq0Ut2BnYL+aJixnqaP+PjsQNcHg6axCF11iNQ4jpXrZDiQcI+q9EEzZDTMsiMxtjfgBQUd8LHT87YoQXDWaFPCVpliACMc8aUk442kH1tc4jEuXwjEjFErvAM/J7VizCdU/dnKrlq2mBDzvZ6hxY9TYHFB/zY6DZPJAgEMUxYWCR9xPJ7X256DV1Kt0Ht33DWoFcgh/pPLM1q9pK0HVxCdclXfZOeCqlrLgZ5Gxv5DM4BtV7Z4m85w==";
fn get_key() -> RsaPrivateKey {
RsaPrivateKey::from_components(
BigUint::from_str_radix("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557", 10).unwrap(),
BigUint::from_u32(3).unwrap(),
BigUint::from_str_radix("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731", 10).unwrap(),
vec![
BigUint::from_str_radix("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433",10).unwrap(),
BigUint::from_str_radix("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029", 10).unwrap()
],
).unwrap()
}
#[bench]
fn bench_rsa_2048_pkcsv1_decrypt(b: &mut Bencher) {
let priv_key = get_key();
let x = Base64::decode_vec(DECRYPT_VAL).unwrap();
b.iter(|| {
let res = priv_key.decrypt(Pkcs1v15Encrypt, &x).unwrap();
test::black_box(res);
});
}
#[bench]
fn bench_rsa_2048_pkcsv1_sign_blinded(b: &mut Bencher) {
let priv_key = get_key();
let digest = Sha256::digest(b"testing").to_vec();
let mut rng = ChaCha8Rng::from_seed([42; 32]);
b.iter(|| {
let res = priv_key
.sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha256>(), &digest)
.unwrap();
test::black_box(res);
});
}

2
vendor/rsa/release.toml vendored Normal file
View File

@@ -0,0 +1,2 @@
pre-release-commit-message = "chore({{crate_name}}): release {{version}}"
dev-version = false

10
vendor/rsa/src/algorithms.rs vendored Normal file
View File

@@ -0,0 +1,10 @@
//! Useful algorithms related to RSA.
mod mgf;
pub(crate) mod generate;
pub(crate) mod oaep;
pub(crate) mod pad;
pub(crate) mod pkcs1v15;
pub(crate) mod pss;
pub(crate) mod rsa;

166
vendor/rsa/src/algorithms/generate.rs vendored Normal file
View File

@@ -0,0 +1,166 @@
//! 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 rand_core::CryptoRngCore;
use crate::{
algorithms::rsa::{compute_modulus, compute_private_exponent_euler_totient},
errors::{Error, Result},
};
pub struct RsaPrivateKeyComponents {
pub n: BigUint,
pub e: BigUint,
pub d: BigUint,
pub primes: Vec<BigUint>,
}
/// Generates a multi-prime RSA keypair of the given bit size, public exponent,
/// and the given random source, as suggested in [1]. Although the public
/// keys are compatible (actually, indistinguishable) from the 2-prime case,
/// the private keys are not. Thus it may not be possible to export multi-prime
/// private keys in certain formats or to subsequently import them into other
/// code.
///
/// Table 1 in [2] suggests maximum numbers of primes for a given size.
///
/// [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<R: CryptoRngCore + ?Sized>(
rng: &mut R,
nprimes: usize,
bit_size: usize,
exp: &BigUint,
) -> Result<RsaPrivateKeyComponents> {
if nprimes < 2 {
return Err(Error::NprimesTooSmall);
}
if bit_size < 64 {
let prime_limit = (1u64 << (bit_size / nprimes) as u64) as f64;
// pi aproximates the number of primes less than prime_limit
let mut pi = prime_limit / (prime_limit.ln() - 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
// reasonable amount of time.
pi /= 2f64;
if pi < nprimes as f64 {
return Err(Error::TooFewPrimes);
}
}
let mut primes = vec![BigUint::zero(); nprimes];
let n_final: BigUint;
let d_final: BigUint;
'next: loop {
let mut todo = bit_size;
// `gen_prime` should set the top two bits in each prime.
// Thus each prime has the form
// p_i = 2^bitlen(p_i) × 0.11... (in base 2).
// And the product is:
// P = 2^todo × α
// where α is the product of nprimes numbers of the form 0.11...
//
// If α < 1/2 (which can happen for nprimes > 2), we need to
// shift todo to compensate for lost bits: the mean value of 0.11...
// is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
// will give good results.
if nprimes >= 7 {
todo += (nprimes - 2) / 5;
}
for (i, prime) in primes.iter_mut().enumerate() {
*prime = rng.gen_prime(todo / (nprimes - i));
todo -= prime.bits();
}
// Makes sure that primes is pairwise unequal.
for (i, prime1) in primes.iter().enumerate() {
for prime2 in primes.iter().take(i) {
if prime1 == prime2 {
continue 'next;
}
}
}
let n = compute_modulus(&primes);
if n.bits() != 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) {
n_final = n;
d_final = d;
break;
}
}
Ok(RsaPrivateKeyComponents {
n: n_final,
e: exp.clone(),
d: d_final,
primes,
})
}
#[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;
#[test]
fn test_impossible_keys() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
for i in 0..32 {
let _ = generate_multi_prime_key_with_exp(&mut rng, 2, i, &exp);
let _ = generate_multi_prime_key_with_exp(&mut rng, 3, i, &exp);
let _ = generate_multi_prime_key_with_exp(&mut rng, 4, i, &exp);
let _ = generate_multi_prime_key_with_exp(&mut rng, 5, i, &exp);
}
}
macro_rules! key_generation {
($name:ident, $multi:expr, $size:expr) => {
#[test]
fn $name() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let exp = BigUint::from_u64(EXP).expect("invalid static exponent");
for _ in 0..10 {
let components =
generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap();
assert_eq!(components.n.bits(), $size);
assert_eq!(components.primes.len(), $multi);
}
}
};
}
key_generation!(key_generation_128, 2, 128);
key_generation!(key_generation_1024, 2, 1024);
key_generation!(key_generation_multi_3_256, 3, 256);
key_generation!(key_generation_multi_4_64, 4, 64);
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);
}

75
vendor/rsa/src/algorithms/mgf.rs vendored Normal file
View File

@@ -0,0 +1,75 @@
//! Mask generation function common to both PSS and OAEP padding
use digest::{Digest, DynDigest, FixedOutputReset};
/// Mask generation function.
///
/// Panics if out is larger than 2**32. This is in accordance with RFC 8017 - PKCS #1 B.2.1
pub(crate) fn mgf1_xor(out: &mut [u8], digest: &mut dyn DynDigest, seed: &[u8]) {
let mut counter = [0u8; 4];
let mut i = 0;
const MAX_LEN: u64 = core::u32::MAX as u64 + 1;
assert!(out.len() as u64 <= MAX_LEN);
while i < out.len() {
let mut digest_input = vec![0u8; seed.len() + 4];
digest_input[0..seed.len()].copy_from_slice(seed);
digest_input[seed.len()..].copy_from_slice(&counter);
digest.update(digest_input.as_slice());
let digest_output = &*digest.finalize_reset();
let mut j = 0;
loop {
if j >= digest_output.len() || i >= out.len() {
break;
}
out[i] ^= digest_output[j];
j += 1;
i += 1;
}
inc_counter(&mut counter);
}
}
/// Mask generation function.
///
/// Panics if out is larger than 2**32. This is in accordance with RFC 8017 - PKCS #1 B.2.1
pub(crate) fn mgf1_xor_digest<D>(out: &mut [u8], digest: &mut D, seed: &[u8])
where
D: Digest + FixedOutputReset,
{
let mut counter = [0u8; 4];
let mut i = 0;
const MAX_LEN: u64 = core::u32::MAX as u64 + 1;
assert!(out.len() as u64 <= MAX_LEN);
while i < out.len() {
Digest::update(digest, seed);
Digest::update(digest, counter);
let digest_output = digest.finalize_reset();
let mut j = 0;
loop {
if j >= digest_output.len() || i >= out.len() {
break;
}
out[i] ^= digest_output[j];
j += 1;
i += 1;
}
inc_counter(&mut counter);
}
}
fn inc_counter(counter: &mut [u8; 4]) {
for i in (0..4).rev() {
counter[i] = counter[i].wrapping_add(1);
if counter[i] != 0 {
// No overflow
return;
}
}
}

246
vendor/rsa/src/algorithms/oaep.rs vendored Normal file
View File

@@ -0,0 +1,246 @@
//! Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
//!
use alloc::string::String;
use alloc::vec::Vec;
use digest::{Digest, DynDigest, FixedOutputReset};
use rand_core::CryptoRngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::Zeroizing;
use super::mgf::{mgf1_xor, mgf1_xor_digest};
use crate::errors::{Error, Result};
// 2**61 -1 (pow is not const yet)
// TODO: This is the maximum for SHA-1, unclear from the RFC what the values are for other hashing functions.
const MAX_LABEL_LEN: u64 = 2_305_843_009_213_693_951;
#[inline]
fn encrypt_internal<R: CryptoRngCore + ?Sized, MGF: FnMut(&mut [u8], &mut [u8])>(
rng: &mut R,
msg: &[u8],
p_hash: &[u8],
h_size: usize,
k: usize,
mut mgf: MGF,
) -> Result<Zeroizing<Vec<u8>>> {
if msg.len() + 2 * h_size + 2 > k {
return Err(Error::MessageTooLong);
}
let mut em = Zeroizing::new(vec![0u8; k]);
let (_, payload) = em.split_at_mut(1);
let (seed, db) = payload.split_at_mut(h_size);
rng.fill_bytes(seed);
// Data block DB = pHash || PS || 01 || M
let db_len = k - h_size - 1;
db[0..h_size].copy_from_slice(p_hash);
db[db_len - msg.len() - 1] = 1;
db[db_len - msg.len()..].copy_from_slice(msg);
mgf(seed, db);
Ok(em)
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
msg: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
k: usize,
) -> Result<Zeroizing<Vec<u8>>> {
let h_size = digest.output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::LabelTooLong);
}
digest.update(label.as_bytes());
let p_hash = digest.finalize_reset();
encrypt_internal(rng, msg, &p_hash, h_size, k, |seed, db| {
mgf1_xor(db, mgf_digest, seed);
mgf1_xor(seed, mgf_digest, db);
})
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_encrypt_digest<
R: CryptoRngCore + ?Sized,
D: Digest,
MGD: Digest + FixedOutputReset,
>(
rng: &mut R,
msg: &[u8],
label: Option<String>,
k: usize,
) -> Result<Zeroizing<Vec<u8>>> {
let h_size = <D as Digest>::output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::LabelTooLong);
}
let p_hash = D::digest(label.as_bytes());
encrypt_internal(rng, msg, &p_hash, h_size, k, |seed, db| {
let mut mgf_digest = MGD::new();
mgf1_xor_digest(db, &mut mgf_digest, seed);
mgf1_xor_digest(seed, &mut mgf_digest, db);
})
}
///Decrypts OAEP padding.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_decrypt(
em: &mut [u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
k: usize,
) -> Result<Vec<u8>> {
let h_size = digest.output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::Decryption);
}
digest.update(label.as_bytes());
let expected_p_hash = digest.finalize_reset();
let res = decrypt_inner(em, h_size, &expected_p_hash, k, |seed, db| {
mgf1_xor(seed, mgf_digest, db);
mgf1_xor(db, mgf_digest, seed);
})?;
if res.is_none().into() {
return Err(Error::Decryption);
}
let (out, index) = res.unwrap();
Ok(out[index as usize..].to_vec())
}
///Decrypts OAEP padding.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
pub(crate) fn oaep_decrypt_digest<D: Digest, MGD: Digest + FixedOutputReset>(
em: &mut [u8],
label: Option<String>,
k: usize,
) -> Result<Vec<u8>> {
let h_size = <D as Digest>::output_size();
let label = label.unwrap_or_default();
if label.len() as u64 > MAX_LABEL_LEN {
return Err(Error::LabelTooLong);
}
let expected_p_hash = D::digest(label.as_bytes());
let res = decrypt_inner(em, h_size, &expected_p_hash, k, |seed, db| {
let mut mgf_digest = MGD::new();
mgf1_xor_digest(seed, &mut mgf_digest, db);
mgf1_xor_digest(db, &mut mgf_digest, seed);
})?;
if res.is_none().into() {
return Err(Error::Decryption);
}
let (out, index) = res.unwrap();
Ok(out[index as usize..].to_vec())
}
/// Decrypts OAEP padding. It returns one or zero in valid that indicates whether the
/// plaintext was correctly structured.
#[inline]
fn decrypt_inner<MGF: FnMut(&mut [u8], &mut [u8])>(
em: &mut [u8],
h_size: usize,
expected_p_hash: &[u8],
k: usize,
mut mgf: MGF,
) -> Result<CtOption<(Vec<u8>, u32)>> {
if k < 11 {
return Err(Error::Decryption);
}
if k < h_size * 2 + 2 {
return Err(Error::Decryption);
}
let first_byte_is_zero = em[0].ct_eq(&0u8);
let (_, payload) = em.split_at_mut(1);
let (seed, db) = payload.split_at_mut(h_size);
mgf(seed, db);
let hash_are_equal = db[0..h_size].ct_eq(expected_p_hash);
// The remainder of the plaintext must be zero or more 0x00, followed
// by 0x01, followed by the message.
// looking_for_index: 1 if we are still looking for the 0x01
// index: the offset of the first 0x01 byte
// zero_before_one: 1 if we saw a non-zero byte before the 1
let mut looking_for_index = Choice::from(1u8);
let mut index = 0u32;
let mut nonzero_before_one = Choice::from(0u8);
for (i, el) in db.iter().skip(h_size).enumerate() {
let equals0 = el.ct_eq(&0u8);
let equals1 = el.ct_eq(&1u8);
index.conditional_assign(&(i as u32), looking_for_index & equals1);
looking_for_index &= !equals1;
nonzero_before_one |= looking_for_index & !equals0;
}
let valid = first_byte_is_zero & hash_are_equal & !nonzero_before_one & !looking_for_index;
Ok(CtOption::new(
(em.to_vec(), index + 2 + (h_size * 2) as u32),
valid,
))
}

55
vendor/rsa/src/algorithms/pad.rs vendored Normal file
View File

@@ -0,0 +1,55 @@
//! Special handling for converting the BigUint to u8 vectors
use alloc::vec::Vec;
use num_bigint::BigUint;
use zeroize::Zeroizing;
use crate::errors::{Error, Result};
/// Returns a new vector of the given length, with 0s left padded.
#[inline]
fn left_pad(input: &[u8], padded_len: usize) -> Result<Vec<u8>> {
if input.len() > padded_len {
return Err(Error::InvalidPadLen);
}
let mut out = vec![0u8; padded_len];
out[padded_len - input.len()..].copy_from_slice(input);
Ok(out)
}
/// Converts input to the new vector of the given length, using BE and with 0s left padded.
#[inline]
pub(crate) fn uint_to_be_pad(input: BigUint, padded_len: usize) -> Result<Vec<u8>> {
left_pad(&input.to_bytes_be(), padded_len)
}
/// Converts input to the new vector of the given length, using BE and with 0s left padded.
#[inline]
pub(crate) fn uint_to_zeroizing_be_pad(input: BigUint, padded_len: usize) -> Result<Vec<u8>> {
let m = Zeroizing::new(input);
let m = Zeroizing::new(m.to_bytes_be());
left_pad(&m, padded_len)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_left_pad() {
const INPUT_LEN: usize = 3;
let input = vec![0u8; INPUT_LEN];
// input len < padded len
let padded = left_pad(&input, INPUT_LEN + 1).unwrap();
assert_eq!(padded.len(), INPUT_LEN + 1);
// input len == padded len
let padded = left_pad(&input, INPUT_LEN).unwrap();
assert_eq!(padded.len(), INPUT_LEN);
// input len > padded len
let padded = left_pad(&input, INPUT_LEN - 1);
assert!(padded.is_err());
}
}

207
vendor/rsa/src/algorithms/pkcs1v15.rs vendored Normal file
View File

@@ -0,0 +1,207 @@
//! PKCS#1 v1.5 support as described in [RFC8017 § 8.2].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pkcs1-v15-signatures).
//!
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
use alloc::vec::Vec;
use digest::Digest;
use pkcs8::AssociatedOid;
use rand_core::CryptoRngCore;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroizing;
use crate::errors::{Error, Result};
/// Fills the provided slice with random values, which are guaranteed
/// to not be zero.
#[inline]
fn non_zero_random_bytes<R: CryptoRngCore + ?Sized>(rng: &mut R, data: &mut [u8]) {
rng.fill_bytes(data);
for el in data {
if *el == 0u8 {
// TODO: break after a certain amount of time
while *el == 0u8 {
rng.fill_bytes(core::slice::from_mut(el));
}
}
}
}
/// Applied the padding scheme from PKCS#1 v1.5 for encryption. The message must be no longer than
/// the length of the public modulus minus 11 bytes.
pub(crate) fn pkcs1v15_encrypt_pad<R>(
rng: &mut R,
msg: &[u8],
k: usize,
) -> Result<Zeroizing<Vec<u8>>>
where
R: CryptoRngCore + ?Sized,
{
if msg.len() + 11 > k {
return Err(Error::MessageTooLong);
}
// EM = 0x00 || 0x02 || PS || 0x00 || M
let mut em = Zeroizing::new(vec![0u8; k]);
em[1] = 2;
non_zero_random_bytes(rng, &mut em[2..k - msg.len() - 1]);
em[k - msg.len() - 1] = 0;
em[k - msg.len()..].copy_from_slice(msg);
Ok(em)
}
/// Removes the encryption padding scheme from PKCS#1 v1.5.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key. See
/// `decrypt_session_key` for a way of solving this problem.
#[inline]
pub(crate) fn pkcs1v15_encrypt_unpad(em: Vec<u8>, k: usize) -> Result<Vec<u8>> {
let (valid, out, index) = decrypt_inner(em, k)?;
if valid == 0 {
return Err(Error::Decryption);
}
Ok(out[index as usize..].to_vec())
}
/// Removes the PKCS1v15 padding It returns one or zero in valid that indicates whether the
/// plaintext was correctly structured. In either case, the plaintext is
/// returned in em so that it may be read independently of whether it was valid
/// in order to maintain constant memory access patterns. If the plaintext was
/// valid then index contains the index of the original message in em.
#[inline]
fn decrypt_inner(em: Vec<u8>, k: usize) -> Result<(u8, Vec<u8>, u32)> {
if k < 11 {
return Err(Error::Decryption);
}
let first_byte_is_zero = em[0].ct_eq(&0u8);
let second_byte_is_two = em[1].ct_eq(&2u8);
// The remainder of the plaintext must be a string of non-zero random
// octets, followed by a 0, followed by the message.
// looking_for_index: 1 iff we are still looking for the zero.
// index: the offset of the first zero byte.
let mut looking_for_index = 1u8;
let mut index = 0u32;
for (i, el) in em.iter().enumerate().skip(2) {
let equals0 = el.ct_eq(&0u8);
index.conditional_assign(&(i as u32), Choice::from(looking_for_index) & equals0);
looking_for_index.conditional_assign(&0u8, equals0);
}
// The PS padding must be at least 8 bytes long, and it starts two
// bytes into em.
// TODO: WARNING: THIS MUST BE CONSTANT TIME CHECK:
// Ref: https://github.com/dalek-cryptography/subtle/issues/20
// This is currently copy & paste from the constant time impl in
// go, but very likely not sufficient.
let valid_ps = Choice::from((((2i32 + 8i32 - index as i32 - 1i32) >> 31) & 1) as u8);
let valid =
first_byte_is_zero & second_byte_is_two & Choice::from(!looking_for_index & 1) & valid_ps;
index = u32::conditional_select(&0, &(index + 1), valid);
Ok((valid.unwrap_u8(), em, index))
}
#[inline]
pub(crate) fn pkcs1v15_sign_pad(prefix: &[u8], hashed: &[u8], k: usize) -> Result<Vec<u8>> {
let hash_len = hashed.len();
let t_len = prefix.len() + hashed.len();
if k < t_len + 11 {
return Err(Error::MessageTooLong);
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
let mut em = vec![0xff; k];
em[0] = 0;
em[1] = 1;
em[k - t_len - 1] = 0;
em[k - t_len..k - hash_len].copy_from_slice(prefix);
em[k - hash_len..k].copy_from_slice(hashed);
Ok(em)
}
#[inline]
pub(crate) fn pkcs1v15_sign_unpad(prefix: &[u8], hashed: &[u8], em: &[u8], k: usize) -> Result<()> {
let hash_len = hashed.len();
let t_len = prefix.len() + hashed.len();
if k < t_len + 11 {
return Err(Error::Verification);
}
// EM = 0x00 || 0x01 || PS || 0x00 || T
let mut ok = em[0].ct_eq(&0u8);
ok &= em[1].ct_eq(&1u8);
ok &= em[k - hash_len..k].ct_eq(hashed);
ok &= em[k - t_len..k - hash_len].ct_eq(prefix);
ok &= em[k - t_len - 1].ct_eq(&0u8);
for el in em.iter().skip(2).take(k - t_len - 3) {
ok &= el.ct_eq(&0xff)
}
if ok.unwrap_u8() != 1 {
return Err(Error::Verification);
}
Ok(())
}
/// prefix = 0x30 <oid_len + 8 + digest_len> 0x30 <oid_len + 4> 0x06 <oid_len> oid 0x05 0x00 0x04 <digest_len>
#[inline]
pub(crate) fn pkcs1v15_generate_prefix<D>() -> Vec<u8>
where
D: Digest + AssociatedOid,
{
let oid = D::OID.as_bytes();
let oid_len = oid.len() as u8;
let digest_len = <D as Digest>::output_size() as u8;
let mut v = vec![
0x30,
oid_len + 8 + digest_len,
0x30,
oid_len + 4,
0x6,
oid_len,
];
v.extend_from_slice(oid);
v.extend_from_slice(&[0x05, 0x00, 0x04, digest_len]);
v
}
#[cfg(test)]
mod tests {
use super::*;
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
#[test]
fn test_non_zero_bytes() {
for _ in 0..10 {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let mut b = vec![0u8; 512];
non_zero_random_bytes(&mut rng, &mut b);
for el in &b {
assert_ne!(*el, 0u8);
}
}
}
#[test]
fn test_encrypt_tiny_no_crash() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = 8;
let message = vec![1u8; 4];
let res = pkcs1v15_encrypt_pad(&mut rng, &message, k);
assert_eq!(res, Err(Error::MessageTooLong));
}
}

334
vendor/rsa/src/algorithms/pss.rs vendored Normal file
View File

@@ -0,0 +1,334 @@
//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
//!
//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pss-signatures).
//!
//! [Probabilistic Signature Scheme]: https://en.wikipedia.org/wiki/Probabilistic_signature_scheme
//! [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
use alloc::vec::Vec;
use digest::{Digest, DynDigest, FixedOutputReset};
use subtle::{Choice, ConstantTimeEq};
use super::mgf::{mgf1_xor, mgf1_xor_digest};
use crate::errors::{Error, Result};
pub(crate) fn emsa_pss_encode(
m_hash: &[u8],
em_bits: usize,
salt: &[u8],
hash: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
// See [1], section 9.1.1
let h_len = hash.output_size();
let s_len = salt.len();
let em_len = (em_bits + 7) / 8;
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.
//
// 2. Let mHash = Hash(M), an octet string of length hLen.
if m_hash.len() != h_len {
return Err(Error::InputNotHashed);
}
// 3. If em_len < h_len + s_len + 2, output "encoding error" and stop.
if em_len < h_len + s_len + 2 {
// TODO: Key size too small
return Err(Error::Internal);
}
let mut em = vec![0; em_len];
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - db.len()];
// 4. Generate a random octet string salt of length s_len; if s_len = 0,
// then salt is the empty string.
//
// 5. Let
// M' = (0x)00 00 00 00 00 00 00 00 || m_hash || salt;
//
// M' is an octet string of length 8 + h_len + s_len with eight
// initial zero octets.
//
// 6. Let H = Hash(M'), an octet string of length h_len.
let prefix = [0u8; 8];
hash.update(&prefix);
hash.update(m_hash);
hash.update(salt);
let hashed = hash.finalize_reset();
h.copy_from_slice(&hashed);
// 7. Generate an octet string PS consisting of em_len - s_len - h_len - 2
// zero octets. The length of PS may be 0.
//
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);
// 9. Let dbMask = MGF(H, emLen - hLen - 1).
//
// 10. Let maskedDB = DB \xor dbMask.
mgf1_xor(db, hash, h);
// 11. Set the leftmost 8 * em_len - em_bits bits of the leftmost octet in
// maskedDB to zero.
db[0] &= 0xFF >> (8 * em_len - em_bits);
// 12. Let EM = maskedDB || H || 0xbc.
em[em_len - 1] = 0xBC;
Ok(em)
}
pub(crate) fn emsa_pss_encode_digest<D>(
m_hash: &[u8],
em_bits: usize,
salt: &[u8],
) -> Result<Vec<u8>>
where
D: Digest + FixedOutputReset,
{
// See [1], section 9.1.1
let h_len = <D as Digest>::output_size();
let s_len = salt.len();
let em_len = (em_bits + 7) / 8;
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "message too
// long" and stop.
//
// 2. Let mHash = Hash(M), an octet string of length hLen.
if m_hash.len() != h_len {
return Err(Error::InputNotHashed);
}
// 3. If em_len < h_len + s_len + 2, output "encoding error" and stop.
if em_len < h_len + s_len + 2 {
// TODO: Key size too small
return Err(Error::Internal);
}
let mut em = vec![0; em_len];
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..(em_len - 1) - db.len()];
// 4. Generate a random octet string salt of length s_len; if s_len = 0,
// then salt is the empty string.
//
// 5. Let
// M' = (0x)00 00 00 00 00 00 00 00 || m_hash || salt;
//
// M' is an octet string of length 8 + h_len + s_len with eight
// initial zero octets.
//
// 6. Let H = Hash(M'), an octet string of length h_len.
let prefix = [0u8; 8];
let mut hash = D::new();
Digest::update(&mut hash, prefix);
Digest::update(&mut hash, m_hash);
Digest::update(&mut hash, salt);
let hashed = hash.finalize_reset();
h.copy_from_slice(&hashed);
// 7. Generate an octet string PS consisting of em_len - s_len - h_len - 2
// zero octets. The length of PS may be 0.
//
// 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
// emLen - hLen - 1.
db[em_len - s_len - h_len - 2] = 0x01;
db[em_len - s_len - h_len - 1..].copy_from_slice(salt);
// 9. Let dbMask = MGF(H, emLen - hLen - 1).
//
// 10. Let maskedDB = DB \xor dbMask.
mgf1_xor_digest(db, &mut hash, h);
// 11. Set the leftmost 8 * em_len - em_bits bits of the leftmost octet in
// maskedDB to zero.
db[0] &= 0xFF >> (8 * em_len - em_bits);
// 12. Let EM = maskedDB || H || 0xbc.
em[em_len - 1] = 0xBC;
Ok(em)
}
fn emsa_pss_verify_pre<'a>(
m_hash: &[u8],
em: &'a mut [u8],
em_bits: usize,
s_len: usize,
h_len: usize,
) -> Result<(&'a mut [u8], &'a mut [u8])> {
// 1. If the length of M is greater than the input limitation for the
// hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
// and stop.
//
// 2. Let mHash = Hash(M), an octet string of length hLen
if m_hash.len() != h_len {
return Err(Error::Verification);
}
// 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
let em_len = em.len(); //(em_bits + 7) / 8;
if em_len < h_len + s_len + 2 {
return Err(Error::Verification);
}
// 4. If the rightmost octet of EM does not have hexadecimal value
// 0xbc, output "inconsistent" and stop.
if em[em.len() - 1] != 0xBC {
return Err(Error::Verification);
}
// 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
// let H be the next hLen octets.
let (db, h) = em.split_at_mut(em_len - h_len - 1);
let h = &mut h[..h_len];
// 6. If the leftmost 8 * em_len - em_bits bits of the leftmost octet in
// maskedDB are not all equal to zero, output "inconsistent" and
// stop.
if db[0]
& (0xFF_u8
.checked_shl(8 - (8 * em_len - em_bits) as u32)
.unwrap_or(0))
!= 0
{
return Err(Error::Verification);
}
Ok((db, h))
}
fn emsa_pss_verify_salt(db: &[u8], em_len: usize, s_len: usize, h_len: usize) -> Choice {
// 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
// or if the octet at position emLen - hLen - sLen - 1 (the leftmost
// position is "position 1") does not have hexadecimal value 0x01,
// output "inconsistent" and stop.
let (zeroes, rest) = db.split_at(em_len - h_len - s_len - 2);
let valid: Choice = zeroes
.iter()
.fold(Choice::from(1u8), |a, e| a & e.ct_eq(&0x00));
valid & rest[0].ct_eq(&0x01)
}
pub(crate) fn emsa_pss_verify(
m_hash: &[u8],
em: &mut [u8],
s_len: usize,
hash: &mut dyn DynDigest,
key_bits: usize,
) -> Result<()> {
let em_bits = key_bits - 1;
let em_len = (em_bits + 7) / 8;
let key_len = (key_bits + 7) / 8;
let h_len = hash.output_size();
let em = &mut em[key_len - em_len..];
let (db, h) = emsa_pss_verify_pre(m_hash, em, em_bits, s_len, h_len)?;
// 7. Let dbMask = MGF(H, em_len - h_len - 1)
//
// 8. Let DB = maskedDB \xor dbMask
mgf1_xor(db, hash, &*h);
// 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
// to zero.
db[0] &= 0xFF >> /*uint*/(8 * em_len - em_bits);
let salt_valid = emsa_pss_verify_salt(db, em_len, s_len, h_len);
// 11. Let salt be the last s_len octets of DB.
let salt = &db[db.len() - s_len..];
// 12. Let
// M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
// M' is an octet string of length 8 + hLen + sLen with eight
// initial zero octets.
//
// 13. Let H' = Hash(M'), an octet string of length hLen.
let prefix = [0u8; 8];
hash.update(&prefix[..]);
hash.update(m_hash);
hash.update(salt);
let h0 = hash.finalize_reset();
// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if (salt_valid & h0.ct_eq(h)).into() {
Ok(())
} else {
Err(Error::Verification)
}
}
pub(crate) fn emsa_pss_verify_digest<D>(
m_hash: &[u8],
em: &mut [u8],
s_len: usize,
key_bits: usize,
) -> Result<()>
where
D: Digest + FixedOutputReset,
{
let em_bits = key_bits - 1;
let em_len = (em_bits + 7) / 8;
let key_len = (key_bits + 7) / 8;
let h_len = <D as Digest>::output_size();
let em = &mut em[key_len - em_len..];
let (db, h) = emsa_pss_verify_pre(m_hash, em, em_bits, s_len, h_len)?;
let mut hash = D::new();
// 7. Let dbMask = MGF(H, em_len - h_len - 1)
//
// 8. Let DB = maskedDB \xor dbMask
mgf1_xor_digest::<D>(db, &mut hash, &*h);
// 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
// to zero.
db[0] &= 0xFF >> /*uint*/(8 * em_len - em_bits);
let salt_valid = emsa_pss_verify_salt(db, em_len, s_len, h_len);
// 11. Let salt be the last s_len octets of DB.
let salt = &db[db.len() - s_len..];
// 12. Let
// M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
// M' is an octet string of length 8 + hLen + sLen with eight
// initial zero octets.
//
// 13. Let H' = Hash(M'), an octet string of length hLen.
let prefix = [0u8; 8];
Digest::update(&mut hash, &prefix[..]);
Digest::update(&mut hash, m_hash);
Digest::update(&mut hash, salt);
let h0 = hash.finalize_reset();
// 14. If H = H', output "consistent." Otherwise, output "inconsistent."
if (salt_valid & h0.ct_eq(h)).into() {
Ok(())
} else {
Err(Error::Verification)
}
}

328
vendor/rsa/src/algorithms/rsa.rs vendored Normal file
View File

@@ -0,0 +1,328 @@
//! 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 rand_core::CryptoRngCore;
use zeroize::{Zeroize, Zeroizing};
use crate::errors::{Error, Result};
use crate::traits::{PrivateKeyParts, PublicKeyParts};
/// ⚠️ Raw RSA encryption of m with the public key. No padding is performed.
///
/// # ☢️️ WARNING: HAZARDOUS API ☢️
///
/// 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<K: PublicKeyParts>(key: &K, m: &BigUint) -> Result<BigUint> {
Ok(m.modpow(key.e(), key.n()))
}
/// ⚠️ Performs raw RSA decryption with no padding or error checking.
///
/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed.
///
/// # ☢️️ WARNING: HAZARDOUS API ☢️
///
/// 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_decrypt<R: CryptoRngCore + ?Sized>(
mut rng: Option<&mut R>,
priv_key: &impl PrivateKeyParts,
c: &BigUint,
) -> Result<BigUint> {
if c >= priv_key.n() {
return Err(Error::Decryption);
}
if priv_key.n().is_zero() {
return Err(Error::Decryption);
}
let mut ir = None;
let c = if let Some(ref mut rng) = rng {
let (blinded, unblinder) = blind(rng, priv_key, c);
ir = Some(unblinder);
Cow::Owned(blinded)
} else {
Cow::Borrowed(c)
};
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()),
};
match ir {
Some(ref ir) => {
// unblind
Ok(unblind(priv_key, &m, ir))
}
None => Ok(m),
}
}
/// ⚠️ Performs raw RSA decryption with no padding.
///
/// Returns a plaintext `BigUint`. Performs RSA blinding if an `Rng` is passed. This will also
/// check for errors in the CRT computation.
///
/// # ☢️️ WARNING: HAZARDOUS API ☢️
///
/// 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_decrypt_and_check<R: CryptoRngCore + ?Sized>(
priv_key: &impl PrivateKeyParts,
rng: Option<&mut R>,
c: &BigUint,
) -> Result<BigUint> {
let m = rsa_decrypt(rng, priv_key, c)?;
// In order to defend against errors in the CRT computation, m^e is
// calculated, which should match the original ciphertext.
let check = rsa_encrypt(priv_key, &m)?;
if c != &check {
return Err(Error::Internal);
}
Ok(m)
}
/// Returns the blinded c, along with the unblinding factor.
fn blind<R: CryptoRngCore, K: PublicKeyParts>(
rng: &mut R,
key: &K,
c: &BigUint,
) -> (BigUint, BigUint) {
// 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<BigInt>;
let unblinder;
loop {
r = rng.gen_biguint_below(key.n());
if r.is_zero() {
r = BigUint::one();
}
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();
rpowe.zeroize();
c
};
(c, unblinder)
}
/// Given an m and and unblinding factor, unblind the m.
fn unblind(key: &impl PublicKeyParts, m: &BigUint, unblinder: &BigUint) -> BigUint {
(m * unblinder) % key.n()
}
/// 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)> {
// Check precondition
let two = BigUint::from_u8(2).unwrap();
if e <= &two.pow(16u32) || e >= &two.pow(256u32) {
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)));
// 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);
// 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() {
return Err(Error::InvalidArguments);
}
let b = Zeroizing::new((n - &*r) / (&*m + &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 {
return Err(Error::InvalidArguments);
}
let b_squared_minus_four_n = Zeroizing::new(&*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_squared = Zeroizing::new(y.pow(2u32));
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;
Ok((p, q))
}
/// Compute the modulus of a key from its primes.
pub(crate) fn compute_modulus(primes: &[BigUint]) -> BigUint {
primes.iter().product()
}
/// 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<BigUint> {
if primes.len() < 2 {
return Err(Error::InvalidPrime);
}
let mut totient = BigUint::one();
for prime in primes {
totient *= prime - BigUint::one();
}
// 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)
}
}
/// Compute the private exponent from its primes (p and q) and public exponent
///
/// This is using the method defined by
/// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47).
/// (Carmichael function)
///
/// FIPS 186-4 **requires** the private exponent to be less than λ(n), which would
/// make Euler's totiem unreliable.
#[inline]
pub(crate) fn compute_private_exponent_carmicheal(
p: &BigUint,
q: &BigUint,
exp: &BigUint,
) -> Result<BigUint> {
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())
} else {
// `exp` evenly divides `lcm`
Err(Error::InvalidPrime)
}
}
#[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 (mut p1, mut q1) = recover_primes(&n, &e, &d).unwrap();
if p1 < q1 {
std::mem::swap(&mut p1, &mut q1);
}
assert_eq!(p, p1);
assert_eq!(q, q1);
}
}

26
vendor/rsa/src/dummy_rng.rs vendored Normal file
View File

@@ -0,0 +1,26 @@
use rand_core::{CryptoRng, RngCore};
/// This is a dummy RNG for cases when we need a concrete RNG type
/// which does not get used.
#[derive(Copy, Clone)]
pub(crate) struct DummyRng;
impl RngCore for DummyRng {
fn next_u32(&mut self) -> u32 {
unimplemented!();
}
fn next_u64(&mut self) -> u64 {
unimplemented!();
}
fn fill_bytes(&mut self, _: &mut [u8]) {
unimplemented!();
}
fn try_fill_bytes(&mut self, _: &mut [u8]) -> core::result::Result<(), rand_core::Error> {
unimplemented!();
}
}
impl CryptoRng for DummyRng {}

122
vendor/rsa/src/encoding.rs vendored Normal file
View File

@@ -0,0 +1,122 @@
//! PKCS#1 and PKCS#8 encoding support.
//!
//! Note: PKCS#1 support is achieved through a blanket impl of the
//! `pkcs1` crate's traits for types which impl the `pkcs8` crate's traits.
use crate::{
traits::{PrivateKeyParts, PublicKeyParts},
BigUint, RsaPrivateKey, RsaPublicKey,
};
use core::convert::{TryFrom, TryInto};
use pkcs8::{der::Encode, Document, EncodePrivateKey, EncodePublicKey, SecretDocument};
use zeroize::Zeroizing;
/// Verify that the `AlgorithmIdentifier` for a key is correct.
fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> pkcs8::spki::Result<()> {
algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?;
if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() {
return Err(pkcs8::spki::Error::KeyMalformed);
}
Ok(())
}
impl TryFrom<pkcs8::PrivateKeyInfo<'_>> for RsaPrivateKey {
type Error = pkcs8::Error;
fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
verify_algorithm_id(&private_key_info.algorithm)?;
let pkcs1_key = pkcs1::RsaPrivateKey::try_from(private_key_info.private_key)?;
// Multi-prime RSA keys not currently supported
if pkcs1_key.version() != pkcs1::Version::TwoPrime {
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 primes = vec![prime1, prime2];
RsaPrivateKey::from_components(n, e, d, primes).map_err(|_| pkcs8::Error::KeyMalformed)
}
}
impl TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for RsaPublicKey {
type Error = pkcs8::spki::Error;
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
verify_algorithm_id(&spki.algorithm)?;
let pkcs1_key = pkcs1::RsaPublicKey::try_from(
spki.subject_public_key
.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());
RsaPublicKey::new(n, e).map_err(|_| pkcs8::spki::Error::KeyMalformed)
}
}
impl EncodePrivateKey for RsaPrivateKey {
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
// Check if the key is multi prime
if self.primes.len() > 2 {
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 coefficient = Zeroizing::new(
self.crt_coefficient()
.ok_or(pkcs1::Error::Crypto)?
.to_bytes_be(),
);
let private_key = pkcs1::RsaPrivateKey {
modulus: pkcs1::UintRef::new(&modulus)?,
public_exponent: pkcs1::UintRef::new(&public_exponent)?,
private_exponent: pkcs1::UintRef::new(&private_exponent)?,
prime1: pkcs1::UintRef::new(&prime1)?,
prime2: pkcs1::UintRef::new(&prime2)?,
exponent1: pkcs1::UintRef::new(&exponent1)?,
exponent2: pkcs1::UintRef::new(&exponent2)?,
coefficient: pkcs1::UintRef::new(&coefficient)?,
other_prime_infos: None,
}
.to_der()?;
pkcs8::PrivateKeyInfo::new(pkcs1::ALGORITHM_ID, private_key.as_ref()).try_into()
}
}
impl EncodePublicKey for RsaPublicKey {
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
let modulus = self.n().to_bytes_be();
let public_exponent = self.e().to_bytes_be();
let subject_public_key = pkcs1::RsaPublicKey {
modulus: pkcs1::UintRef::new(&modulus)?,
public_exponent: pkcs1::UintRef::new(&public_exponent)?,
}
.to_der()?;
pkcs8::SubjectPublicKeyInfoRef {
algorithm: pkcs1::ALGORITHM_ID,
subject_public_key: pkcs8::der::asn1::BitStringRef::new(
0,
subject_public_key.as_ref(),
)?,
}
.try_into()
}
}

126
vendor/rsa/src/errors.rs vendored Normal file
View File

@@ -0,0 +1,126 @@
//! Error types.
/// Alias for [`core::result::Result`] with the `rsa` crate's [`Error`] type.
pub type Result<T> = core::result::Result<T, Error>;
/// Error types
#[derive(Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// Invalid padding scheme.
InvalidPaddingScheme,
/// Decryption error.
Decryption,
/// Verification error.
Verification,
/// Message too long.
MessageTooLong,
/// Input must be hashed.
InputNotHashed,
/// Number of primes must be 2 or greater.
NprimesTooSmall,
/// Too few primes of a given length to generate an RSA key.
TooFewPrimes,
/// Invalid prime value.
InvalidPrime,
/// Invalid modulus.
InvalidModulus,
/// Invalid exponent.
InvalidExponent,
/// Invalid coefficient.
InvalidCoefficient,
/// Modulus too large.
ModulusTooLarge,
/// Public exponent too small.
PublicExponentTooSmall,
/// Public exponent too large.
PublicExponentTooLarge,
/// PKCS#1 error.
Pkcs1(pkcs1::Error),
/// PKCS#8 error.
Pkcs8(pkcs8::Error),
/// Internal error.
Internal,
/// Label too long.
LabelTooLong,
/// Invalid padding length.
InvalidPadLen,
/// Invalid arguments.
InvalidArguments,
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Error::InvalidPaddingScheme => write!(f, "invalid padding scheme"),
Error::Decryption => write!(f, "decryption error"),
Error::Verification => write!(f, "verification error"),
Error::MessageTooLong => write!(f, "message too long"),
Error::InputNotHashed => write!(f, "input must be hashed"),
Error::NprimesTooSmall => write!(f, "nprimes must be >= 2"),
Error::TooFewPrimes => {
write!(f, "too few primes of given length to generate an RSA key")
}
Error::InvalidPrime => write!(f, "invalid prime value"),
Error::InvalidModulus => write!(f, "invalid modulus"),
Error::InvalidExponent => write!(f, "invalid exponent"),
Error::InvalidCoefficient => write!(f, "invalid coefficient"),
Error::ModulusTooLarge => write!(f, "modulus too large"),
Error::PublicExponentTooSmall => write!(f, "public exponent too small"),
Error::PublicExponentTooLarge => write!(f, "public exponent too large"),
Error::Pkcs1(err) => write!(f, "{}", err),
Error::Pkcs8(err) => write!(f, "{}", err),
Error::Internal => write!(f, "internal error"),
Error::LabelTooLong => write!(f, "label too long"),
Error::InvalidPadLen => write!(f, "invalid padding length"),
Error::InvalidArguments => write!(f, "invalid arguments"),
}
}
}
impl From<pkcs1::Error> for Error {
fn from(err: pkcs1::Error) -> Error {
Error::Pkcs1(err)
}
}
impl From<pkcs8::Error> for Error {
fn from(err: pkcs8::Error) -> Error {
Error::Pkcs8(err)
}
}
#[cfg(feature = "std")]
impl From<Error> for signature::Error {
fn from(err: Error) -> Self {
Self::from_source(err)
}
}
#[cfg(not(feature = "std"))]
impl From<Error> for signature::Error {
fn from(_err: Error) -> Self {
Self::new()
}
}

14
vendor/rsa/src/hazmat.rs vendored Normal file
View File

@@ -0,0 +1,14 @@
//! ⚠️ Low-level "hazmat" RSA functions.
//!
//! # ☢️️ WARNING: HAZARDOUS API ☢️
//!
//! This module holds functions that apply RSA's core encryption and decryption
//! primitives to raw data without adding or removing appropriate padding. A
//! well-reviewed padding scheme is crucial to the security of RSA, so there are
//! very few valid uses cases for this API. It's intended to be used for
//! implementing well-reviewed higher-level constructions.
//!
//! We do NOT recommend using it to implement any algorithm which has not
//! received extensive peer review by cryptographers.
pub use crate::algorithms::rsa::{rsa_decrypt, rsa_decrypt_and_check, rsa_encrypt};

859
vendor/rsa/src/key.rs vendored Normal file
View File

@@ -0,0 +1,859 @@
use alloc::vec::Vec;
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 rand_core::CryptoRngCore;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::algorithms::generate::generate_multi_prime_key_with_exp;
use crate::algorithms::rsa::{
compute_modulus, compute_private_exponent_carmicheal, compute_private_exponent_euler_totient,
recover_primes,
};
use crate::dummy_rng::DummyRng;
use crate::errors::{Error, Result};
use crate::traits::{PaddingScheme, PrivateKeyParts, PublicKeyParts, SignatureScheme};
use crate::CrtValue;
/// Represents the public part of an RSA key.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RsaPublicKey {
/// Modulus: product of prime numbers `p` and `q`
n: BigUint,
/// Public exponent: power to which a plaintext message is raised in
/// order to encrypt it.
///
/// Typically 0x10001 (65537)
e: BigUint,
}
/// Represents a whole RSA key, public and private parts.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RsaPrivateKey {
/// Public components of the private key.
pubkey_components: RsaPublicKey,
/// Private exponent
pub(crate) d: BigUint,
/// Prime factors of N, contains >= 2 elements.
pub(crate) primes: Vec<BigUint>,
/// precomputed values to speed up private operations
#[cfg_attr(feature = "serde", serde(skip))]
pub(crate) precomputed: Option<PrecomputedValues>,
}
impl Eq for RsaPrivateKey {}
impl PartialEq for RsaPrivateKey {
#[inline]
fn eq(&self, other: &RsaPrivateKey) -> bool {
self.pubkey_components == other.pubkey_components
&& self.d == other.d
&& self.primes == other.primes
}
}
impl AsRef<RsaPublicKey> for RsaPrivateKey {
fn as_ref(&self) -> &RsaPublicKey {
&self.pubkey_components
}
}
impl Hash for RsaPrivateKey {
fn hash<H: Hasher>(&self, state: &mut H) {
// Domain separator for RSA private keys
state.write(b"RsaPrivateKey");
Hash::hash(&self.pubkey_components, state);
}
}
impl Drop for RsaPrivateKey {
fn drop(&mut self) {
self.d.zeroize();
self.primes.zeroize();
self.precomputed.zeroize();
}
}
impl ZeroizeOnDrop for RsaPrivateKey {}
#[derive(Debug, Clone)]
pub(crate) struct PrecomputedValues {
/// D mod (P-1)
pub(crate) dp: BigUint,
/// D mod (Q-1)
pub(crate) dq: BigUint,
/// Q^-1 mod P
pub(crate) qinv: BigInt,
/// 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<CrtValue>,
}
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();
}
}
impl Drop for PrecomputedValues {
fn drop(&mut self) {
self.zeroize();
}
}
impl From<RsaPrivateKey> for RsaPublicKey {
fn from(private_key: RsaPrivateKey) -> Self {
(&private_key).into()
}
}
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 }
}
}
impl PublicKeyParts for RsaPublicKey {
fn n(&self) -> &BigUint {
&self.n
}
fn e(&self) -> &BigUint {
&self.e
}
}
impl RsaPublicKey {
/// Encrypt the given message.
pub fn encrypt<R: CryptoRngCore, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
msg: &[u8],
) -> Result<Vec<u8>> {
padding.encrypt(rng, self, msg)
}
/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
scheme.verify(self, hashed, sig)
}
}
impl RsaPublicKey {
/// Minimum value of the public exponent `e`.
pub const MIN_PUB_EXPONENT: u64 = 2;
/// Maximum value of the public exponent `e`.
pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
/// Maximum size of the modulus `n` in bits.
pub const MAX_SIZE: usize = 4096;
/// Create a new public key from its components.
///
/// 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<Self> {
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<Self> {
let k = Self { n, e };
check_public_with_max_size(&k, Some(max_size))?;
Ok(k)
}
/// Create a new public key, bypassing checks around the modulus and public
/// exponent size.
///
/// 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 }
}
}
impl PublicKeyParts for RsaPrivateKey {
fn n(&self) -> &BigUint {
&self.pubkey_components.n
}
fn e(&self) -> &BigUint {
&self.pubkey_components.e
}
}
impl RsaPrivateKey {
/// Default exponent for RSA keys.
const EXP: u64 = 65537;
/// Generate a new Rsa key pair of the given bit size using the passed in `rng`.
pub fn new<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<RsaPrivateKey> {
let exp = BigUint::from_u64(Self::EXP).expect("invalid static exponent");
Self::new_with_exp(rng, bit_size, &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<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
exp: &BigUint,
) -> Result<RsaPrivateKey> {
let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
RsaPrivateKey::from_components(components.n, components.e, components.d, components.primes)
}
/// Constructs an RSA key pair from individual components:
///
/// - `n`: RSA modulus
/// - `e`: public exponent (i.e. encrypting exponent)
/// - `d`: private exponent (i.e. decrypting exponent)
/// - `primes`: prime factors of `n`: typically two primes `p` and `q`. More than two primes can
/// be provided for multiprime RSA, however this is generally not recommended. If no `primes`
/// are provided, a prime factor recovery algorithm will be employed to attempt to recover the
/// factors (as described in [NIST SP 800-56B Revision 2] Appendix C.2). This algorithm only
/// works if there are just two prime factors `p` and `q` (as opposed to multiprime), and `e`
/// is between 2^16 and 2^256.
///
/// [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<BigUint>,
) -> Result<RsaPrivateKey> {
if primes.len() < 2 {
if !primes.is_empty() {
return Err(Error::NprimesTooSmall);
}
// Recover `p` and `q` from `d`.
// See method in Appendix C.2: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
let (p, q) = recover_primes(&n, &e, &d)?;
primes.push(p);
primes.push(q);
}
let mut k = RsaPrivateKey {
pubkey_components: RsaPublicKey { n, e },
d,
primes,
precomputed: None,
};
// Always validate the key, to ensure precompute can't fail
k.validate()?;
// precompute when possible, ignore error otherwise.
let _ = k.precompute();
Ok(k)
}
/// Constructs an RSA key pair from its two primes p and q.
///
/// This will rebuild the private exponent and the modulus.
///
/// 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<RsaPrivateKey> {
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)?;
Self::from_components(n, public_exponent, d, vec![p, q])
}
/// Constructs an RSA key pair from its primes.
///
/// This will rebuild the private exponent and the modulus.
pub fn from_primes(primes: Vec<BigUint>, public_exponent: BigUint) -> Result<RsaPrivateKey> {
if primes.len() < 2 {
return Err(Error::NprimesTooSmall);
}
// Makes sure that primes is pairwise unequal.
for (i, prime1) in primes.iter().enumerate() {
for prime2 in primes.iter().take(i) {
if prime1 == prime2 {
return Err(Error::InvalidPrime);
}
}
}
let n = compute_modulus(&primes);
let d = compute_private_exponent_euler_totient(&primes, &public_exponent)?;
Self::from_components(n, public_exponent, d, primes)
}
/// Get the public key from the private key, cloning `n` and `e`.
///
/// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait,
/// but it can occasionally be useful to discard the private information entirely.
pub fn to_public_key(&self) -> RsaPublicKey {
self.pubkey_components.clone()
}
/// Performs some calculations to speed up private key operations.
pub fn precompute(&mut self) -> Result<()> {
if self.precomputed.is_some() {
return Ok(());
}
let dp = &self.d % (&self.primes[0] - BigUint::one());
let dq = &self.d % (&self.primes[1] - BigUint::one());
let qinv = self.primes[1]
.clone()
.mod_inverse(&self.primes[0])
.ok_or(Error::InvalidPrime)?;
let mut r: BigUint = &self.primes[0] * &self.primes[1];
let crt_values: Vec<CrtValue> = {
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
};
self.precomputed = Some(PrecomputedValues {
dp,
dq,
qinv,
crt_values,
});
Ok(())
}
/// Clears precomputed values by setting to None
pub fn clear_precomputed(&mut self) {
self.precomputed = None;
}
/// Compute CRT coefficient: `(1/q) mod p`.
pub fn crt_coefficient(&self) -> Option<BigUint> {
(&self.primes[1]).mod_inverse(&self.primes[0])?.to_biguint()
}
/// Performs basic sanity checks on the key.
/// Returns `Ok(())` if everything is good, otherwise an appropriate error.
pub fn validate(&self) -> Result<()> {
check_public(self)?;
// Check that Πprimes == n.
let mut m = BigUint::one();
for prime in &self.primes {
// Any primes ≤ 1 will cause divide-by-zero panics later.
if *prime <= BigUint::one() {
return Err(Error::InvalidPrime);
}
m *= prime;
}
if m != self.pubkey_components.n {
return Err(Error::InvalidModulus);
}
// Check that de ≡ 1 mod p-1, for each prime.
// This implies that e is coprime to each p-1 as e has a multiplicative
// 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();
for prime in &self.primes {
let congruence: BigUint = &de % (prime - BigUint::one());
if !congruence.is_one() {
return Err(Error::InvalidExponent);
}
}
Ok(())
}
/// Decrypt the given message.
pub fn decrypt<P: PaddingScheme>(&self, padding: P, ciphertext: &[u8]) -> Result<Vec<u8>> {
padding.decrypt(Option::<&mut DummyRng>::None, self, ciphertext)
}
/// Decrypt the given message.
///
/// Uses `rng` to blind the decryption process.
pub fn decrypt_blinded<R: CryptoRngCore, P: PaddingScheme>(
&self,
rng: &mut R,
padding: P,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
padding.decrypt(Some(rng), self, ciphertext)
}
/// Sign the given digest.
pub fn sign<S: SignatureScheme>(&self, padding: S, digest_in: &[u8]) -> Result<Vec<u8>> {
padding.sign(Option::<&mut DummyRng>::None, self, digest_in)
}
/// Sign the given digest using the provided `rng`, which is used in the
/// following ways depending on the [`SignatureScheme`]:
///
/// - [`Pkcs1v15Sign`][`crate::Pkcs1v15Sign`] padding: uses the RNG
/// to mask the private key operation with random blinding, which helps
/// mitigate sidechannel attacks.
/// - [`Pss`][`crate::Pss`] always requires randomness. Use
/// [`Pss::new`][`crate::Pss::new`] for a standard RSASSA-PSS signature, or
/// [`Pss::new_blinded`][`crate::Pss::new_blinded`] for RSA-BSSA blind
/// signatures.
pub fn sign_with_rng<R: CryptoRngCore, S: SignatureScheme>(
&self,
rng: &mut R,
padding: S,
digest_in: &[u8],
) -> Result<Vec<u8>> {
padding.sign(Some(rng), self, digest_in)
}
}
impl PrivateKeyParts for RsaPrivateKey {
fn d(&self) -> &BigUint {
&self.d
}
fn primes(&self) -> &[BigUint] {
&self.primes
}
fn dp(&self) -> Option<&BigUint> {
self.precomputed.as_ref().map(|p| &p.dp)
}
fn dq(&self) -> Option<&BigUint> {
self.precomputed.as_ref().map(|p| &p.dq)
}
fn qinv(&self) -> Option<&BigInt> {
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
}
}
}
/// 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, None)
}
/// 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: Option<usize>,
) -> Result<()> {
if let Some(max_size) = max_size {
if public_key.n().bits() > 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() {
return Err(Error::InvalidModulus);
}
if public_key.e().is_even() {
return Err(Error::InvalidExponent);
}
if e < RsaPublicKey::MIN_PUB_EXPONENT {
return Err(Error::PublicExponentTooSmall);
}
if e > RsaPublicKey::MAX_PUB_EXPONENT {
return Err(Error::PublicExponentTooLarge);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use hex_literal::hex;
use num_traits::{FromPrimitive, ToPrimitive, Zero};
use pkcs8::DecodePrivateKey;
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
#[test]
fn test_from_into() {
let private_key = RsaPrivateKey {
pubkey_components: RsaPublicKey {
n: BigUint::from_u64(100).unwrap(),
e: BigUint::from_u64(200).unwrap(),
},
d: BigUint::from_u64(123).unwrap(),
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));
}
fn test_key_basics(private_key: &RsaPrivateKey) {
private_key.validate().expect("invalid private key");
assert!(
private_key.d() < private_key.n(),
"private exponent too large"
);
let pub_key: RsaPublicKey = private_key.clone().into();
let m = BigUint::from_u64(42).expect("invalid 42");
let c = rsa_encrypt(&pub_key, &m).expect("encryption successfull");
let m2 = rsa_decrypt_and_check::<ChaCha8Rng>(private_key, None, &c)
.expect("unable to decrypt without blinding");
assert_eq!(m, m2);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let m3 = rsa_decrypt_and_check(private_key, Some(&mut rng), &c)
.expect("unable to decrypt with blinding");
assert_eq!(m, m3);
}
macro_rules! key_generation {
($name:ident, $multi:expr, $size:expr) => {
#[test]
fn $name() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let exp = BigUint::from_u64(RsaPrivateKey::EXP).expect("invalid static exponent");
for _ in 0..10 {
let components =
generate_multi_prime_key_with_exp(&mut rng, $multi, $size, &exp).unwrap();
let private_key = RsaPrivateKey::from_components(
components.n,
components.e,
components.d,
components.primes,
)
.unwrap();
assert_eq!(private_key.n().bits(), $size);
test_key_basics(&private_key);
}
}
};
}
key_generation!(key_generation_128, 2, 128);
key_generation!(key_generation_1024, 2, 1024);
key_generation!(key_generation_multi_3_256, 3, 256);
key_generation!(key_generation_multi_4_64, 4, 64);
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);
#[test]
fn test_negative_decryption_value() {
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,
]),
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]),
],
)
.unwrap();
for _ in 0..1000 {
test_key_basics(&private_key);
}
}
#[test]
#[cfg(feature = "serde")]
fn test_serde() {
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use serde_test::{assert_tokens, Token};
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
let priv_tokens = [
Token::Struct {
name: "RsaPrivateKey",
len: 3,
},
Token::Str("pubkey_components"),
Token::Struct {
name: "RsaPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(3814409919),
Token::U32(3429654832),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
Token::Str("d"),
Token::Seq { len: Some(2) },
Token::U32(1482162201),
Token::U32(1675500232),
Token::SeqEnd,
Token::Str("primes"),
Token::Seq { len: Some(2) },
Token::Seq { len: Some(1) },
Token::U32(4133289821),
Token::SeqEnd,
Token::Seq { len: Some(1) },
Token::U32(3563808971),
Token::SeqEnd,
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&priv_key, &priv_tokens);
let priv_tokens = [
Token::Struct {
name: "RsaPublicKey",
len: 2,
},
Token::Str("n"),
Token::Seq { len: Some(2) },
Token::U32(3814409919),
Token::U32(3429654832),
Token::SeqEnd,
Token::Str("e"),
Token::Seq { len: Some(1) },
Token::U32(65537),
Token::SeqEnd,
Token::StructEnd,
];
assert_tokens(&RsaPublicKey::from(priv_key), &priv_tokens);
}
#[test]
fn invalid_coeff_private_key_regression() {
use base64ct::{Base64, Encoding};
let n = Base64::decode_vec("wC8GyQvTCZOK+iiBR5fGQCmzRCTWX9TQ3aRG5gGFk0wB6EFoLMAyEEqeG3gS8xhAm2rSWYx9kKufvNat3iWlbSRVqkcbpVAYlj2vTrpqDpJl+6u+zxFYoUEBevlJJkAhl8EuCccOA30fVpcfRvXPTtvRd3yFT9E9EwZljtgSI02w7gZwg7VIxaGeajh5Euz6ZVQZ+qNRKgXrRC7gPRqVyI6Dt0Jc+Su5KBGNn0QcPDzOahWha1ieaeMkFisZ9mdpsJoZ4tw5eicLaUomKzALHXQVt+/rcZSrCd6/7uUo11B/CYBM4UfSpwXaL88J9AE6A5++no9hmJzaF2LLp+Qwx4yY3j9TDutxSAjsraxxJOGZ3XyA9nG++Ybt3cxZ5fP7ROjxCfROBmVv5dYn0O9OBIqYeCH6QraNpZMadlLNIhyMv8Y+P3r5l/PaK4VJaEi5pPosnEPawp0W0yZDzmjk2z1LthaRx0aZVrAjlH0Rb/6goLUQ9qu1xsDtQVVpN4A89ZUmtTWORnnJr0+595eHHxssd2gpzqf4bPjNITdAEuOCCtpvyi4ls23zwuzryUYjcUOEnsXNQ+DrZpLKxdtsD/qNV/j1hfeyBoPllC3cV+6bcGOFcVGbjYqb+Kw1b0+jL69RSKQqgmS+qYqr8c48nDRxyq3QXhR8qtzUwBFSLVk=").unwrap();
let e = Base64::decode_vec("AQAB").unwrap();
let d = Base64::decode_vec("qQazSQ+FRN7nVK1bRsROMRB8AmsDwLVEHivlz1V3Td2Dr+oW3YUMgxedhztML1IdQJPq/ad6qErJ6yRFNySVIjDaxzBTOEoB1eHa1btOnBJWb8rVvvjaorixvJ6Tn3i4EuhsvVy9DoR1k4rGj3qSIiFjUVvLRDAbLyhpGgEfsr0Z577yJmTC5E8JLRMOKX8Tmxsk3jPVpsgd65Hu1s8S/ZmabwuHCf9SkdMeY/1bd/9i7BqqJeeDLE4B5x1xcC3z3scqDUTzqGO+vZPhjgprPDRlBamVwgenhr7KwCn8iaLamFinRVwOAag8BeBqOJj7lURiOsKQa9FIX1kdFUS1QMQxgtPycLjkbvCJjriqT7zWKsmJ7l8YLs6Wmm9/+QJRwNCEVdMTXKfCP1cJjudaiskEQThfUldtgu8gUDNYbQ/Filb2eKfiX4h1TiMxZqUZHVZyb9nShbQoXJ3vj/MGVF0QM8TxhXM8r2Lv9gDYU5t9nQlUMLhs0jVjai48jHABbFNyH3sEcOmJOIwJrCXw1dzG7AotwyaEVUHOmL04TffmwCFfnyrLjbFgnyOeoyIIBYjcY7QFRm/9nupXMTH5hZ2qrHfCJIp0KK4tNBdQqmnHapFl5l6Le1s4qBS5bEIzjitobLvAFm9abPlDGfxmY6mlrMK4+nytwF9Ct7wc1AE=").unwrap();
let primes = vec![
Base64::decode_vec("9kQWEAzsbzOcdPa+s5wFfw4XDd7bB1q9foZ31b1+TNjGNxbSBCFlDF1q98vwpV6nM8bWDh/wtbNoETSQDgpEnYOQ26LWEw6YY1+q1Q2GGEFceYUf+Myk8/vTc8TN6Zw0bKZBWy10Qo8h7xk4JpzuI7NcxvjJYTkS9aErFxi3vVH0aiZC0tmfaCqr8a2rJxyVwqreRpOjwAWrotMsf2wGsF4ofx5ScoFy5GB5fJkkdOrW1LyTvZAUCX3cstPr19+TNC5zZOk7WzZatnCkN5H5WzalWtZuu0oVL205KPOa3R8V2yv5e6fm0v5fTmqSuvjmaMJLXCN4QJkmIzojO99ckQ==").unwrap(),
Base64::decode_vec("x8exdMjVA2CiI+Thx7loHtVcevoeE2sZ7btRVAvmBqo+lkHwxb7FHRnWvuj6eJSlD2f0T50EewIhhiW3R9BmktCk7hXjbSCnC1u9Oxc1IAUm/7azRqyfCMx43XhLxpD+xkBCpWkKDLxGczsRwTuaP3lKS3bSdBrNlGmdblubvVBIq4YZ2vXVlnYtza0cS+dgCK7BGTqUsrCUd/ZbIvwcwZkZtpkhj1KQfto9X/0OMurBzAqbkeq1cyRHXHkOfN/qbUIIRqr9Ii7Eswf9Vk8xp2O1Nt8nzcYS9PFD12M5eyaeFEkEYfpNMNGuTzp/31oqVjbpoCxS6vuWAZyADxhISQ==").unwrap(),
Base64::decode_vec("is7d0LY4HoXszlC2NO7gejkq7XqL4p1W6hZJPYTNx+r37t1CC2n3Vvzg6kNdpRixDhIpXVTLjN9O7UO/XuqSumYKJIKoP52eb4Tg+a3hw5Iz2Zsb5lUTNSLgkQSBPAf71LHxbL82JL4g1nBUog8ae60BwnVArThKY4EwlJguGNw09BAU4lwf6csDl/nX2vfVwiAloYpeZkHL+L8m+bueGZM5KE2jEz+7ztZCI+T+E5i69rZEYDjx0lfLKlEhQlCW3HbCPELqXgNJJkRfi6MP9kXa9lSfnZmoT081RMvqonB/FUa4HOcKyCrw9XZEtnbNCIdbitfDVEX+pSSD7596wQ==").unwrap(),
Base64::decode_vec("GPs0injugfycacaeIP5jMa/WX55VEnKLDHom4k6WlfDF4L4gIGoJdekcPEUfxOI5faKvHyFwRP1wObkPoRBDM0qZxRfBl4zEtpvjHrd5MibSyJkM8+J0BIKk/nSjbRIGeb3hV5O56PvGB3S0dKhCUnuVObiC+ne7izplsD4OTG70l1Yud33UFntyoMxrxGYLUSqhBMmZfHquJg4NOWOzKNY/K+EcHDLj1Kjvkcgv9Vf7ocsVxvpFdD9uGPceQ6kwRDdEl6mb+6FDgWuXVyqR9+904oanEIkbJ7vfkthagLbEf57dyG6nJlqh5FBZWxGIR72YGypPuAh7qnnqXXjY2Q==").unwrap(),
Base64::decode_vec("CUWC+hRWOT421kwRllgVjy6FYv6jQUcgDNHeAiYZnf5HjS9iK2ki7v8G5dL/0f+Yf+NhE/4q8w4m8go51hACrVpP1p8GJDjiT09+RsOzITsHwl+ceEKoe56ZW6iDHBLlrNw5/MtcYhKpjNU9KJ2udm5J/c9iislcjgckrZG2IB8ADgXHMEByZ5DgaMl4AKZ1Gx8/q6KftTvmOT5rNTMLi76VN5KWQcDWK/DqXiOiZHM7Nr4dX4me3XeRgABJyNR8Fqxj3N1+HrYLe/zs7LOaK0++F9Ul3tLelhrhsvLxei3oCZkF9A/foD3on3luYA+1cRcxWpSY3h2J4/22+yo4+Q==").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(),
);
assert_eq!(res, Err(Error::InvalidModulus));
}
#[test]
fn reject_oversized_private_key() {
// -----BEGIN PUBLIC KEY-----
// MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAkMBiB8qsNVXAsJR6Xoto
// H1r2rtZl/xzUK2tIfy99aPE489u+5tLxCQhQf+a89158vSDpr2/xwgK8w9u0Xpu2
// m7XRKjVMS0Y6UIINFoeTc87rVXT92Scr47kNVcGmSFXez4BSDpS+LKpWwXN+0AQu
// +cmcfdtsx2862iEbqQvq4PwKGQJOdOR0yldH8O4yeJK/buvIOXRHjb++vtQND/xi
// bFGAcd9WJqvaOG7tclhbZ277mbO6ER+y9Lj7AyO8ywybWqNeHaVPHMysPhT7HUWI
// 17m59i1OpuVwwEnvzDQQEUf9d5hUmkLYb5qQzuf6Ddnx/04QJCKAgkhyr9CXgnV6
// vEZ3PKtpicCHRxk7eqTEmgBlgwqH5vflRFV1iywQMXJnuRhzWOQaXl/vb8v4HIvF
// 4TatEZKqfzpbyScLIiYbPEAhHXKdZMd2zY8hkSbicifePApAZmuNpAxxJDZzphh7
// r4lD6t8MPT/RUAdtrZfihqaBhduFI6YeVIy6emg05M6YWvlUyer7nYGaPRS1JqD4
// 0v7xOtme5I8Qw6APiFPXhTqBK3occr7TgGb3V3lpC8Eq+esNHrji98R1fITkFXJW
// KdFcTWjBghPxiobUzMCFUrPIDJcWXeBzrARAryU+hXjEiFfzluXrps0B7RJQ/rLD
// LXeTn4vovUeHQVHa7YfoyWMy9pfqeVC+56LBK7SEIAvL0I3lrq5vIv+ZIuOAdbVg
// JiRy8DneCOk2LP3RnA8M0HSevYW93DiC+4h/l4ntjjiOfi6yRVOZ8WbVyXZ/83j4
// 6+pGWgvi0uMyb+btgOXjBQv7bGqdyHMc5Lqk5bF7ExETx51vKQMYCV4351caS6aX
// q16lYZATHgbTADEAZHdroDMJB+HMQaze9O6qU5ZO8wxxAjw89xry0dnoOQD/yA4H
// 7CRCo9vVDpV2hqIvHY9RI2T7cek28kmQpKvNvvK+ovmM138dHKViWULHk0fBRt7m
// 4wQ+tiL2PmJ/Tr8g1gVhM6S9D1XdE9z0KeDnODCWn1Q8sx2G2ah4ynnYQURDWcwO
// McAoP6bdJ7cCt+4F2tEsMPf4S/EwlnjvuNoQjvztxCPahYe9EnyggtQXyHJveIn7
// gDJsP6b93VB6x4QbLy5ch4DUhqDWginuKVeo7CTgDkq03j/IEaS1BHwreSDQceny
// +bYWONwV+4TMpGytKOHvU5288kmHbyZHdXuaXk8LLqbnqr30fa6Cbp4llCi9sH5a
// Kmi5jxQfVTe+elkMs7oVsLsVgkZS6NqPcOuEckAFijNqG223+IJoqvifCzO5Bdcs
// JTOLE+YaUYc8LUJwIaPykgcXmtMvQjeT8MCQ3aAlzkHfDpSvvICrXtqbGiaKolU6
// 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();
assert_eq!(
RsaPublicKey::new(n, e).err().unwrap(),
Error::ModulusTooLarge
);
}
#[test]
fn build_key_from_primes() {
const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/pkcs8/rsa2048-priv.der");
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 exp = ref_key.e().clone();
let key =
RsaPrivateKey::from_primes(primes, exp).expect("failed to import key from primes");
assert_eq!(key.validate(), Ok(()));
assert_eq!(key.n(), ref_key.n());
assert_eq!(key.dp(), ref_key.dp());
assert_eq!(key.dq(), ref_key.dq());
assert_eq!(key.d(), ref_key.d());
}
#[test]
fn build_key_from_p_q() {
const RSA_2048_SP800_PRIV_DER: &[u8] =
include_bytes!("../tests/examples/pkcs8/rsa2048-sp800-56b-priv.der");
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 key = RsaPrivateKey::from_p_q(primes[0].clone(), primes[1].clone(), exp)
.expect("failed to import key from primes");
assert_eq!(key.validate(), Ok(()));
assert_eq!(key.n(), ref_key.n());
assert_eq!(key.dp(), ref_key.dp());
assert_eq!(key.dq(), ref_key.dq());
assert_eq!(key.d(), ref_key.d());
}
#[test]
fn test_key_invalid_primes() {
let e = RsaPrivateKey::from_components(
BigUint::from_u64(239).unwrap(),
BigUint::from_u64(185).unwrap(),
BigUint::zero(),
vec![
BigUint::from_u64(1).unwrap(),
BigUint::from_u64(239).unwrap(),
],
)
.unwrap_err();
assert_eq!(e, Error::InvalidPrime);
}
}

255
vendor/rsa/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,255 @@
#![cfg_attr(not(test), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
#![warn(missing_docs)]
//! # Supported algorithms
//!
//! This crate supports several schemes described in [RFC8017]:
//!
//! - [OAEP encryption scheme](#oaep-encryption)
//! - [PKCS#1 v1.5 encryption scheme](#pkcs1-v15-encryption)
//! - [PKCS#1 v1.5 signature scheme](#pkcs1-v15-signatures)
//! - [PSS signature scheme](#pss-signatures)
//!
//! These schemes are described below.
//!
//! # Usage
//!
//! ## OAEP encryption
//!
//! Note: requires `sha2` feature of `rsa` crate is enabled.
//!
#![cfg_attr(feature = "sha2", doc = "```")]
#![cfg_attr(not(feature = "sha2"), doc = "```ignore")]
//! use rsa::{RsaPrivateKey, RsaPublicKey, Oaep, sha2::Sha256};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let public_key = RsaPublicKey::from(&private_key);
//!
//! // Encrypt
//! let data = b"hello world";
//! let padding = Oaep::new::<Sha256>();
//! let enc_data = public_key.encrypt(&mut rng, padding, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let padding = Oaep::new::<Sha256>();
//! let dec_data = private_key.decrypt(padding, &enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
//! ## PKCS#1 v1.5 encryption
//! ```
//! use rsa::{RsaPrivateKey, RsaPublicKey, Pkcs1v15Encrypt};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let public_key = RsaPublicKey::from(&private_key);
//!
//! // Encrypt
//! let data = b"hello world";
//! let enc_data = public_key.encrypt(&mut rng, Pkcs1v15Encrypt, &data[..]).expect("failed to encrypt");
//! assert_ne!(&data[..], &enc_data[..]);
//!
//! // Decrypt
//! let dec_data = private_key.decrypt(Pkcs1v15Encrypt, &enc_data).expect("failed to decrypt");
//! assert_eq!(&data[..], &dec_data[..]);
//! ```
//!
//! ## PKCS#1 v1.5 signatures
//!
//! Note: requires `sha2` feature of `rsa` crate is enabled.
//!
#![cfg_attr(feature = "sha2", doc = "```")]
#![cfg_attr(not(feature = "sha2"), doc = "```ignore")]
//! use rsa::RsaPrivateKey;
//! use rsa::pkcs1v15::{SigningKey, VerifyingKey};
//! use rsa::signature::{Keypair, RandomizedSigner, SignatureEncoding, Verifier};
//! use rsa::sha2::{Digest, Sha256};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let signing_key = SigningKey::<Sha256>::new(private_key);
//! let verifying_key = signing_key.verifying_key();
//!
//! // Sign
//! let data = b"hello world";
//! let signature = signing_key.sign_with_rng(&mut rng, data);
//! assert_ne!(signature.to_bytes().as_ref(), data.as_slice());
//!
//! // Verify
//! verifying_key.verify(data, &signature).expect("failed to verify");
//! ```
//!
//! ## PSS signatures
//!
//! Note: requires `sha2` feature of `rsa` crate is enabled.
//!
#![cfg_attr(feature = "sha2", doc = "```")]
#![cfg_attr(not(feature = "sha2"), doc = "```ignore")]
//! use rsa::RsaPrivateKey;
//! use rsa::pss::{BlindedSigningKey, VerifyingKey};
//! use rsa::signature::{Keypair,RandomizedSigner, SignatureEncoding, Verifier};
//! use rsa::sha2::{Digest, Sha256};
//!
//! let mut rng = rand::thread_rng(); // rand@0.8
//!
//! let bits = 2048;
//! let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
//! let signing_key = BlindedSigningKey::<Sha256>::new(private_key);
//! let verifying_key = signing_key.verifying_key();
//!
//! // Sign
//! let data = b"hello world";
//! let signature = signing_key.sign_with_rng(&mut rng, data);
//! assert_ne!(signature.to_bytes().as_ref(), data);
//!
//! // Verify
//! verifying_key.verify(data, &signature).expect("failed to verify");
//! ```
//!
//! ## PKCS#1 RSA Key Encoding
//!
//! PKCS#1 supports a legacy format for encoding RSA keys as binary (DER) or
//! text (PEM) data.
//!
//! You can recognize PEM encoded PKCS#1 keys because they have "RSA * KEY" in
//! the type label, e.g.:
//!
//! ```text
//! -----BEGIN RSA PRIVATE KEY-----
//! ```
//!
//! Most modern applications use the newer PKCS#8 format instead (see below).
//!
//! The following traits can be used to decode/encode [`RsaPrivateKey`] and
//! [`RsaPublicKey`] as PKCS#1. Note that [`pkcs1`] is re-exported from the
//! toplevel of the `rsa` crate:
//!
//! - [`pkcs1::DecodeRsaPrivateKey`]: decode RSA private keys from PKCS#1
//! - [`pkcs1::EncodeRsaPrivateKey`]: encode RSA private keys to PKCS#1
//! - [`pkcs1::DecodeRsaPublicKey`]: decode RSA public keys from PKCS#1
//! - [`pkcs1::EncodeRsaPublicKey`]: encode RSA public keys to PKCS#1
//!
//! ### Example
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[cfg(all(feature = "pem", feature = "std"))]
//! # {
//! use rsa::{RsaPublicKey, pkcs1::DecodeRsaPublicKey};
//!
//! let pem = "-----BEGIN RSA PUBLIC KEY-----
//! MIIBCgKCAQEAtsQsUV8QpqrygsY+2+JCQ6Fw8/omM71IM2N/R8pPbzbgOl0p78MZ
//! GsgPOQ2HSznjD0FPzsH8oO2B5Uftws04LHb2HJAYlz25+lN5cqfHAfa3fgmC38Ff
//! wBkn7l582UtPWZ/wcBOnyCgb3yLcvJrXyrt8QxHJgvWO23ITrUVYszImbXQ67YGS
//! 0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0NfFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J
//! 9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejIn04APPKIjpMyQdnWlby7rNyQtE4+CV+j
//! cFjqJbE/Xilcvqxt6DirjFCvYeKYl1uHLwIDAQAB
//! -----END RSA PUBLIC KEY-----";
//!
//! let public_key = RsaPublicKey::from_pkcs1_pem(pem)?;
//! # }
//! # Ok(())
//! # }
//! ```
//!
//! ## PKCS#8 RSA Key Encoding
//!
//! PKCS#8 is a private key format with support for multiple algorithms.
//! Like PKCS#1, it can be encoded as binary (DER) or text (PEM).
//!
//! You can recognize PEM encoded PKCS#8 keys because they *don't* have
//! an algorithm name in the type label, e.g.:
//!
//! ```text
//! -----BEGIN PRIVATE KEY-----
//! ```
//!
//! The following traits can be used to decode/encode [`RsaPrivateKey`] and
//! [`RsaPublicKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the
//! toplevel of the `rsa` crate:
//!
//! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8
//! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8
//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8
//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8
//!
//! ### Example
//!
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # #[cfg(all(feature = "pem", feature = "std"))]
//! # {
//! use rsa::{RsaPublicKey, pkcs8::DecodePublicKey};
//!
//! let pem = "-----BEGIN PUBLIC KEY-----
//! MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtsQsUV8QpqrygsY+2+JC
//! Q6Fw8/omM71IM2N/R8pPbzbgOl0p78MZGsgPOQ2HSznjD0FPzsH8oO2B5Uftws04
//! LHb2HJAYlz25+lN5cqfHAfa3fgmC38FfwBkn7l582UtPWZ/wcBOnyCgb3yLcvJrX
//! yrt8QxHJgvWO23ITrUVYszImbXQ67YGS0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0N
//! fFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejI
//! n04APPKIjpMyQdnWlby7rNyQtE4+CV+jcFjqJbE/Xilcvqxt6DirjFCvYeKYl1uH
//! LwIDAQAB
//! -----END PUBLIC KEY-----";
//!
//! let public_key = RsaPublicKey::from_public_key_pem(pem)?;
//! # }
//! # Ok(())
//! # }
//! ```
//!
//! [RFC8017]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
//!
// TODO(tarcieri): figure out why rustdoc isn't rendering these links correctly
//! [`pkcs8::DecodePublicKey`]: https://docs.rs/pkcs8/latest/pkcs8/trait.DecodePublicKey.html
//! [`pkcs8::EncodePublicKey`]: https://docs.rs/pkcs8/latest/pkcs8/trait.EncodePublicKey.html
#[cfg(doctest)]
pub struct ReadmeDoctests;
#[macro_use]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
pub use num_bigint::BigUint;
pub use rand_core;
pub use signature;
mod algorithms;
pub mod errors;
pub mod oaep;
pub mod pkcs1v15;
pub mod pss;
pub mod traits;
mod dummy_rng;
mod encoding;
mod key;
pub use pkcs1;
pub use pkcs8;
#[cfg(feature = "sha2")]
pub use sha2;
pub use crate::{
errors::{Error, Result},
key::{RsaPrivateKey, RsaPublicKey},
oaep::Oaep,
pkcs1v15::{Pkcs1v15Encrypt, Pkcs1v15Sign},
pss::Pss,
traits::keys::CrtValue,
};
#[cfg(feature = "hazmat")]
pub mod hazmat;

588
vendor/rsa/src/oaep.rs vendored Normal file
View File

@@ -0,0 +1,588 @@
//! Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#oaep-encryption).
mod decrypting_key;
mod encrypting_key;
pub use self::{decrypting_key::DecryptingKey, encrypting_key::EncryptingKey};
use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt;
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};
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::errors::{Error, Result};
use crate::key::{self, RsaPrivateKey, RsaPublicKey};
use crate::traits::{PaddingScheme, PublicKeyParts};
/// Encryption and Decryption using [OAEP padding](https://datatracker.ietf.org/doc/html/rfc8017#section-7.1).
///
/// - `digest` is used to hash the label. The maximum possible plaintext length is `m = k - 2 * h_len - 2`,
/// where `k` is the size of the RSA modulus.
/// - `mgf_digest` specifies the hash function that is used in the [MGF1](https://datatracker.ietf.org/doc/html/rfc8017#appendix-B.2).
/// - `label` is optional data that can be associated with the message.
///
/// The two hash functions can, but don't need to be the same.
///
/// A prominent example is the [`AndroidKeyStore`](https://developer.android.com/guide/topics/security/cryptography#oaep-mgf1-digest).
/// It uses SHA-1 for `mgf_digest` and a user-chosen SHA flavour for `digest`.
pub struct Oaep {
/// Digest type to use.
pub digest: Box<dyn DynDigest + Send + Sync>,
/// Digest to use for Mask Generation Function (MGF).
pub mgf_digest: Box<dyn DynDigest + Send + Sync>,
/// Optional label.
pub label: Option<String>,
}
impl Oaep {
/// Create a new OAEP `PaddingScheme`, using `T` as the hash function for both the default (empty) label and for MGF1.
///
/// # Example
/// ```
/// use sha1::Sha1;
/// use sha2::Sha256;
/// use rsa::{BigUint, RsaPublicKey, Oaep, };
/// use base64ct::{Base64, Encoding};
///
/// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
/// let e = Base64::decode_vec("AQAB").unwrap();
///
/// let mut rng = rand::thread_rng(); // rand@0.8
/// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap();
/// let padding = Oaep::new::<Sha256>();
/// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap();
/// ```
pub fn new<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(T::new()),
label: None,
}
}
/// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for both the label and for MGF1.
pub fn new_with_label<T: 'static + Digest + DynDigest + Send + Sync, S: AsRef<str>>(
label: S,
) -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(T::new()),
label: Some(label.as_ref().to_string()),
}
}
/// Create a new OAEP `PaddingScheme`, using `T` as the hash function for the default (empty) label, and `U` as the hash function for MGF1.
/// If a label is needed use `PaddingScheme::new_oaep_with_label` or `PaddingScheme::new_oaep_with_mgf_hash_with_label`.
///
/// # Example
/// ```
/// use sha1::Sha1;
/// use sha2::Sha256;
/// use rsa::{BigUint, RsaPublicKey, Oaep, };
/// use base64ct::{Base64, Encoding};
///
/// let n = Base64::decode_vec("ALHgDoZmBQIx+jTmgeeHW6KsPOrj11f6CvWsiRleJlQpW77AwSZhd21ZDmlTKfaIHBSUxRUsuYNh7E2SHx8rkFVCQA2/gXkZ5GK2IUbzSTio9qXA25MWHvVxjMfKSL8ZAxZyKbrG94FLLszFAFOaiLLY8ECs7g+dXOriYtBwLUJK+lppbd+El+8ZA/zH0bk7vbqph5pIoiWggxwdq3mEz4LnrUln7r6dagSQzYErKewY8GADVpXcq5mfHC1xF2DFBub7bFjMVM5fHq7RK+pG5xjNDiYITbhLYrbVv3X0z75OvN0dY49ITWjM7xyvMWJXVJS7sJlgmCCL6RwWgP8PhcE=").unwrap();
/// let e = Base64::decode_vec("AQAB").unwrap();
///
/// let mut rng = rand::thread_rng(); // rand@0.8
/// let key = RsaPublicKey::new(BigUint::from_bytes_be(&n), BigUint::from_bytes_be(&e)).unwrap();
/// let padding = Oaep::new_with_mgf_hash::<Sha256, Sha1>();
/// let encrypted_data = key.encrypt(&mut rng, padding, b"secret").unwrap();
/// ```
pub fn new_with_mgf_hash<
T: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
>() -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(U::new()),
label: None,
}
}
/// Create a new OAEP `PaddingScheme` with an associated `label`, using `T` as the hash function for the label, and `U` as the hash function for MGF1.
pub fn new_with_mgf_hash_and_label<
T: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
S: AsRef<str>,
>(
label: S,
) -> Self {
Self {
digest: Box::new(T::new()),
mgf_digest: Box::new(U::new()),
label: Some(label.as_ref().to_string()),
}
}
}
impl PaddingScheme for Oaep {
fn decrypt<Rng: CryptoRngCore>(
mut self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(
rng,
priv_key,
ciphertext,
&mut *self.digest,
&mut *self.mgf_digest,
self.label,
)
}
fn encrypt<Rng: CryptoRngCore>(
mut self,
rng: &mut Rng,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(
rng,
pub_key,
msg,
&mut *self.digest,
&mut *self.mgf_digest,
self.label,
)
}
}
impl fmt::Debug for Oaep {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("OAEP")
.field("digest", &"...")
.field("mgf_digest", &"...")
.field("label", &self.label)
.finish()
}
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
pub_key: &RsaPublicKey,
msg: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let em = oaep_encrypt(rng, msg, digest, mgf_digest, label, pub_key.size())?;
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
}
/// Encrypts the given message with RSA and the padding scheme from
/// [PKCS#1 OAEP].
///
/// The message must be no longer than the length of the public modulus minus
/// `2 + (2 * hash.size())`.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
fn encrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutputReset>(
rng: &mut R,
pub_key: &RsaPublicKey,
msg: &[u8],
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let em = oaep_encrypt_digest::<_, D, MGD>(rng, msg, label, pub_key.size())?;
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from [PKCS#1 OAEP].
///
/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn decrypt<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
digest: &mut dyn DynDigest,
mgf_digest: &mut dyn DynDigest,
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(priv_key)?;
if ciphertext.len() != priv_key.size() {
return Err(Error::Decryption);
}
let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?;
let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
oaep_decrypt(&mut em, digest, mgf_digest, label, priv_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from [PKCS#1 OAEP].
///
/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key.
///
/// See `decrypt_session_key` for a way of solving this problem.
///
/// [PKCS#1 OAEP]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[inline]
fn decrypt_digest<R: CryptoRngCore + ?Sized, D: Digest, MGD: Digest + FixedOutputReset>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
label: Option<String>,
) -> Result<Vec<u8>> {
key::check_public(priv_key)?;
if ciphertext.len() != priv_key.size() {
return Err(Error::Decryption);
}
let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?;
let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
oaep_decrypt_digest::<D, MGD>(&mut em, label, priv_key.size())
}
#[cfg(test)]
mod tests {
use crate::key::{RsaPrivateKey, RsaPublicKey};
use crate::oaep::{DecryptingKey, EncryptingKey, Oaep};
use crate::traits::PublicKeyParts;
use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};
use alloc::string::String;
use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use num_traits::FromPrimitive;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha8Rng,
};
use sha1::Sha1;
use sha2::{Sha224, Sha256, Sha384, Sha512};
use sha3::{Sha3_256, Sha3_384, Sha3_512};
fn get_private_key() -> RsaPrivateKey {
// -----BEGIN RSA PRIVATE KEY-----
// MIIEpAIBAAKCAQEA05e4TZikwmE47RtpWoEG6tkdVTvwYEG2LT/cUKBB4iK49FKW
// icG4LF5xVU9d1p+i9LYVjPDb61eBGg/DJ+HyjnT+dNO8Fmweq9wbi1e5NMqL5bAL
// TymXW8yZrK9BW1m7KKZ4K7QaLDwpdrPBjbre9i8AxrsiZkAJUJbAzGDSL+fvmH11
// xqgbENlr8pICivEQ3HzBu8Q9Iq2rN5oM1dgHjMeA/1zWIJ3qNMkiz3hPdxfkKNdb
// WuyP8w5fAUFRB2bi4KuNRzyE6HELK5gifD2wlTN600UvGeK5v7zN2BSKv2d2+lUn
// debnWVbkUimuWpxGlJurHmIvDkj1ZSSoTtNIOwIDAQABAoIBAQDE5wxokWLJTGYI
// KBkbUrTYOSEV30hqmtvoMeRY1zlYMg3Bt1VFbpNwHpcC12+wuS+Q4B0f4kgVMoH+
// eaqXY6kvrmnY1+zRRN4p+hNb0U+Vc+NJ5FAx47dpgvWDADgmxVLomjl8Gga9IWNI
// hjDZLowrtkPXq+9wDaldaFyUFImkb1S1MW9itdLDp/G70TTLNzU6RGg/3J2V02RY
// 3iL2xEBX/nSgpDbEMI9z9NpC81xHrBanE41IOvyR5B3DoRJzguDA9RGbAiG0/GOd
// a5w4F3pt6bUm69iMONeYLAf5ig79h31Qiq4nW5RpFcAuLhEG0XXXTsZ3f16A0SwF
// PZx74eNBAoGBAPgnu/OkGHfHzFmuv0LtSynDLe/LjtloY9WwkKBaiTDdYkohydz5
// g4Vo/foN9luEYqXyrJE9bFb5dVMr2OePsHvUBcqZpIS89Z8Bm73cs5M/K85wYwC0
// 97EQEgxd+QGBWQZ8NdowYaVshjWlK1QnOzEnG0MR8Hld9gIeY1XhpC5hAoGBANpI
// F84Aid028q3mo/9BDHPsNL8bT2vaOEMb/t4RzvH39u+nDl+AY6Ox9uFylv+xX+76
// CRKgMluNH9ZaVZ5xe1uWHsNFBy4OxSA9A0QdKa9NZAVKBFB0EM8dp457YRnZCexm
// 5q1iW/mVsnmks8W+fYlc18W5xMSX/ecwkW/NtOQbAoGAHabpz4AhKFbodSLrWbzv
// CUt4NroVFKdjnoodjfujfwJFF2SYMV5jN9LG3lVCxca43ulzc1tqka33Nfv8TBcg
// WHuKQZ5ASVgm5VwU1wgDMSoQOve07MWy/yZTccTc1zA0ihDXgn3bfR/NnaVh2wlh
// CkuI92eyW1494hztc7qlmqECgYEA1zenyOQ9ChDIW/ABGIahaZamNxsNRrDFMl3j
// AD+cxHSRU59qC32CQH8ShRy/huHzTaPX2DZ9EEln76fnrS4Ey7uLH0rrFl1XvT6K
// /timJgLvMEvXTx/xBtUdRN2fUqXtI9odbSyCtOYFL+zVl44HJq2UzY4pVRDrNcxs
// SUkQJqsCgYBSaNfPBzR5rrstLtTdZrjImRW1LRQeDEky9WsMDtCTYUGJTsTSfVO8
// hkU82MpbRVBFIYx+GWIJwcZRcC7OCQoV48vMJllxMAAjqG/p00rVJ+nvA7et/nNu
// BoB0er/UmDm4Ly/97EO9A0PKMOE5YbMq9s3t3RlWcsdrU7dvw+p2+A==
// -----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(),
vec![
BigUint::parse_bytes(b"00f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61",16).unwrap(),
BigUint::parse_bytes(b"00da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 16).unwrap()
],
).unwrap()
}
#[test]
fn test_encrypt_decrypt_oaep() {
let priv_key = get_private_key();
do_test_encrypt_decrypt_oaep::<Sha1>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha224>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha256>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha384>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha512>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha3_256>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha3_384>(&priv_key);
do_test_encrypt_decrypt_oaep::<Sha3_512>(&priv_key);
do_test_oaep_with_different_hashes::<Sha1, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha224, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha512, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha3_256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha3_384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes::<Sha3_512, Sha1>(&priv_key);
}
fn get_label(rng: &mut ChaCha8Rng) -> Option<String> {
const GEN_ASCII_STR_CHARSET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
abcdefghijklmnopqrstuvwxyz\
0123456789=+";
let mut buf = [0u8; 32];
rng.fill_bytes(&mut buf);
if buf[0] < (1 << 7) {
for v in buf.iter_mut() {
*v = GEN_ASCII_STR_CHARSET[(*v >> 2) as usize];
}
Some(core::str::from_utf8(&buf).unwrap().to_string())
} else {
None
}
}
fn do_test_encrypt_decrypt_oaep<D: 'static + Digest + DynDigest + Send + Sync>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = prk.size();
for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);
let pub_key: RsaPublicKey = prk.into();
let ciphertext = if let Some(ref label) = label {
let padding = Oaep::new_with_label::<D, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = Oaep::new::<D>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
};
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);
let padding = if let Some(ref label) = label {
Oaep::new_with_label::<D, _>(label)
} else {
Oaep::new::<D>()
};
let plaintext = if blind {
prk.decrypt(padding, &ciphertext).unwrap()
} else {
prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
};
assert_eq!(input, plaintext);
}
}
fn do_test_oaep_with_different_hashes<
D: 'static + Digest + DynDigest + Send + Sync,
U: 'static + Digest + DynDigest + Send + Sync,
>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = prk.size();
for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);
let pub_key: RsaPublicKey = prk.into();
let ciphertext = if let Some(ref label) = label {
let padding = Oaep::new_with_mgf_hash_and_label::<D, U, _>(label);
pub_key.encrypt(&mut rng, padding, &input).unwrap()
} else {
let padding = Oaep::new_with_mgf_hash::<D, U>();
pub_key.encrypt(&mut rng, padding, &input).unwrap()
};
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);
let padding = if let Some(ref label) = label {
Oaep::new_with_mgf_hash_and_label::<D, U, _>(label)
} else {
Oaep::new_with_mgf_hash::<D, U>()
};
let plaintext = if blind {
prk.decrypt(padding, &ciphertext).unwrap()
} else {
prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
};
assert_eq!(input, plaintext);
}
}
#[test]
fn test_decrypt_oaep_invalid_hash() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let pub_key: RsaPublicKey = (&priv_key).into();
let ciphertext = pub_key
.encrypt(&mut rng, Oaep::new::<Sha1>(), "a_plain_text".as_bytes())
.unwrap();
assert!(
priv_key
.decrypt_blinded(
&mut rng,
Oaep::new_with_label::<Sha1, _>("label"),
&ciphertext,
)
.is_err(),
"decrypt should have failed on hash verification"
);
}
#[test]
fn test_encrypt_decrypt_oaep_traits() {
let priv_key = get_private_key();
do_test_encrypt_decrypt_oaep_traits::<Sha1>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha224>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha256>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha384>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha512>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha3_256>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha3_384>(&priv_key);
do_test_encrypt_decrypt_oaep_traits::<Sha3_512>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha1, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha224, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha512, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha3_256, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha3_384, Sha1>(&priv_key);
do_test_oaep_with_different_hashes_traits::<Sha3_512, Sha1>(&priv_key);
}
fn do_test_encrypt_decrypt_oaep_traits<D: Digest + FixedOutputReset>(prk: &RsaPrivateKey) {
do_test_oaep_with_different_hashes_traits::<D, D>(prk);
}
fn do_test_oaep_with_different_hashes_traits<D: Digest, MGD: Digest + FixedOutputReset>(
prk: &RsaPrivateKey,
) {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let k = prk.size();
for i in 1..8 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let label = get_label(&mut rng);
let pub_key: RsaPublicKey = prk.into();
let ciphertext = if let Some(ref label) = label {
let encrypting_key =
EncryptingKey::<D, MGD>::new_with_label(pub_key, label.clone());
encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
} else {
let encrypting_key = EncryptingKey::<D, MGD>::new(pub_key);
encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
};
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1 << 31);
let decrypting_key = if let Some(ref label) = label {
DecryptingKey::<D, MGD>::new_with_label(prk.clone(), label.clone())
} else {
DecryptingKey::<D, MGD>::new(prk.clone())
};
let plaintext = if blind {
decrypting_key.decrypt(&ciphertext).unwrap()
} else {
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.unwrap()
};
assert_eq!(input, plaintext);
}
}
#[test]
fn test_decrypt_oaep_invalid_hash_traits() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let pub_key: RsaPublicKey = (&priv_key).into();
let encrypting_key = EncryptingKey::<Sha1>::new(pub_key);
let decrypting_key = DecryptingKey::<Sha1>::new_with_label(priv_key, "label");
let ciphertext = encrypting_key
.encrypt_with_rng(&mut rng, "a_plain_text".as_bytes())
.unwrap();
assert!(
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.is_err(),
"decrypt should have failed on hash verification"
);
}
}

96
vendor/rsa/src/oaep/decrypting_key.rs vendored Normal file
View File

@@ -0,0 +1,96 @@
use super::decrypt_digest;
use crate::{
dummy_rng::DummyRng,
traits::{Decryptor, RandomizedDecryptor},
Result, RsaPrivateKey,
};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use rand_core::CryptoRngCore;
use zeroize::ZeroizeOnDrop;
/// Decryption key for PKCS#1 v1.5 decryption as described in [RFC8017 § 7.1].
///
/// [RFC8017 § 7.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[derive(Debug, Clone)]
pub struct DecryptingKey<D, MGD = D>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
inner: RsaPrivateKey,
label: Option<String>,
phantom: PhantomData<D>,
mg_phantom: PhantomData<MGD>,
}
impl<D, MGD> DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPrivateKey) -> Self {
Self {
inner: key,
label: None,
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
/// Create a new verifying key from an RSA public key using provided label
pub fn new_with_label<S: AsRef<str>>(key: RsaPrivateKey, label: S) -> Self {
Self {
inner: key,
label: Some(label.as_ref().to_string()),
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
}
impl<D, MGD> Decryptor for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
decrypt_digest::<DummyRng, D, MGD>(
None,
&self.inner,
ciphertext,
self.label.as_ref().cloned(),
)
}
}
impl<D, MGD> RandomizedDecryptor for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn decrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt_digest::<_, D, MGD>(
Some(rng),
&self.inner,
ciphertext,
self.label.as_ref().cloned(),
)
}
}
impl<D, MGD> ZeroizeOnDrop for DecryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
}

64
vendor/rsa/src/oaep/encrypting_key.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
use super::encrypt_digest;
use crate::{traits::RandomizedEncryptor, Result, RsaPublicKey};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use rand_core::CryptoRngCore;
/// Encryption key for PKCS#1 v1.5 encryption as described in [RFC8017 § 7.1].
///
/// [RFC8017 § 7.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.1
#[derive(Debug, Clone)]
pub struct EncryptingKey<D, MGD = D>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
inner: RsaPublicKey,
label: Option<String>,
phantom: PhantomData<D>,
mg_phantom: PhantomData<MGD>,
}
impl<D, MGD> EncryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPublicKey) -> Self {
Self {
inner: key,
label: None,
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
/// Create a new verifying key from an RSA public key using provided label
pub fn new_with_label<S: AsRef<str>>(key: RsaPublicKey, label: S) -> Self {
Self {
inner: key,
label: Some(label.as_ref().to_string()),
phantom: Default::default(),
mg_phantom: Default::default(),
}
}
}
impl<D, MGD> RandomizedEncryptor for EncryptingKey<D, MGD>
where
D: Digest,
MGD: Digest + FixedOutputReset,
{
fn encrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt_digest::<_, D, MGD>(rng, &self.inner, msg, self.label.as_ref().cloned())
}
}

708
vendor/rsa/src/pkcs1v15.rs vendored Normal file
View File

@@ -0,0 +1,708 @@
//! PKCS#1 v1.5 support as described in [RFC8017 § 8.2].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pkcs1-v15-signatures).
//!
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
mod decrypting_key;
mod encrypting_key;
mod signature;
mod signing_key;
mod verifying_key;
pub use self::{
decrypting_key::DecryptingKey, encrypting_key::EncryptingKey, signature::Signature,
signing_key::SigningKey, verifying_key::VerifyingKey,
};
use alloc::{boxed::Box, vec::Vec};
use core::fmt::Debug;
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::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::errors::{Error, Result};
use crate::key::{self, RsaPrivateKey, RsaPublicKey};
use crate::traits::{PaddingScheme, PublicKeyParts, SignatureScheme};
/// Encryption using PKCS#1 v1.5 padding.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct Pkcs1v15Encrypt;
impl PaddingScheme for Pkcs1v15Encrypt {
fn decrypt<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(rng, priv_key, ciphertext)
}
fn encrypt<Rng: CryptoRngCore>(
self,
rng: &mut Rng,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(rng, pub_key, msg)
}
}
/// `RSASSA-PKCS1-v1_5`: digital signatures using PKCS#1 v1.5 padding.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pkcs1v15Sign {
/// Length of hash to use.
pub hash_len: Option<usize>,
/// Prefix.
pub prefix: Box<[u8]>,
}
impl Pkcs1v15Sign {
/// Create new PKCS#1 v1.5 padding for the given digest.
///
/// The digest must have an [`AssociatedOid`]. Make sure to enable the `oid`
/// feature of the relevant digest crate.
pub fn new<D>() -> Self
where
D: Digest + AssociatedOid,
{
Self {
hash_len: Some(<D as Digest>::output_size()),
prefix: pkcs1v15_generate_prefix::<D>().into_boxed_slice(),
}
}
/// Create new PKCS#1 v1.5 padding for computing an unprefixed signature.
///
/// This sets `hash_len` to `None` and uses an empty `prefix`.
pub fn new_unprefixed() -> Self {
Self {
hash_len: None,
prefix: Box::new([]),
}
}
/// Create new PKCS#1 v1.5 padding for computing an unprefixed signature.
///
/// This sets `hash_len` to `None` and uses an empty `prefix`.
#[deprecated(since = "0.9.0", note = "use Pkcs1v15Sign::new_unprefixed instead")]
pub fn new_raw() -> Self {
Self::new_unprefixed()
}
}
impl SignatureScheme for Pkcs1v15Sign {
fn sign<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
) -> Result<Vec<u8>> {
if let Some(hash_len) = self.hash_len {
if hashed.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
sign(rng, priv_key, &self.prefix, hashed)
}
fn verify(self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()> {
if let Some(hash_len) = self.hash_len {
if hashed.len() != hash_len {
return Err(Error::InputNotHashed);
}
}
verify(
pub_key,
self.prefix.as_ref(),
hashed,
&BigUint::from_bytes_be(sig),
sig.len(),
)
}
}
/// Encrypts the given message with RSA and the padding
/// scheme from PKCS#1 v1.5. The message must be no longer than the
/// length of the public modulus minus 11 bytes.
#[inline]
fn encrypt<R: CryptoRngCore + ?Sized>(
rng: &mut R,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>> {
key::check_public(pub_key)?;
let em = pkcs1v15_encrypt_pad(rng, msg, pub_key.size())?;
let int = Zeroizing::new(BigUint::from_bytes_be(&em));
uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
}
/// Decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.
///
/// If an `rng` is passed, it uses RSA blinding to avoid timing side-channel attacks.
///
/// Note that whether this function returns an error or not discloses secret
/// information. If an attacker can cause this function to run repeatedly and
/// learn whether each instance returned an error then they can decrypt and
/// forge signatures as if they had the private key. See
/// `decrypt_session_key` for a way of solving this problem.
#[inline]
fn decrypt<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
key::check_public(priv_key)?;
let em = rsa_decrypt_and_check(priv_key, rng, &BigUint::from_bytes_be(ciphertext))?;
let em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
pkcs1v15_encrypt_unpad(em, priv_key.size())
}
/// Calculates the signature of hashed using
/// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS#1 v1.5. Note that `hashed` must
/// be the result of hashing the input message using the given hash
/// function. If hash is `None`, hashed is signed directly. This isn't
/// advisable except for interoperability.
///
/// If `rng` is not `None` then RSA blinding will be used to avoid timing
/// side-channel attacks.
///
/// This function is deterministic. Thus, if the set of possible
/// messages is small, an attacker may be able to build a map from
/// messages to signatures and identify the signed messages. As ever,
/// signatures provide authenticity, not confidentiality.
#[inline]
fn sign<R: CryptoRngCore + ?Sized>(
rng: Option<&mut R>,
priv_key: &RsaPrivateKey,
prefix: &[u8],
hashed: &[u8],
) -> Result<Vec<u8>> {
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(),
)
}
/// 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() {
return Err(Error::Verification);
}
let em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
pkcs1v15_sign_unpad(prefix, hashed, &em, pub_key.size())
}
mod oid {
use const_oid::ObjectIdentifier;
/// A trait which associates an RSA-specific OID with a type.
pub trait RsaSignatureAssociatedOid {
/// The OID associated with this type.
const OID: ObjectIdentifier;
}
#[cfg(feature = "sha1")]
impl RsaSignatureAssociatedOid for sha1::Sha1 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.5");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha224 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.14");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha256 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.11");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha384 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.12");
}
#[cfg(feature = "sha2")]
impl RsaSignatureAssociatedOid for sha2::Sha512 {
const OID: ObjectIdentifier =
const_oid::ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.13");
}
}
pub use oid::RsaSignatureAssociatedOid;
#[cfg(test)]
mod tests {
use super::*;
use ::signature::{
hazmat::{PrehashSigner, PrehashVerifier},
DigestSigner, DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner,
SignatureEncoding, Signer, Verifier,
};
use base64ct::{Base64, Encoding};
use hex_literal::hex;
use num_bigint::BigUint;
use num_traits::FromPrimitive;
use num_traits::Num;
use rand_chacha::{
rand_core::{RngCore, SeedableRng},
ChaCha8Rng,
};
use sha1::{Digest, Sha1};
use sha2::Sha256;
use sha3::Sha3_256;
use crate::traits::{
Decryptor, EncryptingKeypair, PublicKeyParts, RandomizedDecryptor, RandomizedEncryptor,
};
use crate::{RsaPrivateKey, RsaPublicKey};
fn get_private_key() -> RsaPrivateKey {
// In order to generate new test vectors you'll need the PEM form of this key:
// -----BEGIN RSA PRIVATE KEY-----
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
// -----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(),
vec![
BigUint::from_str_radix("98920366548084643601728869055592650835572950932266967461790948584315647051443",10).unwrap(),
BigUint::from_str_radix("94560208308847015747498523884063394671606671904944666360068158221458669711639", 10).unwrap()
],
).unwrap()
}
#[test]
fn test_decrypt_pkcs1v15() {
let priv_key = get_private_key();
let tests = [[
"gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
"x",
], [
"Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
"testing.",
], [
"arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
"testing.\n",
], [
"WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
"01234567890123456789012345678901234567890123456789012",
]];
for test in &tests {
let out = priv_key
.decrypt(Pkcs1v15Encrypt, &Base64::decode_vec(test[0]).unwrap())
.unwrap();
assert_eq!(out, test[1].as_bytes());
}
}
#[test]
fn test_encrypt_decrypt_pkcs1v15() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let k = priv_key.size();
for i in 1..100 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let pub_key: RsaPublicKey = priv_key.clone().into();
let ciphertext = encrypt(&mut rng, &pub_key, &input).unwrap();
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1u32 << 31);
let blinder = if blind { Some(&mut rng) } else { None };
let plaintext = decrypt(blinder, &priv_key, &ciphertext).unwrap();
assert_eq!(input, plaintext);
}
}
#[test]
fn test_decrypt_pkcs1v15_traits() {
let priv_key = get_private_key();
let decrypting_key = DecryptingKey::new(priv_key);
let tests = [[
"gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
"x",
], [
"Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
"testing.",
], [
"arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
"testing.\n",
], [
"WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
"01234567890123456789012345678901234567890123456789012",
]];
for test in &tests {
let out = decrypting_key
.decrypt(&Base64::decode_vec(test[0]).unwrap())
.unwrap();
assert_eq!(out, test[1].as_bytes());
}
}
#[test]
fn test_encrypt_decrypt_pkcs1v15_traits() {
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = get_private_key();
let k = priv_key.size();
let decrypting_key = DecryptingKey::new(priv_key);
for i in 1..100 {
let mut input = vec![0u8; i * 8];
rng.fill_bytes(&mut input);
if input.len() > k - 11 {
input = input[0..k - 11].to_vec();
}
let encrypting_key = decrypting_key.encrypting_key();
let ciphertext = encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap();
assert_ne!(input, ciphertext);
let blind: bool = rng.next_u32() < (1u32 << 31);
let plaintext = if blind {
decrypting_key
.decrypt_with_rng(&mut rng, &ciphertext)
.unwrap()
} else {
decrypting_key.decrypt(&ciphertext).unwrap()
};
assert_eq!(input, plaintext);
}
}
#[test]
fn test_sign_pkcs1v15() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];
for (text, expected) in &tests {
let digest = Sha1::digest(text.as_bytes()).to_vec();
let out = priv_key.sign(Pkcs1v15Sign::new::<Sha1>(), &digest).unwrap();
assert_ne!(out, digest);
assert_eq!(out, expected);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let out2 = priv_key
.sign_with_rng(&mut rng, Pkcs1v15Sign::new::<Sha1>(), &digest)
.unwrap();
assert_eq!(out2, expected);
}
}
#[test]
fn test_sign_pkcs1v15_signer() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];
let signing_key = SigningKey::<Sha1>::new(priv_key);
for (text, expected) in &tests {
let out = signing_key.sign(text.as_bytes()).to_bytes();
assert_ne!(out.as_ref(), text.as_bytes());
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
assert_eq!(out.as_ref(), expected);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let out2 = signing_key
.sign_with_rng(&mut rng, text.as_bytes())
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_sign_pkcs1v15_signer_sha2_256() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"2ffae3f3e130287b3a1dcb320e46f52e8f3f7969b646932273a7e3a6f2a182ea"
"02d42875a7ffa4a148aa311f9e4b562e4e13a2223fb15f4e5bf5f2b206d9451b"
),
)];
let signing_key = SigningKey::<Sha256>::new(priv_key);
for (text, expected) in &tests {
let out = signing_key.sign(text.as_bytes()).to_bytes();
assert_ne!(out.as_ref(), text.as_bytes());
assert_eq!(out.as_ref(), expected);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let out2 = signing_key
.sign_with_rng(&mut rng, text.as_bytes())
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_sign_pkcs1v15_signer_sha3_256() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"55e9fba3354dfb51d2c8111794ea552c86afc2cab154652c03324df8c2c51ba7"
"2ff7c14de59a6f9ba50d90c13a7537cc3011948369f1f0ec4a49d21eb7e723f9"
),
)];
let signing_key = SigningKey::<Sha3_256>::new(priv_key);
for (text, expected) in &tests {
let out = signing_key.sign(text.as_bytes()).to_bytes();
assert_ne!(out.as_ref(), text.as_bytes());
assert_eq!(out.as_ref(), expected);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let out2 = signing_key
.sign_with_rng(&mut rng, text.as_bytes())
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_sign_pkcs1v15_digest_signer() {
let priv_key = get_private_key();
let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];
let signing_key = SigningKey::new(priv_key);
for (text, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let out = signing_key.sign_digest(digest).to_bytes();
assert_ne!(out.as_ref(), text.as_bytes());
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
assert_eq!(out.as_ref(), expected);
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let out2 = signing_key
.sign_digest_with_rng(&mut rng, digest)
.to_bytes();
assert_eq!(out2.as_ref(), expected);
}
}
#[test]
fn test_verify_pkcs1v15() {
let priv_key = get_private_key();
let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
for (text, sig, expected) in &tests {
let digest = Sha1::digest(text.as_bytes()).to_vec();
let result = pub_key.verify(Pkcs1v15Sign::new::<Sha1>(), &digest, sig);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pkcs1v15_signer() {
let priv_key = get_private_key();
let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
for (text, sig, expected) in &tests {
let result = verifying_key.verify(
text.as_bytes(),
&Signature::try_from(sig.as_slice()).unwrap(),
);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pkcs1v15_digest_signer() {
let priv_key = get_private_key();
let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::new(pub_key);
for (text, sig, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let result =
verifying_key.verify_digest(digest, &Signature::try_from(sig.as_slice()).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_unpadded_signature() {
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
let priv_key = get_private_key();
let sig = priv_key.sign(Pkcs1v15Sign::new_unprefixed(), msg).unwrap();
assert_eq!(expected_sig, sig);
let pub_key: RsaPublicKey = priv_key.into();
pub_key
.verify(Pkcs1v15Sign::new_unprefixed(), msg, &sig)
.expect("failed to verify");
}
#[test]
fn test_unpadded_signature_hazmat() {
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
let expected_sig = Base64::decode_vec("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==").unwrap();
let priv_key = get_private_key();
let signing_key = SigningKey::<Sha1>::new_unprefixed(priv_key);
let sig = signing_key
.sign_prehash(msg)
.expect("Failure during sign")
.to_bytes();
assert_eq!(sig.as_ref(), expected_sig);
let verifying_key = signing_key.verifying_key();
verifying_key
.verify_prehash(msg, &Signature::try_from(expected_sig.as_slice()).unwrap())
.expect("failed to verify");
}
}

View File

@@ -0,0 +1,51 @@
use super::{decrypt, EncryptingKey};
use crate::{
dummy_rng::DummyRng,
traits::{Decryptor, EncryptingKeypair, RandomizedDecryptor},
Result, RsaPrivateKey,
};
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
use zeroize::ZeroizeOnDrop;
/// Decryption key for PKCS#1 v1.5 decryption as described in [RFC8017 § 7.2].
///
/// [RFC8017 § 7.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.2
#[derive(Debug, Clone)]
pub struct DecryptingKey {
inner: RsaPrivateKey,
}
impl DecryptingKey {
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPrivateKey) -> Self {
Self { inner: key }
}
}
impl Decryptor for DecryptingKey {
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>> {
decrypt::<DummyRng>(None, &self.inner, ciphertext)
}
}
impl RandomizedDecryptor for DecryptingKey {
fn decrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>> {
decrypt(Some(rng), &self.inner, ciphertext)
}
}
impl EncryptingKeypair for DecryptingKey {
type EncryptingKey = EncryptingKey;
fn encrypting_key(&self) -> EncryptingKey {
EncryptingKey {
inner: self.inner.clone().into(),
}
}
}
impl ZeroizeOnDrop for DecryptingKey {}

View File

@@ -0,0 +1,29 @@
use super::encrypt;
use crate::{traits::RandomizedEncryptor, Result, RsaPublicKey};
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
/// Encryption key for PKCS#1 v1.5 encryption as described in [RFC8017 § 7.2].
///
/// [RFC8017 § 7.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-7.2
#[derive(Debug, Clone)]
pub struct EncryptingKey {
pub(super) inner: RsaPublicKey,
}
impl EncryptingKey {
/// Create a new verifying key from an RSA public key.
pub fn new(key: RsaPublicKey) -> Self {
Self { inner: key }
}
}
impl RandomizedEncryptor for EncryptingKey {
fn encrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>> {
encrypt(rng, &self.inner, msg)
}
}

80
vendor/rsa/src/pkcs1v15/signature.rs vendored Normal file
View File

@@ -0,0 +1,80 @@
pub use ::signature::SignatureEncoding;
use spki::{
der::{asn1::BitString, Result as DerResult},
SignatureBitStringEncoding,
};
use crate::algorithms::pad::uint_to_be_pad;
use alloc::{boxed::Box, string::ToString};
use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
use num_bigint::BigUint;
/// `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)]
pub struct Signature {
pub(super) inner: BigUint,
pub(super) len: usize,
}
impl SignatureEncoding for Signature {
type Repr = Box<[u8]>;
}
impl SignatureBitStringEncoding for Signature {
fn to_bitstring(&self) -> DerResult<BitString> {
BitString::new(0, self.to_vec())
}
}
impl TryFrom<&[u8]> for Signature {
type Error = signature::Error;
fn try_from(bytes: &[u8]) -> signature::Result<Self> {
Ok(Self {
inner: BigUint::from_bytes_be(bytes),
len: bytes.len(),
})
}
}
impl From<Signature> 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()
}
}
impl LowerHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
for byte in self.to_bytes().iter() {
write!(f, "{:02x}", byte)?;
}
Ok(())
}
}
impl UpperHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
for byte in self.to_bytes().iter() {
write!(f, "{:02X}", byte)?;
}
Ok(())
}
}
impl Display for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}", self)
}
}

255
vendor/rsa/src/pkcs1v15/signing_key.rs vendored Normal file
View File

@@ -0,0 +1,255 @@
use super::{oid, pkcs1v15_generate_prefix, sign, Signature, VerifyingKey};
use crate::{dummy_rng::DummyRng, Result, RsaPrivateKey};
use alloc::vec::Vec;
use core::marker::PhantomData;
use digest::Digest;
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
SignatureAlgorithmIdentifier,
},
AssociatedOid, EncodePrivateKey, SecretDocument,
};
use rand_core::CryptoRngCore;
use signature::{
hazmat::PrehashSigner, DigestSigner, Keypair, RandomizedDigestSigner, RandomizedSigner, Signer,
};
use zeroize::ZeroizeOnDrop;
/// Signing key for `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(Debug, Clone)]
pub struct SigningKey<D>
where
D: Digest,
{
inner: RsaPrivateKey,
prefix: Vec<u8>,
phantom: PhantomData<D>,
}
impl<D> SigningKey<D>
where
D: Digest + AssociatedOid,
{
/// Create a new signing key with a prefix for the digest `D`.
pub fn new(key: RsaPrivateKey) -> Self {
Self {
inner: key,
prefix: pkcs1v15_generate_prefix::<D>(),
phantom: Default::default(),
}
}
/// Generate a new signing key with a prefix for the digest `D`.
pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
prefix: pkcs1v15_generate_prefix::<D>(),
phantom: Default::default(),
})
}
/// Create a new signing key with a prefix for the digest `D`.
#[deprecated(since = "0.9.0", note = "use SigningKey::new instead")]
pub fn new_with_prefix(key: RsaPrivateKey) -> Self {
Self::new(key)
}
/// 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<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
) -> Result<Self> {
Self::random(rng, bit_size)
}
}
impl<D> SigningKey<D>
where
D: Digest,
{
/// Create a new signing key from the give RSA private key with an empty prefix.
///
/// ## Note: unprefixed signatures are uncommon
///
/// In most cases you'll want to use [`SigningKey::new`].
pub fn new_unprefixed(key: RsaPrivateKey) -> Self {
Self {
inner: key,
prefix: Vec::new(),
phantom: Default::default(),
}
}
/// Generate a new signing key with an empty prefix.
pub fn random_unprefixed<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
prefix: Vec::new(),
phantom: Default::default(),
})
}
}
//
// `*Signer` trait impls
//
impl<D> DigestSigner<D, Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_digest(&self, digest: D) -> signature::Result<Signature> {
sign::<DummyRng>(None, &self.inner, &self.prefix, &digest.finalize())?
.as_slice()
.try_into()
}
}
impl<D> PrehashSigner<Signature> for SigningKey<D>
where
D: Digest,
{
fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
sign::<DummyRng>(None, &self.inner, &self.prefix, prehash)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_digest_with_rng(
&self,
rng: &mut impl CryptoRngCore,
digest: D,
) -> signature::Result<Signature> {
sign(Some(rng), &self.inner, &self.prefix, &digest.finalize())?
.as_slice()
.try_into()
}
}
impl<D> RandomizedSigner<Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_with_rng(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> signature::Result<Signature> {
sign(Some(rng), &self.inner, &self.prefix, &D::digest(msg))?
.as_slice()
.try_into()
}
}
impl<D> Signer<Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
sign::<DummyRng>(None, &self.inner, &self.prefix, &D::digest(msg))?
.as_slice()
.try_into()
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPrivateKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
impl<D> EncodePrivateKey for SigningKey<D>
where
D: Digest,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
self.inner.to_pkcs8_der()
}
}
impl<D> From<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn from(key: RsaPrivateKey) -> Self {
Self::new_unprefixed(key)
}
}
impl<D> From<SigningKey<D>> for RsaPrivateKey
where
D: Digest,
{
fn from(key: SigningKey<D>) -> Self {
key.inner
}
}
impl<D> Keypair for SigningKey<D>
where
D: Digest,
{
type VerifyingKey = VerifyingKey<D>;
fn verifying_key(&self) -> Self::VerifyingKey {
VerifyingKey {
inner: self.inner.to_public_key(),
prefix: self.prefix.clone(),
phantom: Default::default(),
}
}
}
impl<D> SignatureAlgorithmIdentifier for SigningKey<D>
where
D: Digest + oid::RsaSignatureAssociatedOid,
{
type Params = AnyRef<'static>;
const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
AlgorithmIdentifierRef {
oid: D::OID,
parameters: Some(AnyRef::NULL),
};
}
impl<D> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<D>
where
D: Digest + AssociatedOid,
{
type Error = pkcs8::Error;
fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
RsaPrivateKey::try_from(private_key_info).map(Self::new)
}
}
impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}

203
vendor/rsa/src/pkcs1v15/verifying_key.rs vendored Normal file
View File

@@ -0,0 +1,203 @@
use super::{oid, pkcs1v15_generate_prefix, verify, Signature};
use crate::RsaPublicKey;
use alloc::vec::Vec;
use core::marker::PhantomData;
use digest::Digest;
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
SignatureAlgorithmIdentifier,
},
AssociatedOid, Document, EncodePublicKey,
};
use signature::{hazmat::PrehashVerifier, DigestVerifier, Verifier};
/// Verifying key for `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(Debug)]
pub struct VerifyingKey<D>
where
D: Digest,
{
pub(super) inner: RsaPublicKey,
pub(super) prefix: Vec<u8>,
pub(super) phantom: PhantomData<D>,
}
impl<D> VerifyingKey<D>
where
D: Digest + AssociatedOid,
{
/// Create a new verifying key with a prefix for the digest `D`.
pub fn new(key: RsaPublicKey) -> Self {
Self {
inner: key,
prefix: pkcs1v15_generate_prefix::<D>(),
phantom: Default::default(),
}
}
/// Create a new verifying key with a prefix for the digest `D`.
#[deprecated(since = "0.9.0", note = "use VerifyingKey::new instead")]
pub fn new_with_prefix(key: RsaPublicKey) -> Self {
Self::new(key)
}
}
impl<D> VerifyingKey<D>
where
D: Digest,
{
/// Create a new verifying key from an RSA public key with an empty prefix.
///
/// ## Note: unprefixed signatures are uncommon
///
/// In most cases you'll want to use [`VerifyingKey::new`] instead.
pub fn new_unprefixed(key: RsaPublicKey) -> Self {
Self {
inner: key,
prefix: Vec::new(),
phantom: Default::default(),
}
}
}
//
// `*Verifier` trait impls
//
impl<D> DigestVerifier<D, Signature> for VerifyingKey<D>
where
D: Digest,
{
fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> {
verify(
&self.inner,
&self.prefix,
&digest.finalize(),
&signature.inner,
signature.len,
)
.map_err(|e| e.into())
}
}
impl<D> PrehashVerifier<Signature> for VerifyingKey<D>
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())
}
}
impl<D> Verifier<Signature> for VerifyingKey<D>
where
D: Digest,
{
fn verify(&self, msg: &[u8], signature: &Signature) -> signature::Result<()> {
verify(
&self.inner,
&self.prefix.clone(),
&D::digest(msg),
&signature.inner,
signature.len,
)
.map_err(|e| e.into())
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPublicKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for VerifyingKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
// Implemented manually so we don't have to bind D with Clone
impl<D> Clone for VerifyingKey<D>
where
D: Digest,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
prefix: self.prefix.clone(),
phantom: Default::default(),
}
}
}
impl<D> EncodePublicKey for VerifyingKey<D>
where
D: Digest,
{
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
self.inner.to_public_key_der()
}
}
impl<D> From<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn from(key: RsaPublicKey) -> Self {
Self::new_unprefixed(key)
}
}
impl<D> From<VerifyingKey<D>> for RsaPublicKey
where
D: Digest,
{
fn from(key: VerifyingKey<D>) -> Self {
key.inner
}
}
impl<D> SignatureAlgorithmIdentifier for VerifyingKey<D>
where
D: Digest + oid::RsaSignatureAssociatedOid,
{
type Params = AnyRef<'static>;
const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> =
AlgorithmIdentifierRef {
oid: D::OID,
parameters: Some(AnyRef::NULL),
};
}
impl<D> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for VerifyingKey<D>
where
D: Digest + AssociatedOid,
{
type Error = pkcs8::spki::Error;
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
RsaPublicKey::try_from(spki).map(Self::new)
}
}

613
vendor/rsa/src/pss.rs vendored Normal file
View File

@@ -0,0 +1,613 @@
//! Support for the [Probabilistic Signature Scheme] (PSS) a.k.a. RSASSA-PSS.
//!
//! Designed by Mihir Bellare and Phillip Rogaway. Specified in [RFC8017 § 8.1].
//!
//! # Usage
//!
//! See [code example in the toplevel rustdoc](../index.html#pss-signatures).
//!
//! [Probabilistic Signature Scheme]: https://en.wikipedia.org/wiki/Probabilistic_signature_scheme
//! [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
mod blinded_signing_key;
mod signature;
mod signing_key;
mod verifying_key;
pub use self::{
blinded_signing_key::BlindedSigningKey, signature::Signature, signing_key::SigningKey,
verifying_key::VerifyingKey,
};
use alloc::{boxed::Box, vec::Vec};
use core::fmt::{self, Debug};
use const_oid::{AssociatedOid, ObjectIdentifier};
use digest::{Digest, DynDigest, FixedOutputReset};
use num_bigint::BigUint;
use pkcs1::RsaPssParams;
use pkcs8::spki::{der::Any, AlgorithmIdentifierOwned};
use rand_core::CryptoRngCore;
use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
use crate::algorithms::pss::*;
use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
use crate::errors::{Error, Result};
use crate::traits::PublicKeyParts;
use crate::traits::SignatureScheme;
use crate::{RsaPrivateKey, RsaPublicKey};
/// Digital signatures using PSS padding.
pub struct Pss {
/// Create blinded signatures.
pub blinded: bool,
/// Digest type to use.
pub digest: Box<dyn DynDigest + Send + Sync>,
/// Salt length.
pub salt_len: usize,
}
impl Pss {
/// New PSS padding for the given digest.
/// Digest output size is used as a salt length.
pub fn new<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
Self::new_with_salt::<T>(<T as Digest>::output_size())
}
/// New PSS padding for the given digest with a salt value of the given length.
pub fn new_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(len: usize) -> Self {
Self {
blinded: false,
digest: Box::new(T::new()),
salt_len: len,
}
}
/// New PSS padding for blinded signatures (RSA-BSSA) for the given digest.
/// Digest output size is used as a salt length.
pub fn new_blinded<T: 'static + Digest + DynDigest + Send + Sync>() -> Self {
Self::new_blinded_with_salt::<T>(<T as Digest>::output_size())
}
/// New PSS padding for blinded signatures (RSA-BSSA) for the given digest
/// with a salt value of the given length.
pub fn new_blinded_with_salt<T: 'static + Digest + DynDigest + Send + Sync>(
len: usize,
) -> Self {
Self {
blinded: true,
digest: Box::new(T::new()),
salt_len: len,
}
}
}
impl SignatureScheme for Pss {
fn sign<Rng: CryptoRngCore>(
mut self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
) -> Result<Vec<u8>> {
sign(
rng.ok_or(Error::InvalidPaddingScheme)?,
self.blinded,
priv_key,
hashed,
self.salt_len,
&mut *self.digest,
)
}
fn verify(mut self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()> {
verify(
pub_key,
hashed,
&BigUint::from_bytes_be(sig),
sig.len(),
&mut *self.digest,
self.salt_len,
)
}
}
impl Debug for Pss {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PSS")
.field("blinded", &self.blinded)
.field("digest", &"...")
.field("salt_len", &self.salt_len)
.finish()
}
}
pub(crate) fn verify(
pub_key: &RsaPublicKey,
hashed: &[u8],
sig: &BigUint,
sig_len: usize,
digest: &mut dyn DynDigest,
salt_len: usize,
) -> Result<()> {
if sig_len != pub_key.size() {
return Err(Error::Verification);
}
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())
}
pub(crate) fn verify_digest<D>(
pub_key: &RsaPublicKey,
hashed: &[u8],
sig: &BigUint,
sig_len: usize,
salt_len: usize,
) -> Result<()>
where
D: Digest + FixedOutputReset,
{
if sig >= pub_key.n() || sig_len != pub_key.size() {
return Err(Error::Verification);
}
let mut em = uint_to_be_pad(rsa_encrypt(pub_key, sig)?, pub_key.size())?;
emsa_pss_verify_digest::<D>(hashed, &mut em, salt_len, pub_key.n().bits())
}
/// SignPSS calculates the signature of hashed using RSASSA-PSS.
///
/// Note that hashed must be the result of hashing the input message using the
/// given hash function. The opts argument may be nil, in which case sensible
/// defaults are used.
pub(crate) fn sign<T: CryptoRngCore>(
rng: &mut T,
blind: bool,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt_len: usize,
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let mut salt = vec![0; salt_len];
rng.fill_bytes(&mut salt[..]);
sign_pss_with_salt(blind.then_some(rng), priv_key, hashed, &salt, digest)
}
pub(crate) fn sign_digest<T: CryptoRngCore + ?Sized, D: Digest + FixedOutputReset>(
rng: &mut T,
blind: bool,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt_len: usize,
) -> Result<Vec<u8>> {
let mut salt = vec![0; salt_len];
rng.fill_bytes(&mut salt[..]);
sign_pss_with_salt_digest::<_, D>(blind.then_some(rng), priv_key, hashed, &salt)
}
/// signPSSWithSalt calculates the signature of hashed using PSS with specified salt.
///
/// Note that hashed must be the result of hashing the input message using the
/// given hash function. salt is a random sequence of bytes whose length will be
/// later used to verify the signature.
fn sign_pss_with_salt<T: CryptoRngCore>(
blind_rng: Option<&mut T>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt: &[u8],
digest: &mut dyn DynDigest,
) -> Result<Vec<u8>> {
let em_bits = priv_key.n().bits() - 1;
let em = emsa_pss_encode(hashed, em_bits, salt, digest)?;
uint_to_zeroizing_be_pad(
rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?,
priv_key.size(),
)
}
fn sign_pss_with_salt_digest<T: CryptoRngCore + ?Sized, D: Digest + FixedOutputReset>(
blind_rng: Option<&mut T>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
salt: &[u8],
) -> Result<Vec<u8>> {
let em_bits = priv_key.n().bits() - 1;
let em = emsa_pss_encode_digest::<D>(hashed, em_bits, salt)?;
uint_to_zeroizing_be_pad(
rsa_decrypt_and_check(priv_key, blind_rng, &BigUint::from_bytes_be(&em))?,
priv_key.size(),
)
}
/// Returns the [`AlgorithmIdentifierOwned`] associated with PSS signature using a given digest.
pub fn get_default_pss_signature_algo_id<D>() -> pkcs8::spki::Result<AlgorithmIdentifierOwned>
where
D: Digest + AssociatedOid,
{
let salt_len: u8 = <D as Digest>::output_size() as u8;
get_pss_signature_algo_id::<D>(salt_len)
}
fn get_pss_signature_algo_id<D>(salt_len: u8) -> pkcs8::spki::Result<AlgorithmIdentifierOwned>
where
D: Digest + AssociatedOid,
{
const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");
let pss_params = RsaPssParams::new::<D>(salt_len);
Ok(AlgorithmIdentifierOwned {
oid: ID_RSASSA_PSS,
parameters: Some(Any::encode_from(&pss_params)?),
})
}
#[cfg(test)]
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 rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
use sha1::{Digest, Sha1};
use signature::hazmat::{PrehashVerifier, RandomizedPrehashSigner};
use signature::{DigestVerifier, Keypair, RandomizedDigestSigner, RandomizedSigner, Verifier};
fn get_private_key() -> RsaPrivateKey {
// In order to generate new test vectors you'll need the PEM form of this key:
// -----BEGIN RSA PRIVATE KEY-----
// MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
// fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
// /ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
// RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
// EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
// IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
// tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
// -----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(),
vec![
BigUint::from_str_radix("98920366548084643601728869055592650835572950932266967461790948584315647051443",10).unwrap(),
BigUint::from_str_radix("94560208308847015747498523884063394671606671904944666360068158221458669711639", 10).unwrap()
],
).unwrap()
}
#[test]
fn test_verify_pss() {
let priv_key = get_private_key();
let tests = [
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
for (text, sig, expected) in &tests {
let digest = Sha1::digest(text.as_bytes()).to_vec();
let result = pub_key.verify(Pss::new::<Sha1>(), &digest, sig);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pss_signer() {
let priv_key = get_private_key();
let tests = [
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key: VerifyingKey<Sha1> = VerifyingKey::new(pub_key);
for (text, sig, expected) in &tests {
let result = verifying_key.verify(
text.as_bytes(),
&Signature::try_from(sig.as_slice()).unwrap(),
);
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_verify_pss_digest_signer() {
let priv_key = get_private_key();
let tests = [
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
"test\n",
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::new(pub_key);
for (text, sig, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let result =
verifying_key.verify_digest(digest, &Signature::try_from(sig.as_slice()).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_sign_and_verify_roundtrip() {
let priv_key = get_private_key();
let tests = ["test\n"];
let rng = ChaCha8Rng::from_seed([42; 32]);
for test in &tests {
let digest = Sha1::digest(test.as_bytes()).to_vec();
let sig = priv_key
.sign_with_rng(&mut rng.clone(), Pss::new::<Sha1>(), &digest)
.expect("failed to sign");
priv_key
.to_public_key()
.verify(Pss::new::<Sha1>(), &digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_blinded_and_verify_roundtrip() {
let priv_key = get_private_key();
let tests = ["test\n"];
let rng = ChaCha8Rng::from_seed([42; 32]);
for test in &tests {
let digest = Sha1::digest(test.as_bytes()).to_vec();
let sig = priv_key
.sign_with_rng(&mut rng.clone(), Pss::new_blinded::<Sha1>(), &digest)
.expect("failed to sign");
priv_key
.to_public_key()
.verify(Pss::new::<Sha1>(), &digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = SigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
verifying_key
.verify(test.as_bytes(), &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_blinded_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key.sign_with_rng(&mut rng, test.as_bytes());
verifying_key
.verify(test.as_bytes(), &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_digest_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = SigningKey::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let mut digest = Sha1::new();
digest.update(test.as_bytes());
let sig = signing_key.sign_digest_with_rng(&mut rng, digest);
let mut digest = Sha1::new();
digest.update(test.as_bytes());
verifying_key
.verify_digest(digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_roundtrip_blinded_digest_signer() {
let priv_key = get_private_key();
let tests = ["test\n"];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let mut digest = Sha1::new();
digest.update(test.as_bytes());
let sig = signing_key.sign_digest_with_rng(&mut rng, digest);
let mut digest = Sha1::new();
digest.update(test.as_bytes());
verifying_key
.verify_digest(digest, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_verify_pss_hazmat() {
let priv_key = get_private_key();
let tests = [
(
Sha1::digest("test\n"),
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962f"
),
true,
),
(
Sha1::digest("test\n"),
hex!(
"6f86f26b14372b2279f79fb6807c49889835c204f71e38249b4c5601462da8ae"
"30f26ffdd9c13f1c75eee172bebe7b7c89f2f1526c722833b9737d6c172a962e"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::<Sha1>::new(pub_key);
for (text, sig, expected) in &tests {
let result = verifying_key
.verify_prehash(text.as_ref(), &Signature::try_from(sig.as_slice()).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
}
}
}
}
#[test]
fn test_sign_and_verify_pss_hazmat() {
let priv_key = get_private_key();
let tests = [Sha1::digest("test\n")];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = SigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key
.sign_prehash_with_rng(&mut rng, &test)
.expect("failed to sign");
verifying_key
.verify_prehash(&test, &sig)
.expect("failed to verify");
}
}
#[test]
fn test_sign_and_verify_pss_blinded_hazmat() {
let priv_key = get_private_key();
let tests = [Sha1::digest("test\n")];
let mut rng = ChaCha8Rng::from_seed([42; 32]);
let signing_key = BlindedSigningKey::<Sha1>::new(priv_key);
let verifying_key = signing_key.verifying_key();
for test in &tests {
let sig = signing_key
.sign_prehash_with_rng(&mut rng, &test)
.expect("failed to sign");
verifying_key
.verify_prehash(&test, &sig)
.expect("failed to verify");
}
}
#[test]
// Tests the corner case where the key is multiple of 8 + 1 bits long
fn test_sign_and_verify_2049bit_key() {
let plaintext = "Hello\n";
let rng = ChaCha8Rng::from_seed([42; 32]);
let priv_key = RsaPrivateKey::new(&mut rng.clone(), 2049).unwrap();
let digest = Sha1::digest(plaintext.as_bytes()).to_vec();
let sig = priv_key
.sign_with_rng(&mut rng.clone(), Pss::new::<Sha1>(), &digest)
.expect("failed to sign");
priv_key
.to_public_key()
.verify(Pss::new::<Sha1>(), &digest, &sig)
.expect("failed to verify");
}
}

View File

@@ -0,0 +1,200 @@
use super::{get_pss_signature_algo_id, sign_digest, Signature, VerifyingKey};
use crate::{Result, RsaPrivateKey};
use const_oid::AssociatedOid;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierOwned, AlgorithmIdentifierRef,
AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier,
},
EncodePrivateKey, SecretDocument,
};
use rand_core::CryptoRngCore;
use signature::{
hazmat::RandomizedPrehashSigner, Keypair, RandomizedDigestSigner, RandomizedSigner,
};
use zeroize::ZeroizeOnDrop;
/// Signing key for producing "blinded" RSASSA-PSS signatures as described in
/// [draft-irtf-cfrg-rsa-blind-signatures](https://datatracker.ietf.org/doc/draft-irtf-cfrg-rsa-blind-signatures/).
#[derive(Debug, Clone)]
pub struct BlindedSigningKey<D>
where
D: Digest,
{
inner: RsaPrivateKey,
salt_len: usize,
phantom: PhantomData<D>,
}
impl<D> BlindedSigningKey<D>
where
D: Digest,
{
/// Create a new RSASSA-PSS signing key which produces "blinded"
/// signatures.
/// Digest output size is used as a salt length.
pub fn new(key: RsaPrivateKey) -> Self {
Self::new_with_salt_len(key, <D as Digest>::output_size())
}
/// Create a new RSASSA-PSS signing key which produces "blinded"
/// signatures with a salt of the given length.
pub fn new_with_salt_len(key: RsaPrivateKey, salt_len: usize) -> Self {
Self {
inner: key,
salt_len,
phantom: Default::default(),
}
}
/// Create a new random RSASSA-PSS signing key which produces "blinded"
/// signatures.
/// Digest output size is used as a salt length.
pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
Self::random_with_salt_len(rng, bit_size, <D as Digest>::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<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
salt_len: usize,
) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
salt_len,
phantom: Default::default(),
})
}
/// Return specified salt length for this key
pub fn salt_len(&self) -> usize {
self.salt_len
}
}
//
// `*Signer` trait impls
//
impl<D> RandomizedSigner<Signature> for BlindedSigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_with_rng(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, true, &self.inner, &D::digest(msg), self.salt_len)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedDigestSigner<D, Signature> for BlindedSigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_digest_with_rng(
&self,
rng: &mut impl CryptoRngCore,
digest: D,
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, true, &self.inner, &digest.finalize(), self.salt_len)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedPrehashSigner<Signature> for BlindedSigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn sign_prehash_with_rng(
&self,
rng: &mut impl CryptoRngCore,
prehash: &[u8],
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, true, &self.inner, prehash, self.salt_len)?
.as_slice()
.try_into()
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPrivateKey> for BlindedSigningKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPrivateKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for BlindedSigningKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
impl<D> DynSignatureAlgorithmIdentifier for BlindedSigningKey<D>
where
D: Digest + AssociatedOid,
{
fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result<AlgorithmIdentifierOwned> {
get_pss_signature_algo_id::<D>(self.salt_len as u8)
}
}
impl<D> EncodePrivateKey for BlindedSigningKey<D>
where
D: Digest,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
self.inner.to_pkcs8_der()
}
}
impl<D> From<RsaPrivateKey> for BlindedSigningKey<D>
where
D: Digest,
{
fn from(key: RsaPrivateKey) -> Self {
Self::new(key)
}
}
impl<D> From<BlindedSigningKey<D>> for RsaPrivateKey
where
D: Digest,
{
fn from(key: BlindedSigningKey<D>) -> Self {
key.inner
}
}
impl<D> Keypair for BlindedSigningKey<D>
where
D: Digest,
{
type VerifyingKey = VerifyingKey<D>;
fn verifying_key(&self) -> Self::VerifyingKey {
VerifyingKey {
inner: self.inner.to_public_key(),
salt_len: self.salt_len,
phantom: Default::default(),
}
}
}
impl<D> ZeroizeOnDrop for BlindedSigningKey<D> where D: Digest {}

74
vendor/rsa/src/pss/signature.rs vendored Normal file
View File

@@ -0,0 +1,74 @@
pub use ::signature::SignatureEncoding;
use spki::{
der::{asn1::BitString, Result as DerResult},
SignatureBitStringEncoding,
};
use crate::algorithms::pad::uint_to_be_pad;
use alloc::{boxed::Box, string::ToString};
use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
use num_bigint::BigUint;
/// 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)]
pub struct Signature {
pub(super) inner: BigUint,
pub(super) len: usize,
}
impl SignatureEncoding for Signature {
type Repr = Box<[u8]>;
}
impl SignatureBitStringEncoding for Signature {
fn to_bitstring(&self) -> DerResult<BitString> {
BitString::new(0, self.to_vec())
}
}
impl TryFrom<&[u8]> for Signature {
type Error = signature::Error;
fn try_from(bytes: &[u8]) -> signature::Result<Self> {
Ok(Self {
len: bytes.len(),
inner: BigUint::from_bytes_be(bytes),
})
}
}
impl From<Signature> 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()
}
}
impl LowerHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:x}", &self.inner)
}
}
impl UpperHex for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}", &self.inner)
}
}
impl Display for Signature {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "{:X}", self)
}
}

222
vendor/rsa/src/pss/signing_key.rs vendored Normal file
View File

@@ -0,0 +1,222 @@
use super::{get_pss_signature_algo_id, sign_digest, Signature, VerifyingKey};
use crate::{Result, RsaPrivateKey};
use const_oid::AssociatedOid;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{
der::AnyRef, AlgorithmIdentifierOwned, AlgorithmIdentifierRef,
AssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier,
},
EncodePrivateKey, SecretDocument,
};
use rand_core::CryptoRngCore;
use signature::{
hazmat::RandomizedPrehashSigner, Keypair, RandomizedDigestSigner, RandomizedSigner,
};
use zeroize::ZeroizeOnDrop;
#[cfg(feature = "getrandom")]
use {
rand_core::OsRng,
signature::{hazmat::PrehashSigner, Signer},
};
/// Signing key for producing RSASSA-PSS signatures as described in
/// [RFC8017 § 8.1].
///
/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
#[derive(Debug, Clone)]
pub struct SigningKey<D>
where
D: Digest,
{
inner: RsaPrivateKey,
salt_len: usize,
phantom: PhantomData<D>,
}
impl<D> SigningKey<D>
where
D: Digest,
{
/// Create a new RSASSA-PSS signing key.
/// Digest output size is used as a salt length.
pub fn new(key: RsaPrivateKey) -> Self {
Self::new_with_salt_len(key, <D as Digest>::output_size())
}
/// Create a new RSASSA-PSS signing key with a salt of the given length.
pub fn new_with_salt_len(key: RsaPrivateKey, salt_len: usize) -> Self {
Self {
inner: key,
salt_len,
phantom: Default::default(),
}
}
/// Generate a new random RSASSA-PSS signing key.
/// Digest output size is used as a salt length.
pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
Self::random_with_salt_len(rng, bit_size, <D as Digest>::output_size())
}
/// Generate a new random RSASSA-PSS signing key with a salt of the given length.
pub fn random_with_salt_len<R: CryptoRngCore + ?Sized>(
rng: &mut R,
bit_size: usize,
salt_len: usize,
) -> Result<Self> {
Ok(Self {
inner: RsaPrivateKey::new(rng, bit_size)?,
salt_len,
phantom: Default::default(),
})
}
/// Return specified salt length for this key
pub fn salt_len(&self) -> usize {
self.salt_len
}
}
//
// `*Signer` trait impls
//
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_digest_with_rng(
&self,
rng: &mut impl CryptoRngCore,
digest: D,
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, false, &self.inner, &digest.finalize(), self.salt_len)?
.as_slice()
.try_into()
}
}
impl<D> RandomizedSigner<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign_with_rng(
&self,
rng: &mut impl CryptoRngCore,
msg: &[u8],
) -> signature::Result<Signature> {
self.try_sign_digest_with_rng(rng, D::new_with_prefix(msg))
}
}
impl<D> RandomizedPrehashSigner<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn sign_prehash_with_rng(
&self,
rng: &mut impl CryptoRngCore,
prehash: &[u8],
) -> signature::Result<Signature> {
sign_digest::<_, D>(rng, false, &self.inner, prehash, self.salt_len)?
.as_slice()
.try_into()
}
}
#[cfg(feature = "getrandom")]
impl<D> PrehashSigner<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn sign_prehash(&self, prehash: &[u8]) -> signature::Result<Signature> {
self.sign_prehash_with_rng(&mut OsRng, prehash)
}
}
#[cfg(feature = "getrandom")]
impl<D> Signer<Signature> for SigningKey<D>
where
D: Digest + FixedOutputReset,
{
fn try_sign(&self, msg: &[u8]) -> signature::Result<Signature> {
self.try_sign_with_rng(&mut OsRng, msg)
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPrivateKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
impl<D> DynSignatureAlgorithmIdentifier for SigningKey<D>
where
D: Digest + AssociatedOid,
{
fn signature_algorithm_identifier(&self) -> pkcs8::spki::Result<AlgorithmIdentifierOwned> {
get_pss_signature_algo_id::<D>(self.salt_len as u8)
}
}
impl<D> EncodePrivateKey for SigningKey<D>
where
D: Digest,
{
fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
self.inner.to_pkcs8_der()
}
}
impl<D> From<RsaPrivateKey> for SigningKey<D>
where
D: Digest,
{
fn from(key: RsaPrivateKey) -> Self {
Self::new(key)
}
}
impl<D> From<SigningKey<D>> for RsaPrivateKey
where
D: Digest,
{
fn from(key: SigningKey<D>) -> Self {
key.inner
}
}
impl<D> Keypair for SigningKey<D>
where
D: Digest,
{
type VerifyingKey = VerifyingKey<D>;
fn verifying_key(&self) -> Self::VerifyingKey {
VerifyingKey {
inner: self.inner.to_public_key(),
salt_len: self.salt_len,
phantom: Default::default(),
}
}
}
impl<D> ZeroizeOnDrop for SigningKey<D> where D: Digest {}

158
vendor/rsa/src/pss/verifying_key.rs vendored Normal file
View File

@@ -0,0 +1,158 @@
use super::{verify_digest, Signature};
use crate::RsaPublicKey;
use core::marker::PhantomData;
use digest::{Digest, FixedOutputReset};
use pkcs8::{
spki::{der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier},
Document, EncodePublicKey,
};
use signature::{hazmat::PrehashVerifier, DigestVerifier, Verifier};
/// Verifying key for checking the validity of RSASSA-PSS signatures as
/// described in [RFC8017 § 8.1].
///
/// [RFC8017 § 8.1]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.1
#[derive(Debug)]
pub struct VerifyingKey<D>
where
D: Digest,
{
pub(super) inner: RsaPublicKey,
pub(super) salt_len: usize,
pub(super) phantom: PhantomData<D>,
}
impl<D> VerifyingKey<D>
where
D: Digest,
{
/// Create a new RSASSA-PSS verifying key.
/// Digest output size is used as a salt length.
pub fn new(key: RsaPublicKey) -> Self {
Self::new_with_salt_len(key, <D as Digest>::output_size())
}
/// Create a new RSASSA-PSS verifying key.
pub fn new_with_salt_len(key: RsaPublicKey, salt_len: usize) -> Self {
Self {
inner: key,
salt_len,
phantom: Default::default(),
}
}
}
//
// `*Verifier` trait impls
//
impl<D> DigestVerifier<D, Signature> for VerifyingKey<D>
where
D: Digest + FixedOutputReset,
{
fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> {
verify_digest::<D>(
&self.inner,
&digest.finalize(),
&signature.inner,
signature.len,
self.salt_len,
)
.map_err(|e| e.into())
}
}
impl<D> PrehashVerifier<Signature> for VerifyingKey<D>
where
D: Digest + FixedOutputReset,
{
fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> signature::Result<()> {
verify_digest::<D>(
&self.inner,
prehash,
&signature.inner,
signature.len,
self.salt_len,
)
.map_err(|e| e.into())
}
}
impl<D> Verifier<Signature> for VerifyingKey<D>
where
D: Digest + FixedOutputReset,
{
fn verify(&self, msg: &[u8], signature: &Signature) -> signature::Result<()> {
verify_digest::<D>(
&self.inner,
&D::digest(msg),
&signature.inner,
signature.len,
self.salt_len,
)
.map_err(|e| e.into())
}
}
//
// Other trait impls
//
impl<D> AsRef<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn as_ref(&self) -> &RsaPublicKey {
&self.inner
}
}
impl<D> AssociatedAlgorithmIdentifier for VerifyingKey<D>
where
D: Digest,
{
type Params = AnyRef<'static>;
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
}
// Implemented manually so we don't have to bind D with Clone
impl<D> Clone for VerifyingKey<D>
where
D: Digest,
{
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
salt_len: self.salt_len,
phantom: Default::default(),
}
}
}
impl<D> EncodePublicKey for VerifyingKey<D>
where
D: Digest,
{
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
self.inner.to_public_key_der()
}
}
impl<D> From<RsaPublicKey> for VerifyingKey<D>
where
D: Digest,
{
fn from(key: RsaPublicKey) -> Self {
Self::new(key)
}
}
impl<D> From<VerifyingKey<D>> for RsaPublicKey
where
D: Digest,
{
fn from(key: VerifyingKey<D>) -> Self {
key.inner
}
}

9
vendor/rsa/src/traits.rs vendored Normal file
View File

@@ -0,0 +1,9 @@
//! RSA-related trait definitions.
mod encryption;
pub(crate) mod keys;
mod padding;
pub use encryption::{Decryptor, EncryptingKeypair, RandomizedDecryptor, RandomizedEncryptor};
pub use keys::{PrivateKeyParts, PublicKeyParts};
pub use padding::{PaddingScheme, SignatureScheme};

42
vendor/rsa/src/traits/encryption.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
//! Encryption-related traits.
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
use crate::errors::Result;
/// Encrypt the message using provided random source
pub trait RandomizedEncryptor {
/// Encrypt the given message.
fn encrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
msg: &[u8],
) -> Result<Vec<u8>>;
}
/// Decrypt the given message
pub trait Decryptor {
/// Decrypt the given message.
fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>>;
}
/// Decrypt the given message using provided random source
pub trait RandomizedDecryptor {
/// Decrypt the given message.
fn decrypt_with_rng<R: CryptoRngCore + ?Sized>(
&self,
rng: &mut R,
ciphertext: &[u8],
) -> Result<Vec<u8>>;
}
/// Encryption keypair with an associated encryption key.
pub trait EncryptingKeypair {
/// Encrypting key type for this keypair.
type EncryptingKey: Clone;
/// Get the encrypting key which can encrypt messages to be decrypted by
/// the decryption key portion of this keypair.
fn encrypting_key(&self) -> Self::EncryptingKey;
}

65
vendor/rsa/src/traits/keys.rs vendored Normal file
View File

@@ -0,0 +1,65 @@
//! Traits related to the key components
use num_bigint::{BigInt, BigUint};
use zeroize::Zeroize;
/// Components of an RSA public key.
pub trait PublicKeyParts {
/// Returns the modulus of the key.
fn n(&self) -> &BigUint;
/// Returns the public exponent of the key.
fn e(&self) -> &BigUint;
/// 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
}
}
/// Components of an RSA private key.
pub trait PrivateKeyParts: PublicKeyParts {
/// Returns the private exponent of the key.
fn d(&self) -> &BigUint;
/// Returns the prime factors.
fn primes(&self) -> &[BigUint];
/// Returns the precomputed dp value, D mod (P-1)
fn dp(&self) -> Option<&BigUint>;
/// Returns the precomputed dq value, D mod (Q-1)
fn dq(&self) -> Option<&BigUint>;
/// Returns the precomputed qinv value, Q^-1 mod P
fn qinv(&self) -> Option<&BigInt>;
/// Returns an iterator over the CRT Values
fn crt_values(&self) -> Option<&[CrtValue]>;
}
/// Contains the precomputed Chinese remainder theorem values.
#[derive(Debug, Clone)]
pub struct CrtValue {
/// D mod (prime - 1)
pub(crate) exp: BigInt,
/// R·Coeff ≡ 1 mod Prime.
pub(crate) coeff: BigInt,
/// product of primes prior to this (inc p and q)
pub(crate) r: BigInt,
}
impl Zeroize for CrtValue {
fn zeroize(&mut self) {
self.exp.zeroize();
self.coeff.zeroize();
self.r.zeroize();
}
}
impl Drop for CrtValue {
fn drop(&mut self) {
self.zeroize();
}
}

49
vendor/rsa/src/traits/padding.rs vendored Normal file
View File

@@ -0,0 +1,49 @@
//! Supported padding schemes.
use alloc::vec::Vec;
use rand_core::CryptoRngCore;
use crate::errors::Result;
use crate::key::{RsaPrivateKey, RsaPublicKey};
/// Padding scheme used for encryption.
pub trait PaddingScheme {
/// Decrypt the given message using the given private key.
///
/// If an `rng` is passed, it uses RSA blinding to help mitigate timing
/// side-channel attacks.
fn decrypt<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
ciphertext: &[u8],
) -> Result<Vec<u8>>;
/// Encrypt the given message using the given public key.
fn encrypt<Rng: CryptoRngCore>(
self,
rng: &mut Rng,
pub_key: &RsaPublicKey,
msg: &[u8],
) -> Result<Vec<u8>>;
}
/// Digital signature scheme.
pub trait SignatureScheme {
/// Sign the given digest.
fn sign<Rng: CryptoRngCore>(
self,
rng: Option<&mut Rng>,
priv_key: &RsaPrivateKey,
hashed: &[u8],
) -> Result<Vec<u8>>;
/// Verify a signed message.
///
/// `hashed` must be the result of hashing the input using the hashing function
/// passed in through `hash`.
///
/// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
fn verify(self, pub_key: &RsaPublicKey, hashed: &[u8], sig: &[u8]) -> Result<()>;
}

Binary file not shown.

View File

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAtsQsUV8QpqrygsY+2+JCQ6Fw8/omM71IM2N/R8pPbzbgOl0p
78MZGsgPOQ2HSznjD0FPzsH8oO2B5Uftws04LHb2HJAYlz25+lN5cqfHAfa3fgmC
38FfwBkn7l582UtPWZ/wcBOnyCgb3yLcvJrXyrt8QxHJgvWO23ITrUVYszImbXQ6
7YGS0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0NfFdfsZhTT8YbxBvA8FdODgEwx7u/
vf3J9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejIn04APPKIjpMyQdnWlby7rNyQtE4+
CV+jcFjqJbE/Xilcvqxt6DirjFCvYeKYl1uHLwIDAQABAoIBAH7Mg2LA7bB0EWQh
XiL3SrnZG6BpAHAM9jaQ5RFNjua9z7suP5YUaSpnegg/FopeUuWWjmQHudl8bg5A
ZPgtoLdYoU8XubfUH19I4o1lUXBPVuaeeqn6Yw/HZCjAbSXkVdz8VbesK092ZD/e
0/4V/3irsn5lrMSq0L322yfvYKaRDFxKCF7UMnWrGcHZl6Msbv/OffLRk19uYB7t
4WGhK1zCfKIfgdLJnD0eoI6Q4wU6sJvvpyTe8NDDo8HpdAwNn3YSahSewKp9gHgg
VIQlTZUdsHxM+R+2RUwJZYj9WSTbq+s1nKICUmjQBPnWbrPW963BE5utQPFt3mOe
EWRzdsECgYEA3MBhJC1Okq+u5yrFE8plufdwNvm9fg5uYUYafvdlQiXsFTx+XDGm
FXpuWhP/bheOh1jByzPZ1rvjF57xiZjkIuzcvtePTs/b5fT82K7CydDchkc8qb0W
2dI40h+13e++sUPKYdC9aqjZHzOgl3kOlkDbyRCF3F8mNDujE49rLWcCgYEA0/MU
dX5A6VSDb5K+JCNq8vDaBKNGU8GAr2fpYAhtk/3mXLI+/Z0JN0di9ZgeNhhJr2jN
11OU/2pOButpsgnkIo2y36cOQPf5dQpSgXZke3iNDld3osuLIuPNJn/3C087AtOq
+w4YxZClZLAxiLCqX8SBVrB2IiFCQ70SJ++n8vkCgYEAzmi3rBsNEA1jblVIh1PF
wJhD/bOQ4nBd92iUV8m9jZdl4wl4YX4u/IBI9MMkIG24YIe2VOl7s9Rk5+4/jNg/
4QQ2998Y6aljxOZJEdZ+3jQELy4m49OhrTRq2ta5t/Z3CMsJTmLe6f9NXWZpr5iK
8iVdHOjtMXxqfYaR2jVNEtsCgYAl9uWUQiAoa037v0I1wO5YQ9IZgJGJUSDWynsg
C4JtPs5zji4ASY+sCipsqWnH8MPKGrC8QClxMr51ONe+30yw78a5jvfbpU9Wqpmq
vOU0xJwnlH1GeMUcY8eMfOFocjG0yOtYeubvBIDLr0/AFzz9WHp+Z69RX7m53nUR
GDlyKQKBgDGZVAbUBiB8rerqNbONBAxfipoa4IJ+ntBrFT2DtoIZNbSzaoK+nVbH
kbWMJycaV5PVOh1lfAiZeWCxQz5RcZh/RS8USnxyMG1j4dP/wLcbdasI8uRaSC6Y
hFHL5HjhLrIo0HRWySS2b2ztBI2FP1M+MaaGFPHDzm2OyZg85yr3
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,8 @@
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAtsQsUV8QpqrygsY+2+JCQ6Fw8/omM71IM2N/R8pPbzbgOl0p78MZ
GsgPOQ2HSznjD0FPzsH8oO2B5Uftws04LHb2HJAYlz25+lN5cqfHAfa3fgmC38Ff
wBkn7l582UtPWZ/wcBOnyCgb3yLcvJrXyrt8QxHJgvWO23ITrUVYszImbXQ67YGS
0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0NfFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J
9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejIn04APPKIjpMyQdnWlby7rNyQtE4+CV+j
cFjqJbE/Xilcvqxt6DirjFCvYeKYl1uHLwIDAQAB
-----END RSA PUBLIC KEY-----

Binary file not shown.

View File

@@ -0,0 +1,51 @@
-----BEGIN RSA PRIVATE KEY-----
MIIJKQIBAAKCAgEAp6dFcoEeomF+Sehb1zDd4w8QP32I7j92XlQNPdmTu7C6FAAC
hZ0LQIl0NmN/WLgo6nTfgyFjQHf5nUqi1UyjdYUu9ZdmHTcTzh7ztP1qjiICOORn
ZoosfuOGHSISrmoevd+oi2LfEPa8957/SsKY+yVj3xuHZDga+bH7DM0IXgJrCtn2
chojUXfQOWtIdUrUp1JCJQqHO/L25+48dd1hPjZbpPMhCmzGa5Ci+j92LKaIQIe2
v4Fh6xRIGfD1cvIfbI4nPnDUWjZbiygZznNGE8wjsBMpoXkB8XB4QDhh9UxSoFHi
pYx1wtnYAJG7mAihBsH37LQDThUFi+7HJcX5GdYuqiNLYmKNNGxgu5GecIUdqzhX
Hm8O12NBKfmU6jaP7nNz397AREXrykf6IO0VQKhgyUi6vJjaWRyh3i4uJVQO+bfL
NT9gITuBSkXTWe+puBHu/wjGWZO/ioXCv+qqftXmtD4YrmBEZM5flhUBNufQn4sk
+tQ9eHARjPp7wkh1UG67wyG5d+CGGupQEoYgEh8LOUqc3QpCQRoTUMB3DZddcbAK
kENiQMlnoMOlwgoPbed/Pyyv2pTtAUPB9uNPc+DKwnnu63xjdyOisCbIKALhpK66
qIRt+Y55GUmHc+DU8xmVb03jqtAO+5oUfWazrBoB01ss+0jUALDnqA3JdVECAwEA
AQKCAgEAn+MJeyMiuQ+rZgbAF6CV6+ZAw5wQC87gLyOPoU2v846eV1aPESftRDYS
a5BGMbEn7Dlbs+4SfrgsiNJWKn+1X+2NFFC35OLS839XQmNvzG8omWNSLVtXBggs
rfoBwO6ZtNDpJ006mS4Gl0y+AWlGhjVpYqwZWf2b1EfluZaMBUPfG/E0dCrzRc2y
+h+TcbDUz2HGjRbWU9jpmdT9OhbPl4o1qkDoYM3OCWVd2LTPGdQUGx6SrV5RqOSl
wn+nRWEdkOSdDpKCIiq28SZkPhx3V4gW/OO5jzIdJUnylKRw34RTRGvzb5hd8l7Y
/en98wc/sncn30jp4fxwVrx4llCQt4UBJkBkYsglMFHvhONO48POuPlsZYw4vkVV
jS9k4p0iM1BVX8Hvoo7B9K+1ukCA8JqGzcNTjBrXyXLm16NhLmhFupr73xnwkGDR
p3neljXi0vjgxRC6JMbESzDJvfr4W+kXrsXUOvqxqjrdM8yD2pPKxpIY9qNutH8Z
nVQkyV/Z7Xsei+KuqmQzsickExbCDueSZQzrSL/WNERrGdKGtOoXIkmNoaNpcyEO
w4JHUaWAjZqu9ZxEnhmlB3z+yhJr2ajdSZZWHU4ns2Cf+CxbGyHmJ4RdRJYbM7h1
1cT6n/NX72vjNklp4TN8kbKaB7mpE83kDOLVUwyQDnN1FoXmVDECggEBANAhOnlC
W2ZbcZEYRIiT7DJ1YA9j2/hbd/To6Z7zAvboJZYEj23Kdy3mu/ESTbhLCv5hsDqG
BKsAee1T8zBHl60Bs4xE/ielpF43hIOoBLVqSpZ/SPAahm5yHmfkyaEEivaJJ/qk
PWqF2T579wdNunl1Y/yr4SMJt2ZTxtthTcIxzFVtnyWsSEGgLTHN8wFbISMH+dDH
n+tdOVbOU8yPoWUb5gdh8Z90ZySJ6vnyFUCfOZVud6ghg/H3K7L+3fG5+/xK2J6k
RYCd29W9WVJ3mQwL6TZvuy7PewV8wcPcj7d7+EVtB7vJWzwYFfSOYrgUaMPU2dls
D0jasEmTvo2R7eUCggEBAM42xoEFIqvl1kZfNusTfaO56kpfHSfGYUcp645eLly4
jj7xpHOiGUS2ZVez3CzkYuS/NEbLSZADflZysXBcuugbZbr5Z6Jm3Bjv6A9Nu/4a
WQYyBc4pQ8rfQhzOdK9wY/0ag688Oa+EUl9ZvcH/VIFfUq/R6NSGKyw2VPbPqD3A
jiqdUrn4M8ZGr3aURn38X31617RBiV/Lf/vtUmMksBVKFYI/UQfIlUjt3LYdpTCM
bMg01KDBbfpsodZ7YaZWd+sXGc0SXQ7w24gC+3bPwXV3vLJRCuKU4b+KkXOiuFwW
prUIyY8tdwt/PeSNnnIMU+JjaAtX5xCUEAFXRVcGUv0CggEAdItGzQPlXmmyLEdk
iP4b8x1azwNh965we4m42DLH5C6WbWzcS+Rl3CQp9ZIER0BuRYe6QOsuzfqUS9sI
gG52doBPZCp2DwloAwIfiAGbsWJ1pdRcqWaRBGOOtyqb5ThAAFFJO8agRXfx8FVG
PKa/1qdvd9tfVFlqgzhCUDIqcqWj/+pEhbn1NBpXdF4YxxeadJ1QvCIsYIVxSDR9
JD0BaTa4FkY4IMvzvbglBhUS5X7DpfOXuWQbGHEJ3U9uRJ+ahOn8ZskhyiWbJhLD
Y7Ro1SAOVVc3f7za7HWxotVs/JfErEujWvojxoDOOoVIrj9vcslLu74QyQD8WhcL
Swb+KQKCAQB1yk4LBp7uZ8PEwMCC+MgsjJbq0ne575RDbQuTb/K1neoKxEa2kmIy
oKk0tpVOw0pF9X3r7lTfwU8aHDuEvkM5L+UlLy9mUbDpQahhjXqTxAMUCeDNCT8j
E/IUuE1opR9IRSvxHcqpmkDfHEjLFojzuTpnGdUQCG+Cuqo/rRAh7eqHJwRJHCCe
4mN5rWqyrkTxTQkHeuP4Zyp9AeusnBlEn+O3WWl0s7uqQ8xt7nMcTyoYFi1aggLL
J+Atvp5hwESRccmYHSQw053ijCmNjVCpQ7LyfF5mXLqyiXlZ/xml6H5jLFjNwx+b
3pvBAK//31DPIQ8eY6CmFJ0r1ujRs9gVAoIBAQCMVXxINei0BmYGpdwlXbw+tfFY
bHMomIyOJCQD+Vde+w0oASwGNLckF2itciBJOCkG1jWvyx0qBb3/yAX+ZwOJt/qQ
1l+Ur7wgCNm8DTzO5CXfxyQCBQYDyfV57oUQ7MaTrG3TKDa24V49xSA2ahukr8kd
Pkik1nJMpCRD9IA+OxJjSwQ4Vy2OE7xy8agoU7jZ/KYZnXqQq2TZ5595OsKH+aGQ
EQgqUmjyCTMtVNmNbhkDCQf9nmuC7xJGd7oIrWeXpEIhPQl6NRxQoIko3XMtaymm
z2cG2vXyD3j4cXD7J5QDxSIbXlxwwrqg5ppy4NHzJn29jJvd/yivqS83yY02
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,13 @@
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAgEAp6dFcoEeomF+Sehb1zDd4w8QP32I7j92XlQNPdmTu7C6FAAChZ0L
QIl0NmN/WLgo6nTfgyFjQHf5nUqi1UyjdYUu9ZdmHTcTzh7ztP1qjiICOORnZoos
fuOGHSISrmoevd+oi2LfEPa8957/SsKY+yVj3xuHZDga+bH7DM0IXgJrCtn2choj
UXfQOWtIdUrUp1JCJQqHO/L25+48dd1hPjZbpPMhCmzGa5Ci+j92LKaIQIe2v4Fh
6xRIGfD1cvIfbI4nPnDUWjZbiygZznNGE8wjsBMpoXkB8XB4QDhh9UxSoFHipYx1
wtnYAJG7mAihBsH37LQDThUFi+7HJcX5GdYuqiNLYmKNNGxgu5GecIUdqzhXHm8O
12NBKfmU6jaP7nNz397AREXrykf6IO0VQKhgyUi6vJjaWRyh3i4uJVQO+bfLNT9g
ITuBSkXTWe+puBHu/wjGWZO/ioXCv+qqftXmtD4YrmBEZM5flhUBNufQn4sk+tQ9
eHARjPp7wkh1UG67wyG5d+CGGupQEoYgEh8LOUqc3QpCQRoTUMB3DZddcbAKkENi
QMlnoMOlwgoPbed/Pyyv2pTtAUPB9uNPc+DKwnnu63xjdyOisCbIKALhpK66qIRt
+Y55GUmHc+DU8xmVb03jqtAO+5oUfWazrBoB01ss+0jUALDnqA3JdVECAwEAAQ==
-----END RSA PUBLIC KEY-----

Binary file not shown.

View File

@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2xCxRXxCmqvKC
xj7b4kJDoXDz+iYzvUgzY39Hyk9vNuA6XSnvwxkayA85DYdLOeMPQU/Owfyg7YHl
R+3CzTgsdvYckBiXPbn6U3lyp8cB9rd+CYLfwV/AGSfuXnzZS09Zn/BwE6fIKBvf
Ity8mtfKu3xDEcmC9Y7bchOtRVizMiZtdDrtgZLRiEytuLFHOaja2mbclwgG2ces
RQyxPQ18V1+xmFNPxhvEG8DwV04OATDHu7+9/cn2puLj4q/xy+rIm6V4hFKNVc+w
gyeh6MifTgA88oiOkzJB2daVvLus3JC0Tj4JX6NwWOolsT9eKVy+rG3oOKuMUK9h
4piXW4cvAgMBAAECggEAfsyDYsDtsHQRZCFeIvdKudkboGkAcAz2NpDlEU2O5r3P
uy4/lhRpKmd6CD8Wil5S5ZaOZAe52XxuDkBk+C2gt1ihTxe5t9QfX0jijWVRcE9W
5p56qfpjD8dkKMBtJeRV3PxVt6wrT3ZkP97T/hX/eKuyfmWsxKrQvfbbJ+9gppEM
XEoIXtQydasZwdmXoyxu/8598tGTX25gHu3hYaErXMJ8oh+B0smcPR6gjpDjBTqw
m++nJN7w0MOjwel0DA2fdhJqFJ7Aqn2AeCBUhCVNlR2wfEz5H7ZFTAlliP1ZJNur
6zWcogJSaNAE+dZus9b3rcETm61A8W3eY54RZHN2wQKBgQDcwGEkLU6Sr67nKsUT
ymW593A2+b1+Dm5hRhp+92VCJewVPH5cMaYVem5aE/9uF46HWMHLM9nWu+MXnvGJ
mOQi7Ny+149Oz9vl9PzYrsLJ0NyGRzypvRbZ0jjSH7Xd776xQ8ph0L1qqNkfM6CX
eQ6WQNvJEIXcXyY0O6MTj2stZwKBgQDT8xR1fkDpVINvkr4kI2ry8NoEo0ZTwYCv
Z+lgCG2T/eZcsj79nQk3R2L1mB42GEmvaM3XU5T/ak4G62myCeQijbLfpw5A9/l1
ClKBdmR7eI0OV3eiy4si480mf/cLTzsC06r7DhjFkKVksDGIsKpfxIFWsHYiIUJD
vRIn76fy+QKBgQDOaLesGw0QDWNuVUiHU8XAmEP9s5DicF33aJRXyb2Nl2XjCXhh
fi78gEj0wyQgbbhgh7ZU6Xuz1GTn7j+M2D/hBDb33xjpqWPE5kkR1n7eNAQvLibj
06GtNGra1rm39ncIywlOYt7p/01dZmmvmIryJV0c6O0xfGp9hpHaNU0S2wKBgCX2
5ZRCIChrTfu/QjXA7lhD0hmAkYlRINbKeyALgm0+znOOLgBJj6wKKmypacfww8oa
sLxAKXEyvnU4177fTLDvxrmO99ulT1aqmaq85TTEnCeUfUZ4xRxjx4x84WhyMbTI
61h65u8EgMuvT8AXPP1Yen5nr1FfubnedREYOXIpAoGAMZlUBtQGIHyt6uo1s40E
DF+Kmhrggn6e0GsVPYO2ghk1tLNqgr6dVseRtYwnJxpXk9U6HWV8CJl5YLFDPlFx
mH9FLxRKfHIwbWPh0//Atxt1qwjy5FpILpiEUcvkeOEusijQdFbJJLZvbO0EjYU/
Uz4xpoYU8cPObY7JmDznKvc=
-----END PRIVATE KEY-----

Binary file not shown.

View File

@@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtsQsUV8QpqrygsY+2+JC
Q6Fw8/omM71IM2N/R8pPbzbgOl0p78MZGsgPOQ2HSznjD0FPzsH8oO2B5Uftws04
LHb2HJAYlz25+lN5cqfHAfa3fgmC38FfwBkn7l582UtPWZ/wcBOnyCgb3yLcvJrX
yrt8QxHJgvWO23ITrUVYszImbXQ67YGS0YhMrbixRzmo2tpm3JcIBtnHrEUMsT0N
fFdfsZhTT8YbxBvA8FdODgEwx7u/vf3J9qbi4+Kv8cvqyJuleIRSjVXPsIMnoejI
n04APPKIjpMyQdnWlby7rNyQtE4+CV+jcFjqJbE/Xilcvqxt6DirjFCvYeKYl1uH
LwIDAQAB
-----END PUBLIC KEY-----

Binary file not shown.

201
vendor/rsa/tests/pkcs1.rs vendored Normal file
View File

@@ -0,0 +1,201 @@
//! PKCS#1 encoding tests
use hex_literal::hex;
use rsa::{
pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey},
traits::{PrivateKeyParts, PublicKeyParts},
RsaPrivateKey, RsaPublicKey,
};
#[cfg(feature = "pem")]
use rsa::pkcs1::LineEnding;
/// RSA-2048 PKCS#1 private key encoded as ASN.1 DER.
///
/// Note: this key is extracted from the corresponding `rsa2048-priv.der`
/// example key in the `pkcs8` crate.
const RSA_2048_PRIV_DER: &[u8] = include_bytes!("examples/pkcs1/rsa2048-priv.der");
/// RSA-4096 PKCS#1 private key encoded as ASN.1 DER
const RSA_4096_PRIV_DER: &[u8] = include_bytes!("examples/pkcs1/rsa4096-priv.der");
/// RSA-2048 PKCS#1 public key encoded as ASN.1 DER.
///
/// Note: this key is extracted from the corresponding `rsa2048-priv.der`
/// example key in the `pkcs8` crate.
const RSA_2048_PUB_DER: &[u8] = include_bytes!("examples/pkcs1/rsa2048-pub.der");
/// RSA-4096 PKCS#1 public key encoded as ASN.1 DER
const RSA_4096_PUB_DER: &[u8] = include_bytes!("examples/pkcs1/rsa4096-pub.der");
/// RSA-2048 PKCS#1 private key encoded as PEM
#[cfg(feature = "pem")]
const RSA_2048_PRIV_PEM: &str = include_str!("examples/pkcs1/rsa2048-priv.pem");
/// RSA-4096 PKCS#1 private key encoded as PEM
#[cfg(feature = "pem")]
const RSA_4096_PRIV_PEM: &str = include_str!("examples/pkcs1/rsa4096-priv.pem");
/// RSA-2048 PKCS#1 public key encoded as PEM
#[cfg(feature = "pem")]
const RSA_2048_PUB_PEM: &str = include_str!("examples/pkcs1/rsa2048-pub.pem");
/// RSA-4096 PKCS#1 public key encoded as PEM
#[cfg(feature = "pem")]
const RSA_4096_PUB_PEM: &str = include_str!("examples/pkcs1/rsa4096-pub.pem");
#[test]
fn decode_rsa2048_priv_der() {
let key = RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-priv.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9"));
}
#[test]
fn decode_rsa4096_priv_der() {
let key = RsaPrivateKey::from_pkcs1_der(RSA_4096_PRIV_DER).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-priv.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375852EF597661D3713CE1EF3B4FD6A8E220238E467668A2C7EE3861D2212AE6A1EBDDFA88B62DF10F6BCF79EFF4AC298FB2563DF1B8764381AF9B1FB0CCD085E026B0AD9F6721A235177D0396B48754AD4A75242250A873BF2F6E7EE3C75DD613E365BA4F3210A6CC66B90A2FA3F762CA6884087B6BF8161EB144819F0F572F21F6C8E273E70D45A365B8B2819CE734613CC23B01329A17901F17078403861F54C52A051E2A58C75C2D9D80091BB9808A106C1F7ECB4034E15058BEEC725C5F919D62EAA234B62628D346C60BB919E70851DAB38571E6F0ED7634129F994EA368FEE7373DFDEC04445EBCA47FA20ED1540A860C948BABC98DA591CA1DE2E2E25540EF9B7CB353F60213B814A45D359EFA9B811EEFF08C65993BF8A85C2BFEAAA7ED5E6B43E18AE604464CE5F96150136E7D09F8B24FAD43D7870118CFA7BC24875506EBBC321B977E0861AEA50128620121F0B394A9CDD0A42411A1350C0770D975D71B00A90436240C967A0C3A5C20A0F6DE77F3F2CAFDA94ED0143C1F6E34F73E0CAC279EEEB7C637723A2B026C82802E1A4AEBAA8846DF98E7919498773E0D4F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55FED8D1450B7E4E2D2F37F5742636FCC6F289963522D5B5706082CADFA01C0EE99B4D0E9274D3A992E06974CBE01694686356962AC1959FD9BD447E5B9968C0543DF1BF134742AF345CDB2FA1F9371B0D4CF61C68D16D653D8E999D4FD3A16CF978A35AA40E860CDCE09655DD8B4CF19D4141B1E92AD5E51A8E4A5C27FA745611D90E49D0E9282222AB6F126643E1C77578816FCE3B98F321D2549F294A470DF8453446BF36F985DF25ED8FDE9FDF3073FB27727DF48E9E1FC7056BC78965090B7850126406462C8253051EF84E34EE3C3CEB8F96C658C38BE45558D2F64E29D223350555FC1EFA28EC1F4AFB5BA4080F09A86CDC3538C1AD7C972E6D7A3612E6845BA9AFBDF19F09060D1A779DE9635E2D2F8E0C510BA24C6C44B30C9BDFAF85BE917AEC5D43AFAB1AA3ADD33CC83DA93CAC69218F6A36EB47F199D5424C95FD9ED7B1E8BE2AEAA6433B227241316C20EE792650CEB48BFD634446B19D286B4EA1722498DA1A36973210EC3824751A5808D9AAEF59C449E19A5077CFECA126BD9A8DD4996561D4E27B3609FF82C5B1B21E627845D44961B33B875D5C4FA9FF357EF6BE3364969E1337C91B29A07B9A913CDE40CE2D5530C900E73751685E65431"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E82596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD01B38C44FE27A5A45E378483A804B56A4A967F48F01A866E721E67E4C9A1048AF68927FAA43D6A85D93E7BF7074DBA797563FCABE12309B76653C6DB614DC231CC556D9F25AC4841A02D31CDF3015B212307F9D0C79FEB5D3956CE53CC8FA1651BE60761F19F74672489EAF9F215409F39956E77A82183F1F72BB2FEDDF1B9FBFC4AD89EA445809DDBD5BD595277990C0BE9366FBB2ECF7B057CC1C3DC8FB77BF8456D07BBC95B3C1815F48E62B81468C3D4D9D96C0F48DAB04993BE8D91EDE5"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB88E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE81B65BAF967A266DC18EFE80F4DBBFE1A59063205CE2943CADF421CCE74AF7063FD1A83AF3C39AF84525F59BDC1FF54815F52AFD1E8D4862B2C3654F6CFA83DC08E2A9D52B9F833C646AF7694467DFC5F7D7AD7B441895FCB7FFBED526324B0154A15823F5107C89548EDDCB61DA5308C6CC834D4A0C16DFA6CA1D67B61A65677EB1719CD125D0EF0DB8802FB76CFC17577BCB2510AE294E1BF8A9173A2B85C16A6B508C98F2D770B7F3DE48D9E720C53E263680B57E7109410015745570652FD"));
}
#[test]
fn decode_rsa2048_pub_der() {
let key = RsaPublicKey::from_pkcs1_der(RSA_2048_PUB_DER).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-pub.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
}
#[test]
fn decode_rsa4096_pub_der() {
let key = RsaPublicKey::from_pkcs1_der(RSA_4096_PUB_DER).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-pub.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375852EF597661D3713CE1EF3B4FD6A8E220238E467668A2C7EE3861D2212AE6A1EBDDFA88B62DF10F6BCF79EFF4AC298FB2563DF1B8764381AF9B1FB0CCD085E026B0AD9F6721A235177D0396B48754AD4A75242250A873BF2F6E7EE3C75DD613E365BA4F3210A6CC66B90A2FA3F762CA6884087B6BF8161EB144819F0F572F21F6C8E273E70D45A365B8B2819CE734613CC23B01329A17901F17078403861F54C52A051E2A58C75C2D9D80091BB9808A106C1F7ECB4034E15058BEEC725C5F919D62EAA234B62628D346C60BB919E70851DAB38571E6F0ED7634129F994EA368FEE7373DFDEC04445EBCA47FA20ED1540A860C948BABC98DA591CA1DE2E2E25540EF9B7CB353F60213B814A45D359EFA9B811EEFF08C65993BF8A85C2BFEAAA7ED5E6B43E18AE604464CE5F96150136E7D09F8B24FAD43D7870118CFA7BC24875506EBBC321B977E0861AEA50128620121F0B394A9CDD0A42411A1350C0770D975D71B00A90436240C967A0C3A5C20A0F6DE77F3F2CAFDA94ED0143C1F6E34F73E0CAC279EEEB7C637723A2B026C82802E1A4AEBAA8846DF98E7919498773E0D4F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
}
#[test]
fn encode_rsa2048_priv_der() {
let key = RsaPrivateKey::from_pkcs1_der(RSA_2048_PRIV_DER).unwrap();
let der = key.to_pkcs1_der().unwrap();
assert_eq!(der.as_bytes(), RSA_2048_PRIV_DER)
}
#[test]
fn encode_rsa4096_priv_der() {
let key = RsaPrivateKey::from_pkcs1_der(RSA_4096_PRIV_DER).unwrap();
let der = key.to_pkcs1_der().unwrap();
assert_eq!(der.as_bytes(), RSA_4096_PRIV_DER)
}
#[test]
fn encode_rsa2048_pub_der() {
let key = RsaPublicKey::from_pkcs1_der(RSA_2048_PUB_DER).unwrap();
let der = key.to_pkcs1_der().unwrap();
assert_eq!(der.as_ref(), RSA_2048_PUB_DER)
}
#[test]
fn encode_rsa4096_pub_der() {
let key = RsaPublicKey::from_pkcs1_der(RSA_4096_PUB_DER).unwrap();
let der = key.to_pkcs1_der().unwrap();
assert_eq!(der.as_ref(), RSA_4096_PUB_DER)
}
#[test]
#[cfg(feature = "pem")]
fn decode_rsa2048_priv_pem() {
let key = RsaPrivateKey::from_pkcs1_pem(RSA_2048_PRIV_PEM).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-priv.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9"));
}
#[test]
#[cfg(feature = "pem")]
fn decode_rsa4096_priv_pem() {
let key = RsaPrivateKey::from_pkcs1_pem(RSA_4096_PRIV_PEM).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-priv.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375852EF597661D3713CE1EF3B4FD6A8E220238E467668A2C7EE3861D2212AE6A1EBDDFA88B62DF10F6BCF79EFF4AC298FB2563DF1B8764381AF9B1FB0CCD085E026B0AD9F6721A235177D0396B48754AD4A75242250A873BF2F6E7EE3C75DD613E365BA4F3210A6CC66B90A2FA3F762CA6884087B6BF8161EB144819F0F572F21F6C8E273E70D45A365B8B2819CE734613CC23B01329A17901F17078403861F54C52A051E2A58C75C2D9D80091BB9808A106C1F7ECB4034E15058BEEC725C5F919D62EAA234B62628D346C60BB919E70851DAB38571E6F0ED7634129F994EA368FEE7373DFDEC04445EBCA47FA20ED1540A860C948BABC98DA591CA1DE2E2E25540EF9B7CB353F60213B814A45D359EFA9B811EEFF08C65993BF8A85C2BFEAAA7ED5E6B43E18AE604464CE5F96150136E7D09F8B24FAD43D7870118CFA7BC24875506EBBC321B977E0861AEA50128620121F0B394A9CDD0A42411A1350C0770D975D71B00A90436240C967A0C3A5C20A0F6DE77F3F2CAFDA94ED0143C1F6E34F73E0CAC279EEEB7C637723A2B026C82802E1A4AEBAA8846DF98E7919498773E0D4F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("9FE3097B2322B90FAB6606C017A095EBE640C39C100BCEE02F238FA14DAFF38E9E57568F1127ED4436126B904631B127EC395BB3EE127EB82C88D2562A7FB55FED8D1450B7E4E2D2F37F5742636FCC6F289963522D5B5706082CADFA01C0EE99B4D0E9274D3A992E06974CBE01694686356962AC1959FD9BD447E5B9968C0543DF1BF134742AF345CDB2FA1F9371B0D4CF61C68D16D653D8E999D4FD3A16CF978A35AA40E860CDCE09655DD8B4CF19D4141B1E92AD5E51A8E4A5C27FA745611D90E49D0E9282222AB6F126643E1C77578816FCE3B98F321D2549F294A470DF8453446BF36F985DF25ED8FDE9FDF3073FB27727DF48E9E1FC7056BC78965090B7850126406462C8253051EF84E34EE3C3CEB8F96C658C38BE45558D2F64E29D223350555FC1EFA28EC1F4AFB5BA4080F09A86CDC3538C1AD7C972E6D7A3612E6845BA9AFBDF19F09060D1A779DE9635E2D2F8E0C510BA24C6C44B30C9BDFAF85BE917AEC5D43AFAB1AA3ADD33CC83DA93CAC69218F6A36EB47F199D5424C95FD9ED7B1E8BE2AEAA6433B227241316C20EE792650CEB48BFD634446B19D286B4EA1722498DA1A36973210EC3824751A5808D9AAEF59C449E19A5077CFECA126BD9A8DD4996561D4E27B3609FF82C5B1B21E627845D44961B33B875D5C4FA9FF357EF6BE3364969E1337C91B29A07B9A913CDE40CE2D5530C900E73751685E65431"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("D0213A79425B665B719118448893EC3275600F63DBF85B77F4E8E99EF302F6E82596048F6DCA772DE6BBF1124DB84B0AFE61B03A8604AB0079ED53F3304797AD01B38C44FE27A5A45E378483A804B56A4A967F48F01A866E721E67E4C9A1048AF68927FAA43D6A85D93E7BF7074DBA797563FCABE12309B76653C6DB614DC231CC556D9F25AC4841A02D31CDF3015B212307F9D0C79FEB5D3956CE53CC8FA1651BE60761F19F74672489EAF9F215409F39956E77A82183F1F72BB2FEDDF1B9FBFC4AD89EA445809DDBD5BD595277990C0BE9366FBB2ECF7B057CC1C3DC8FB77BF8456D07BBC95B3C1815F48E62B81468C3D4D9D96C0F48DAB04993BE8D91EDE5"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("CE36C6810522ABE5D6465F36EB137DA3B9EA4A5F1D27C6614729EB8E5E2E5CB88E3EF1A473A21944B66557B3DC2CE462E4BF3446CB4990037E5672B1705CBAE81B65BAF967A266DC18EFE80F4DBBFE1A59063205CE2943CADF421CCE74AF7063FD1A83AF3C39AF84525F59BDC1FF54815F52AFD1E8D4862B2C3654F6CFA83DC08E2A9D52B9F833C646AF7694467DFC5F7D7AD7B441895FCB7FFBED526324B0154A15823F5107C89548EDDCB61DA5308C6CC834D4A0C16DFA6CA1D67B61A65677EB1719CD125D0EF0DB8802FB76CFC17577BCB2510AE294E1BF8A9173A2B85C16A6B508C98F2D770B7F3DE48D9E720C53E263680B57E7109410015745570652FD"));
}
#[test]
#[cfg(feature = "pem")]
fn decode_rsa2048_pub_pem() {
let key = RsaPublicKey::from_pkcs1_pem(RSA_2048_PUB_PEM).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa2048-pub.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
}
#[test]
#[cfg(feature = "pem")]
fn decode_rsa4096_pub_pem() {
let key = RsaPublicKey::from_pkcs1_pem(RSA_4096_PUB_PEM).unwrap();
// Extracted using:
// $ openssl asn1parse -in tests/examples/pkcs1/rsa4096-pub.pem
assert_eq!(&key.n().to_bytes_be(), &hex!("A7A74572811EA2617E49E85BD730DDE30F103F7D88EE3F765E540D3DD993BBB0BA140002859D0B40897436637F58B828EA74DF8321634077F99D4AA2D54CA375852EF597661D3713CE1EF3B4FD6A8E220238E467668A2C7EE3861D2212AE6A1EBDDFA88B62DF10F6BCF79EFF4AC298FB2563DF1B8764381AF9B1FB0CCD085E026B0AD9F6721A235177D0396B48754AD4A75242250A873BF2F6E7EE3C75DD613E365BA4F3210A6CC66B90A2FA3F762CA6884087B6BF8161EB144819F0F572F21F6C8E273E70D45A365B8B2819CE734613CC23B01329A17901F17078403861F54C52A051E2A58C75C2D9D80091BB9808A106C1F7ECB4034E15058BEEC725C5F919D62EAA234B62628D346C60BB919E70851DAB38571E6F0ED7634129F994EA368FEE7373DFDEC04445EBCA47FA20ED1540A860C948BABC98DA591CA1DE2E2E25540EF9B7CB353F60213B814A45D359EFA9B811EEFF08C65993BF8A85C2BFEAAA7ED5E6B43E18AE604464CE5F96150136E7D09F8B24FAD43D7870118CFA7BC24875506EBBC321B977E0861AEA50128620121F0B394A9CDD0A42411A1350C0770D975D71B00A90436240C967A0C3A5C20A0F6DE77F3F2CAFDA94ED0143C1F6E34F73E0CAC279EEEB7C637723A2B026C82802E1A4AEBAA8846DF98E7919498773E0D4F319956F4DE3AAD00EFB9A147D66B3AC1A01D35B2CFB48D400B0E7A80DC97551"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
}
#[test]
#[cfg(feature = "pem")]
fn encode_rsa2048_priv_pem() {
let key = RsaPrivateKey::from_pkcs1_pem(RSA_2048_PRIV_PEM).unwrap();
let pem = key.to_pkcs1_pem(LineEnding::LF).unwrap();
assert_eq!(&*pem, RSA_2048_PRIV_PEM)
}
#[test]
#[cfg(feature = "pem")]
fn encode_rsa4096_priv_pem() {
let key = RsaPrivateKey::from_pkcs1_pem(RSA_4096_PRIV_PEM).unwrap();
let pem = key.to_pkcs1_pem(LineEnding::LF).unwrap();
assert_eq!(&*pem, RSA_4096_PRIV_PEM)
}
#[test]
#[cfg(feature = "pem")]
fn encode_rsa2048_pub_pem() {
let key = RsaPublicKey::from_pkcs1_pem(RSA_2048_PUB_PEM).unwrap();
let pem = key.to_pkcs1_pem(LineEnding::LF).unwrap();
assert_eq!(&*pem, RSA_2048_PUB_PEM)
}
#[test]
#[cfg(feature = "pem")]
fn encode_rsa4096_pub_pem() {
let key = RsaPublicKey::from_pkcs1_pem(RSA_4096_PUB_PEM).unwrap();
let pem = key.to_pkcs1_pem(LineEnding::LF).unwrap();
assert_eq!(&*pem, RSA_4096_PUB_PEM)
}

23
vendor/rsa/tests/pkcs1v15.rs vendored Normal file
View File

@@ -0,0 +1,23 @@
// simple but prevent regression - see https://github.com/RustCrypto/RSA/issues/329
#[cfg(feature = "pem")]
#[test]
fn signature_stringify() {
use pkcs8::DecodePrivateKey;
use signature::Signer;
use rsa::pkcs1v15::SigningKey;
use rsa::RsaPrivateKey;
let pem = include_str!("examples/pkcs8/rsa2048-priv.pem");
let private_key = RsaPrivateKey::from_pkcs8_pem(pem).unwrap();
let signing_key = SigningKey::<sha2::Sha256>::new(private_key);
let bytes: &[u8] = b"rsa4096"; // HACK - the criterion is that the signature has leading zeros.
let signature = signing_key.sign(bytes);
let expected = "029E365B60971D5A499FF5E1C288B954D3A5DCF52482CEE46DB90DC860B725A8D6CA031146FA156E9F17579BE6122FFB11DAC35E59B2193D75F7B31CE1442DDE7F4FF7885AD5D6080266E9A33BB4CEC93FCC2B6B885457A0ABF19E2DAA00876F694B37F535F119925CCCF9A17B90AE6CF39F07D7FEFBEECDF1B344C14B728196DDD154230BADDEDA5A7EFF373F6CD3EF6D41789572A7A068E3A252D3B7D5D706C6170D8CFDB48C8E738A4B3BFEA3E15716805E376EBD99EA09C6E82F3CFA13CEB23CD289E8F95C27F489ADC05AAACE8A9276EE7CED3B7A5C7264F0D34FF18CEDC3E91D667FCF9992A8CFDE8562F65FDDE1E06595C27E0F82063839A358C927B2";
assert_eq!(format!("{}", signature), expected);
assert_eq!(format!("{:x}", signature), expected.to_lowercase());
assert_eq!(format!("{:X}", signature), expected);
assert_eq!(signature.to_string(), expected);
}

118
vendor/rsa/tests/pkcs8.rs vendored Normal file
View File

@@ -0,0 +1,118 @@
//! PKCS#8 encoding tests
/// RSA-2048 PKCS#8 private key encoded as ASN.1 DER
const RSA_2048_PRIV_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-priv.der");
/// RSA-2048 `SubjectPublicKeyInfo` encoded as ASN.1 DER
const RSA_2048_PUB_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-pub.der");
/// RSA-2048 PKCS#8 private key encoded as PEM
#[cfg(feature = "pem")]
const RSA_2048_PRIV_PEM: &str = include_str!("examples/pkcs8/rsa2048-priv.pem");
/// RSA-2048 PKCS#8 public key encoded as PEM
#[cfg(feature = "pem")]
const RSA_2048_PUB_PEM: &str = include_str!("examples/pkcs8/rsa2048-pub.pem");
use hex_literal::hex;
use rsa::{
pkcs1v15,
pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
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(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9"));
let _ = pkcs1v15::SigningKey::<Sha256>::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
}
#[test]
fn decode_rsa2048_pub_der() {
let key = RsaPublicKey::from_public_key_der(RSA_2048_PUB_DER).unwrap();
// Note: matches PKCS#1 test vectors
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
let _ = pkcs1v15::VerifyingKey::<Sha256>::from_public_key_der(RSA_2048_PUB_DER).unwrap();
}
#[test]
fn encode_rsa2048_priv_der() {
let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
let der = key.to_pkcs8_der().unwrap();
assert_eq!(der.as_bytes(), RSA_2048_PRIV_DER);
let pkcs1v15_key = pkcs1v15::SigningKey::<Sha256>::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
let pkcs1v15_der = pkcs1v15_key.to_pkcs8_der().unwrap();
assert_eq!(pkcs1v15_der.as_bytes(), RSA_2048_PRIV_DER);
}
#[test]
fn encode_rsa2048_pub_der() {
let key = RsaPublicKey::from_public_key_der(RSA_2048_PUB_DER).unwrap();
let der = key.to_public_key_der().unwrap();
assert_eq!(der.as_ref(), RSA_2048_PUB_DER);
let pkcs1v15_key =
pkcs1v15::VerifyingKey::<Sha256>::from_public_key_der(RSA_2048_PUB_DER).unwrap();
let pkcs1v15_der = pkcs1v15_key.to_public_key_der().unwrap();
assert_eq!(pkcs1v15_der.as_ref(), RSA_2048_PUB_DER);
}
#[test]
#[cfg(feature = "pem")]
fn decode_rsa2048_priv_pem() {
let key = RsaPrivateKey::from_pkcs8_pem(RSA_2048_PRIV_PEM).unwrap();
// Note: matches PKCS#1 test vectors
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
assert_eq!(&key.d().to_bytes_be(), &hex!("7ECC8362C0EDB0741164215E22F74AB9D91BA06900700CF63690E5114D8EE6BDCFBB2E3F9614692A677A083F168A5E52E5968E6407B9D97C6E0E4064F82DA0B758A14F17B9B7D41F5F48E28D6551704F56E69E7AA9FA630FC76428C06D25E455DCFC55B7AC2B4F76643FDED3FE15FF78ABB27E65ACC4AAD0BDF6DB27EF60A6910C5C4A085ED43275AB19C1D997A32C6EFFCE7DF2D1935F6E601EEDE161A12B5CC27CA21F81D2C99C3D1EA08E90E3053AB09BEFA724DEF0D0C3A3C1E9740C0D9F76126A149EC0AA7D8078205484254D951DB07C4CF91FB6454C096588FD5924DBABEB359CA2025268D004F9D66EB3D6F7ADC1139BAD40F16DDE639E11647376C1"));
assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("DCC061242D4E92AFAEE72AC513CA65B9F77036F9BD7E0E6E61461A7EF7654225EC153C7E5C31A6157A6E5A13FF6E178E8758C1CB33D9D6BBE3179EF18998E422ECDCBED78F4ECFDBE5F4FCD8AEC2C9D0DC86473CA9BD16D9D238D21FB5DDEFBEB143CA61D0BD6AA8D91F33A097790E9640DBC91085DC5F26343BA3138F6B2D67"));
assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("D3F314757E40E954836F92BE24236AF2F0DA04A34653C180AF67E960086D93FDE65CB23EFD9D09374762F5981E361849AF68CDD75394FF6A4E06EB69B209E4228DB2DFA70E40F7F9750A528176647B788D0E5777A2CB8B22E3CD267FF70B4F3B02D3AAFB0E18C590A564B03188B0AA5FC48156B07622214243BD1227EFA7F2F9"));
let _ = pkcs1v15::SigningKey::<Sha256>::from_pkcs8_pem(RSA_2048_PRIV_PEM).unwrap();
}
#[test]
#[cfg(feature = "pem")]
fn decode_rsa2048_pub_pem() {
let key = RsaPublicKey::from_public_key_pem(RSA_2048_PUB_PEM).unwrap();
// Note: matches PKCS#1 test vectors
assert_eq!(&key.n().to_bytes_be(), &hex!("B6C42C515F10A6AAF282C63EDBE24243A170F3FA2633BD4833637F47CA4F6F36E03A5D29EFC3191AC80F390D874B39E30F414FCEC1FCA0ED81E547EDC2CD382C76F61C9018973DB9FA537972A7C701F6B77E0982DFC15FC01927EE5E7CD94B4F599FF07013A7C8281BDF22DCBC9AD7CABB7C4311C982F58EDB7213AD4558B332266D743AED8192D1884CADB8B14739A8DADA66DC970806D9C7AC450CB13D0D7C575FB198534FC61BC41BC0F0574E0E0130C7BBBFBDFDC9F6A6E2E3E2AFF1CBEAC89BA57884528D55CFB08327A1E8C89F4E003CF2888E933241D9D695BCBBACDC90B44E3E095FA37058EA25B13F5E295CBEAC6DE838AB8C50AF61E298975B872F"));
assert_eq!(&key.e().to_bytes_be(), &hex!("010001"));
let _ = pkcs1v15::VerifyingKey::<Sha256>::from_public_key_pem(RSA_2048_PUB_PEM).unwrap();
}
#[test]
#[cfg(feature = "pem")]
fn encode_rsa2048_priv_pem() {
let key = RsaPrivateKey::from_pkcs8_pem(RSA_2048_PRIV_PEM).unwrap();
let pem = key.to_pkcs8_pem(LineEnding::LF).unwrap();
assert_eq!(&*pem, RSA_2048_PRIV_PEM)
}
#[test]
#[cfg(feature = "pem")]
fn encode_rsa2048_pub_pem() {
let key = RsaPublicKey::from_public_key_pem(RSA_2048_PUB_PEM).unwrap();
let pem = key.to_public_key_pem(LineEnding::LF).unwrap();
assert_eq!(&*pem, RSA_2048_PUB_PEM)
}

42
vendor/rsa/tests/proptests.rs vendored Normal file
View File

@@ -0,0 +1,42 @@
//! Property-based tests.
use proptest::prelude::*;
use rand_chacha::ChaCha8Rng;
use rand_core::SeedableRng;
use rsa::{
pkcs1v15,
signature::{Keypair, SignatureEncoding, Signer, Verifier},
RsaPrivateKey,
};
use sha2::Sha256;
prop_compose! {
// WARNING: do *NOT* copy and paste this code. It's insecure and optimized for test speed.
fn private_key()(seed in any::<[u8; 32]>()) -> RsaPrivateKey {
let mut rng = ChaCha8Rng::from_seed(seed);
RsaPrivateKey::new(&mut rng, 512).unwrap()
}
}
proptest! {
#[test]
fn pkcs1v15_sign_roundtrip(private_key in private_key(), msg in any::<Vec<u8>>()) {
let signing_key = pkcs1v15::SigningKey::<Sha256>::new(private_key);
let signature_bytes = signing_key.sign(&msg).to_bytes();
let verifying_key = signing_key.verifying_key();
let signature = pkcs1v15::Signature::try_from(&*signature_bytes).unwrap();
prop_assert!(verifying_key.verify(&msg, &signature).is_ok());
}
// TODO(tarcieri): debug why these are failing
// #[test]
// fn pss_sign_roundtrip(private_key in private_key(), msg in any::<Vec<u8>>()) {
// let signing_key = pss::SigningKey::<Sha256>::new(private_key);
// let signature_bytes = signing_key.sign(&msg).to_bytes();
//
// let verifying_key = signing_key.verifying_key();
// let signature = pss::Signature::try_from(&*signature_bytes).unwrap();
// prop_assert!(verifying_key.verify(&msg, &signature).is_ok());
// }
}