Workspacify
This commit is contained in:
10
crypto/Cargo.toml
Normal file
10
crypto/Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "crypto"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
num-bigint-dig = { workspace = true }
|
||||
num-integer = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
zeroize = { workspace = true }
|
||||
24
crypto/src/known_algorithms.rs
Normal file
24
crypto/src/known_algorithms.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
pub static ALLOWED_KEY_EXCHANGE_ALGORITHMS: &[&str] = &[
|
||||
"ecdh-sha2-nistp256",
|
||||
"ecdh-sha2-nistp384",
|
||||
"ecdh-sha2-nistp521",
|
||||
"curve25519-sha256",
|
||||
];
|
||||
|
||||
pub static ALLOWED_HOST_KEY_ALGORITHMS: &[&str] = &[
|
||||
"ssh-ed25519",
|
||||
"ecdsa-sha2-nistp256",
|
||||
"ecdsa-sha2-nistp384",
|
||||
"ecdsa-sha2-nistp521",
|
||||
"ssh-rsa",
|
||||
];
|
||||
|
||||
pub static ALLOWED_ENCRYPTION_ALGORITHMS: &[&str] = &[
|
||||
"aes256-ctr",
|
||||
"aes256-gcm@openssh.com",
|
||||
"chacha20-poly1305@openssh.com",
|
||||
];
|
||||
|
||||
pub static ALLOWED_MAC_ALGORITHMS: &[&str] = &["hmac-sha2-256", "hmac-sha2-512"];
|
||||
|
||||
pub static ALLOWED_COMPRESSION_ALGORITHMS: &[&str] = &["none", "zlib"];
|
||||
272
crypto/src/lib.rs
Normal file
272
crypto/src/lib.rs
Normal file
@@ -0,0 +1,272 @@
|
||||
pub mod known_algorithms;
|
||||
pub mod rsa;
|
||||
|
||||
use std::fmt;
|
||||
use std::str::FromStr;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum KeyExchangeAlgorithm {
|
||||
EcdhSha2Nistp256,
|
||||
EcdhSha2Nistp384,
|
||||
EcdhSha2Nistp521,
|
||||
Curve25519Sha256,
|
||||
}
|
||||
|
||||
impl KeyExchangeAlgorithm {
|
||||
pub fn allowed() -> &'static [KeyExchangeAlgorithm] {
|
||||
&[
|
||||
KeyExchangeAlgorithm::EcdhSha2Nistp256,
|
||||
KeyExchangeAlgorithm::EcdhSha2Nistp384,
|
||||
KeyExchangeAlgorithm::EcdhSha2Nistp521,
|
||||
KeyExchangeAlgorithm::Curve25519Sha256,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum AlgoFromStrError {
|
||||
#[error("Did not recognize key exchange algorithm '{0}'")]
|
||||
UnknownKeyExchangeAlgorithm(String),
|
||||
#[error("Did not recognize host key algorithm '{0}'")]
|
||||
UnknownHostKeyAlgorithm(String),
|
||||
#[error("Did not recognize encryption algorithm '{0}'")]
|
||||
UnknownEncryptionAlgorithm(String),
|
||||
#[error("Did not recognize MAC algorithm '{0}'")]
|
||||
UnknownMacAlgorithm(String),
|
||||
#[error("Did not recognize compression algorithm '{0}'")]
|
||||
UnknownCompressionAlgorithm(String),
|
||||
}
|
||||
|
||||
impl FromStr for KeyExchangeAlgorithm {
|
||||
type Err = AlgoFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ecdh-sha2-nistp256" => Ok(KeyExchangeAlgorithm::EcdhSha2Nistp256),
|
||||
"ecdh-sha2-nistp384" => Ok(KeyExchangeAlgorithm::EcdhSha2Nistp384),
|
||||
"ecdh-sha2-nistp521" => Ok(KeyExchangeAlgorithm::EcdhSha2Nistp521),
|
||||
"curve25519-sha256" => Ok(KeyExchangeAlgorithm::Curve25519Sha256),
|
||||
other => Err(AlgoFromStrError::UnknownKeyExchangeAlgorithm(
|
||||
other.to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for KeyExchangeAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
KeyExchangeAlgorithm::EcdhSha2Nistp256 => write!(f, "ecdh-sha2-nistp256"),
|
||||
KeyExchangeAlgorithm::EcdhSha2Nistp384 => write!(f, "ecdh-sha2-nistp384"),
|
||||
KeyExchangeAlgorithm::EcdhSha2Nistp521 => write!(f, "ecdh-sha2-nistp521"),
|
||||
KeyExchangeAlgorithm::Curve25519Sha256 => write!(f, "curve25519-sha256"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_invert_kex_algos() {
|
||||
for variant in KeyExchangeAlgorithm::allowed().iter() {
|
||||
let s = variant.to_string();
|
||||
let reversed = KeyExchangeAlgorithm::from_str(&s);
|
||||
assert!(reversed.is_ok());
|
||||
assert_eq!(variant, &reversed.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum HostKeyAlgorithm {
|
||||
Ed25519,
|
||||
EcdsaSha2Nistp256,
|
||||
EcdsaSha2Nistp384,
|
||||
EcdsaSha2Nistp521,
|
||||
Rsa,
|
||||
}
|
||||
|
||||
impl HostKeyAlgorithm {
|
||||
pub fn allowed() -> &'static [Self] {
|
||||
&[
|
||||
HostKeyAlgorithm::Ed25519,
|
||||
HostKeyAlgorithm::EcdsaSha2Nistp256,
|
||||
HostKeyAlgorithm::EcdsaSha2Nistp384,
|
||||
HostKeyAlgorithm::EcdsaSha2Nistp521,
|
||||
HostKeyAlgorithm::Rsa,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for HostKeyAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
HostKeyAlgorithm::Ed25519 => write!(f, "ssh-ed25519"),
|
||||
HostKeyAlgorithm::EcdsaSha2Nistp256 => write!(f, "ecdsa-sha2-nistp256"),
|
||||
HostKeyAlgorithm::EcdsaSha2Nistp384 => write!(f, "ecdsa-sha2-nistp384"),
|
||||
HostKeyAlgorithm::EcdsaSha2Nistp521 => write!(f, "ecdsa-sha2-nistp521"),
|
||||
HostKeyAlgorithm::Rsa => write!(f, "ssh-rsa"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for HostKeyAlgorithm {
|
||||
type Err = AlgoFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"ssh-ed25519" => Ok(HostKeyAlgorithm::Ed25519),
|
||||
"ecdsa-sha2-nistp256" => Ok(HostKeyAlgorithm::EcdsaSha2Nistp256),
|
||||
"ecdsa-sha2-nistp384" => Ok(HostKeyAlgorithm::EcdsaSha2Nistp384),
|
||||
"ecdsa-sha2-nistp521" => Ok(HostKeyAlgorithm::EcdsaSha2Nistp521),
|
||||
"ssh-rsa" => Ok(HostKeyAlgorithm::Rsa),
|
||||
unknown => Err(AlgoFromStrError::UnknownHostKeyAlgorithm(
|
||||
unknown.to_string(),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_invert_host_key_algos() {
|
||||
for variant in HostKeyAlgorithm::allowed().iter() {
|
||||
let s = variant.to_string();
|
||||
let reversed = HostKeyAlgorithm::from_str(&s);
|
||||
assert!(reversed.is_ok());
|
||||
assert_eq!(variant, &reversed.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum EncryptionAlgorithm {
|
||||
Aes256Ctr,
|
||||
Aes256Gcm,
|
||||
ChaCha20Poly1305,
|
||||
}
|
||||
|
||||
impl EncryptionAlgorithm {
|
||||
pub fn allowed() -> &'static [Self] {
|
||||
&[
|
||||
EncryptionAlgorithm::Aes256Ctr,
|
||||
EncryptionAlgorithm::Aes256Gcm,
|
||||
EncryptionAlgorithm::ChaCha20Poly1305,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for EncryptionAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
EncryptionAlgorithm::Aes256Ctr => write!(f, "aes256-ctr"),
|
||||
EncryptionAlgorithm::Aes256Gcm => write!(f, "aes256-gcm@openssh.com"),
|
||||
EncryptionAlgorithm::ChaCha20Poly1305 => write!(f, "chacha20-poly1305@openssh.com"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for EncryptionAlgorithm {
|
||||
type Err = AlgoFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"aes256-ctr" => Ok(EncryptionAlgorithm::Aes256Ctr),
|
||||
"aes256-gcm@openssh.com" => Ok(EncryptionAlgorithm::Aes256Gcm),
|
||||
"chacha20-poly1305@openssh.com" => Ok(EncryptionAlgorithm::ChaCha20Poly1305),
|
||||
_ => Err(AlgoFromStrError::UnknownEncryptionAlgorithm(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_invert_encryption_algos() {
|
||||
for variant in EncryptionAlgorithm::allowed().iter() {
|
||||
let s = variant.to_string();
|
||||
let reversed = EncryptionAlgorithm::from_str(&s);
|
||||
assert!(reversed.is_ok());
|
||||
assert_eq!(variant, &reversed.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum MacAlgorithm {
|
||||
HmacSha256,
|
||||
HmacSha512,
|
||||
}
|
||||
|
||||
impl MacAlgorithm {
|
||||
pub fn allowed() -> &'static [Self] {
|
||||
&[MacAlgorithm::HmacSha256, MacAlgorithm::HmacSha512]
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MacAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
MacAlgorithm::HmacSha256 => write!(f, "hmac-sha2-256"),
|
||||
MacAlgorithm::HmacSha512 => write!(f, "hmac-sha2-512"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for MacAlgorithm {
|
||||
type Err = AlgoFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"hmac-sha2-256" => Ok(MacAlgorithm::HmacSha256),
|
||||
"hmac-sha2-512" => Ok(MacAlgorithm::HmacSha512),
|
||||
_ => Err(AlgoFromStrError::UnknownMacAlgorithm(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_invert_mac_algos() {
|
||||
for variant in MacAlgorithm::allowed().iter() {
|
||||
let s = variant.to_string();
|
||||
let reversed = MacAlgorithm::from_str(&s);
|
||||
assert!(reversed.is_ok());
|
||||
assert_eq!(variant, &reversed.unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum CompressionAlgorithm {
|
||||
None,
|
||||
Zlib,
|
||||
}
|
||||
|
||||
impl CompressionAlgorithm {
|
||||
pub fn allowed() -> &'static [Self] {
|
||||
&[CompressionAlgorithm::None, CompressionAlgorithm::Zlib]
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CompressionAlgorithm {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
CompressionAlgorithm::None => write!(f, "none"),
|
||||
CompressionAlgorithm::Zlib => write!(f, "zlib"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for CompressionAlgorithm {
|
||||
type Err = AlgoFromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"none" => Ok(CompressionAlgorithm::None),
|
||||
"zlib" => Ok(CompressionAlgorithm::Zlib),
|
||||
_ => Err(AlgoFromStrError::UnknownCompressionAlgorithm(s.to_string())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_invert_compression_algos() {
|
||||
for variant in CompressionAlgorithm::allowed().iter() {
|
||||
let s = variant.to_string();
|
||||
let reversed = CompressionAlgorithm::from_str(&s);
|
||||
assert!(reversed.is_ok());
|
||||
assert_eq!(variant, &reversed.unwrap());
|
||||
}
|
||||
}
|
||||
251
crypto/src/rsa.rs
Normal file
251
crypto/src/rsa.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use num_bigint_dig::{BigInt, BigUint, ModInverse};
|
||||
use num_integer::{sqrt, Integer};
|
||||
use num_traits::Pow;
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
|
||||
/// An RSA public key
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct PublicKey {
|
||||
/// The public modulus, the product of the primes 'p' and 'q'
|
||||
n: BigUint,
|
||||
/// The public exponent.
|
||||
e: BigUint,
|
||||
}
|
||||
|
||||
/// An RSA private key
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
pub struct PrivateKey {
|
||||
/// The public modulus, the product of the primes 'p' and 'q'
|
||||
n: BigUint,
|
||||
/// The public exponent
|
||||
e: BigUint,
|
||||
/// The private exponent
|
||||
d: BigUint,
|
||||
/// The prime 'p'
|
||||
p: BigUint,
|
||||
/// The prime 'q'
|
||||
q: BigUint,
|
||||
/// d mod (p-1)
|
||||
dmodp1: BigUint,
|
||||
/// d mod (q-1)
|
||||
dmodq1: BigUint,
|
||||
/// q^-1 mod P
|
||||
qinv: BigInt,
|
||||
}
|
||||
|
||||
impl Drop for PrivateKey {
|
||||
fn drop(&mut self) {
|
||||
self.d.zeroize();
|
||||
self.p.zeroize();
|
||||
self.q.zeroize();
|
||||
self.dmodp1.zeroize();
|
||||
self.dmodq1.zeroize();
|
||||
self.qinv.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl PublicKey {
|
||||
/// Generate a public key from the given input values.
|
||||
///
|
||||
/// No checking is performed at this point to ensure that these
|
||||
/// values are sane in any way.
|
||||
pub fn new(n: BigUint, e: BigUint) -> Self {
|
||||
PublicKey { n, e }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum PrivateKeyLoadError {
|
||||
#[error("Invalid value for public 'e' value; must be between 2^16 and 2^256, got {0}")]
|
||||
InvalidEValue(BigUint),
|
||||
#[error("Could not recover primes 'p' and 'q' from provided private key data")]
|
||||
CouldNotRecoverPrimes,
|
||||
#[error("Could not generate modular inverse of 'q' in provided private key data")]
|
||||
CouldNotGenerateModInv,
|
||||
#[error("Could not cross-confirm value '{value}' in provided private key data")]
|
||||
IncoherentValue { value: &'static str },
|
||||
}
|
||||
|
||||
impl PrivateKey {
|
||||
/// Generate a private key from the associated public key and the private
|
||||
/// value 'd'.
|
||||
///
|
||||
/// This will do some further computations, and should not be called when
|
||||
/// you absolutely must get an answer back immediately. Or, to put it
|
||||
/// another way, you really should call this with `block_in_place` or
|
||||
/// similar in an async context.
|
||||
pub fn from_d(public: &PublicKey, d: BigUint) -> Result<Self, PrivateKeyLoadError> {
|
||||
let (p, q) = recover_primes(&public.n, &public.e, &d)?;
|
||||
let dmodp1 = &d % (&p - 1u64);
|
||||
let dmodq1 = &d % (&q - 1u64);
|
||||
let qinv = (&q)
|
||||
.mod_inverse(&p)
|
||||
.ok_or(PrivateKeyLoadError::CouldNotGenerateModInv)?;
|
||||
|
||||
Ok(PrivateKey {
|
||||
n: public.n.clone(),
|
||||
e: public.e.clone(),
|
||||
d,
|
||||
p,
|
||||
q,
|
||||
dmodp1,
|
||||
dmodq1,
|
||||
qinv,
|
||||
})
|
||||
}
|
||||
|
||||
/// Generate a private key from the associated public key, the private
|
||||
/// value 'd', and several other useful values.
|
||||
///
|
||||
/// This will do some additional computations, and should not be called
|
||||
/// when you absolutely must get an answer back immediately. Or, to put
|
||||
/// it another way, you really should call this with `block_in_place` or
|
||||
/// similar.
|
||||
///
|
||||
/// This version of this function performs some safety checking to ensure
|
||||
/// the provided values are reasonable. To avoid this cost, but at the
|
||||
/// risk of accepting bad key data, use the `_unchecked` variant.
|
||||
pub fn from_parts(
|
||||
public: &PublicKey,
|
||||
d: BigUint,
|
||||
qinv: BigInt,
|
||||
p: BigUint,
|
||||
q: BigUint,
|
||||
) -> Result<Self, PrivateKeyLoadError> {
|
||||
let computed_private = Self::from_d(public, d)?;
|
||||
|
||||
if qinv != computed_private.qinv {
|
||||
return Err(PrivateKeyLoadError::IncoherentValue { value: "qinv" });
|
||||
}
|
||||
|
||||
if p != computed_private.p {
|
||||
return Err(PrivateKeyLoadError::IncoherentValue { value: "p" });
|
||||
}
|
||||
|
||||
if q != computed_private.q {
|
||||
return Err(PrivateKeyLoadError::IncoherentValue { value: "q" });
|
||||
}
|
||||
|
||||
Ok(computed_private)
|
||||
}
|
||||
|
||||
/// Generate a private key from the associated public key, the private
|
||||
/// value 'd', and several other useful values.
|
||||
///
|
||||
/// This will do some additional computations, and should not be called
|
||||
/// when you absolutely must get an answer back immediately. Or, to put
|
||||
/// it another way, you really should call this with `block_in_place` or
|
||||
/// similar.
|
||||
///
|
||||
/// This version of this function performs no safety checking to ensure
|
||||
/// the provided values are reasonable.
|
||||
pub fn from_parts_unchecked(
|
||||
public: &PublicKey,
|
||||
d: BigUint,
|
||||
qinv: BigInt,
|
||||
p: BigUint,
|
||||
q: BigUint,
|
||||
) -> Result<Self, PrivateKeyLoadError> {
|
||||
let dmodp1 = &d % (&p - 1u64);
|
||||
let dmodq1 = &d % (&q - 1u64);
|
||||
|
||||
Ok(PrivateKey {
|
||||
n: public.n.clone(),
|
||||
e: public.e.clone(),
|
||||
d,
|
||||
qinv,
|
||||
p,
|
||||
q,
|
||||
dmodp1,
|
||||
dmodq1,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Recover the two primes, `p` and `q`, used to generate the given private
|
||||
/// key.
|
||||
///
|
||||
/// This algorithm is as straightforward an implementation of Appendix C.1
|
||||
/// of NIST 800-56b, revision 2, as I could make it.
|
||||
fn recover_primes(
|
||||
n: &BigUint,
|
||||
e: &BigUint,
|
||||
d: &BigUint,
|
||||
) -> Result<(BigUint, BigUint), PrivateKeyLoadError> {
|
||||
// Assumptions:
|
||||
// 1. The modulus n is the product of two prime factors p and q, with p > q.
|
||||
// 2. Both p and q are less than 2^(nBits/2), where nBits ≥ 2048 is the bit length of n.
|
||||
let n_bits = n.bits() * 8;
|
||||
let max_p_or_q = BigUint::from(2u8).pow(n_bits / 2);
|
||||
// 3. The public exponent e is an odd integer between 2^16 and 2^256.
|
||||
let two = BigUint::from(2u64);
|
||||
if e < &two.pow(16u64) || e > &two.pow(256u64) {
|
||||
return Err(PrivateKeyLoadError::InvalidEValue(e.clone()));
|
||||
}
|
||||
// 4. The private exponent d is a positive integer that is less than λ(n) = LCM(p – 1, q – 1).
|
||||
// 5. The exponents e and d satisfy de ≡ 1 (mod λ(n)).
|
||||
|
||||
// Implementation:
|
||||
// 1. Let a = (de – 1) × GCD(n – 1, de – 1).
|
||||
let mut de_minus_1 = Zeroizing::new(d * e);
|
||||
*de_minus_1 -= 1u64;
|
||||
let n_minus_one = Zeroizing::new(n - 1u64);
|
||||
let gcd_of_n1_and_de1 = Zeroizing::new(n_minus_one.gcd(&de_minus_1));
|
||||
let a = Zeroizing::new(&*de_minus_1 * &*gcd_of_n1_and_de1);
|
||||
// 2. Let m = a/n and r = a – mn, so that a = mn + r and 0 ≤ r < n.
|
||||
let m = Zeroizing::new(&*a / n);
|
||||
let mn = Zeroizing::new(&*m * n);
|
||||
if *mn > *a {
|
||||
// if mn is greater than 'a', then 'r' is going to be negative, which
|
||||
// violates our assumptions.
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
let r = Zeroizing::new(&*a - (&*m * n));
|
||||
if &*r >= n {
|
||||
// this violates the other side condition of 2
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
// 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 b = Zeroizing::new(((n - &*r) / (&*m + 1u64)) + 1u64);
|
||||
let b_squared = Zeroizing::new(&*b * &*b);
|
||||
// 4n contains no secret information, actually, so no need to add the zeorize trait
|
||||
let four_n = 4usize * n;
|
||||
if *b_squared <= four_n {
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
// 4. Let ϒ be the positive square root of b2 – 4n; if ϒ is not an integer, then output
|
||||
// an error indicator, and exit without further processing.
|
||||
let b_squared_minus_four_n = Zeroizing::new(&*b_squared - four_n);
|
||||
let y = Zeroizing::new(sqrt((*b_squared_minus_four_n).clone()));
|
||||
let cross_check = Zeroizing::new(&*y * &*y);
|
||||
if cross_check != b_squared_minus_four_n {
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
// 5. Let p = (b + ϒ)/2 and let q = (b – ϒ)/2.
|
||||
let mut p = &*b + &*y;
|
||||
p >>= 1;
|
||||
let mut q = &*b - &*y;
|
||||
q >>= 1;
|
||||
// go back and check some of our assumptions from above:
|
||||
// 1. The modulus n is the product of two prime factors p and q, with p > q.
|
||||
if n != &(&p * &q) {
|
||||
p.zeroize();
|
||||
q.zeroize();
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
if p <= q {
|
||||
p.zeroize();
|
||||
q.zeroize();
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
// 2. Both p and q are less than 2^(nBits/2), where nBits ≥ 2048 is the bit length of n.
|
||||
if p >= max_p_or_q || q >= max_p_or_q {
|
||||
p.zeroize();
|
||||
q.zeroize();
|
||||
return Err(PrivateKeyLoadError::CouldNotRecoverPrimes);
|
||||
}
|
||||
|
||||
// 6. Output (p, q) as the prime factors.
|
||||
Ok((p, q))
|
||||
}
|
||||
Reference in New Issue
Block a user