Clean up the struct/trait split for RSA keys.

This commit is contained in:
2019-04-13 16:41:41 -07:00
parent 026b321f7c
commit 40a5793089
4 changed files with 191 additions and 219 deletions

View File

@@ -1,7 +1,21 @@
use cryptonum::unsigned::*;
use num::bigint::BigUint; use num::bigint::BigUint;
use rsa::errors::RSAError; use rsa::errors::RSAError;
use simple_asn1::{ASN1Block,ASN1DecodeErr}; use simple_asn1::{ASN1Block,ASN1DecodeErr};
pub trait RSAMode {
type Barrett;
}
impl RSAMode for U512 { type Barrett = BarrettU512; }
impl RSAMode for U1024 { type Barrett = BarrettU1024; }
impl RSAMode for U2048 { type Barrett = BarrettU2048; }
impl RSAMode for U3072 { type Barrett = BarrettU3072; }
impl RSAMode for U4096 { type Barrett = BarrettU4096; }
impl RSAMode for U8192 { type Barrett = BarrettU8192; }
impl RSAMode for U15360 { type Barrett = BarrettU15360; }
pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8> pub fn pkcs1_pad(ident: &[u8], hash: &[u8], keylen: usize) -> Vec<u8>
{ {
let mut idhash = Vec::new(); let mut idhash = Vec::new();

View File

@@ -24,6 +24,7 @@ mod private;
mod public; mod public;
mod signing_hashes; mod signing_hashes;
pub use self::core::RSAMode;
pub use self::errors::RSAError; pub use self::errors::RSAError;
pub use self::signing_hashes::{SigningHash, pub use self::signing_hashes::{SigningHash,
SIGNING_HASH_NULL, SIGNING_HASH_NULL,
@@ -33,15 +34,8 @@ pub use self::signing_hashes::{SigningHash,
SIGNING_HASH_SHA384, SIGNING_HASH_SHA384,
SIGNING_HASH_SHA512}; SIGNING_HASH_SHA512};
pub use self::oaep::OAEPParams; pub use self::oaep::OAEPParams;
pub use self::private::{RSAPrivate, RSAPrivateKey, pub use self::private::{RSAPrivate, RSAPrivateKey};
RSA512Private, RSA1024Private, RSA2048Private, pub use self::public::{RSAPublic, RSAPublicKey};
RSA3072Private, RSA4096Private, RSA8192Private,
RSA15360Private};
pub use self::public::{RSAPublic, RSAPublicKey,
RSA512Public, RSA1024Public, RSA2048Public,
RSA3072Public, RSA4096Public, RSA8192Public,
RSA15360Public};
use cryptonum::signed::{EGCD,ModInv}; use cryptonum::signed::{EGCD,ModInv};
use cryptonum::unsigned::{CryptoNum,PrimeGen}; use cryptonum::unsigned::{CryptoNum,PrimeGen};
use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360}; use cryptonum::unsigned::{U256,U512,U1024,U1536,U2048,U3072,U4096,U7680,U8192,U15360};
@@ -60,38 +54,38 @@ fn diff<T>(a: &T, b: &T) -> T
} }
} }
pub struct RSAKeyPair<R: RSAMode> {
pub public: RSAPublicKey<R>,
pub private: RSAPrivateKey<R>
}
macro_rules! generate_rsa_pair macro_rules! generate_rsa_pair
{ {
($pair: ident, $pub: ident, $priv: ident, $uint: ident, $half: ident, $iterations: expr) => { ($uint: ident, $half: ident, $iterations: expr) => {
pub struct $pair { impl RSAKeyPair<$uint> {
pub public: $pub, pub fn new(pu: RSAPublicKey<$uint>, pr: RSAPrivateKey<$uint>) -> RSAKeyPair<$uint> {
pub private: $priv RSAKeyPair {
}
impl $pair {
pub fn new(pu: $pub, pr: $priv) -> $pair {
$pair {
public: pu, public: pu,
private: pr private: pr
} }
} }
pub fn generate<G>(rng: &mut G) -> $pair pub fn generate<G>(rng: &mut G) -> RSAKeyPair<$uint>
where G: RngCore where G: RngCore
{ {
loop { loop {
let ebase = 65537u32; let ebase = 65537u32;
let e = $uint::from(ebase); let e = $uint::from(ebase);
let (p, q) = $pair::generate_pq(rng, &$half::from(ebase)); let (p, q) = RSAKeyPair::<$uint>::generate_pq(rng, &$half::from(ebase));
let one = $half::from(1u32); let one = $half::from(1u32);
let pminus1 = &p - &one; let pminus1 = &p - &one;
let qminus1 = &q - &one; let qminus1 = &q - &one;
let phi = pminus1 * qminus1; let phi = pminus1 * qminus1;
let n = &p * &q; let n = &p * &q;
if let Some(d) = e.modinv(&phi) { if let Some(d) = e.modinv(&phi) {
let public = $pub::new(n.clone(), e); let public = RSAPublicKey::<$uint>::new(n.clone(), e);
let private = $priv::new(n, d); let private = RSAPrivateKey::<$uint>::new(n, d);
return $pair::new(public, private); return RSAKeyPair::<$uint>::new(public, private);
} }
} }
} }
@@ -129,13 +123,13 @@ macro_rules! generate_rsa_pair
} }
} }
generate_rsa_pair!(RSA512KeyPair, RSA512Public, RSA512Private, U512, U256, 7); generate_rsa_pair!(U512, U256, 7);
generate_rsa_pair!(RSA1024KeyPair, RSA1024Public, RSA1024Private, U1024, U512, 7); generate_rsa_pair!(U1024, U512, 7);
generate_rsa_pair!(RSA2048KeyPair, RSA2048Public, RSA2048Private, U2048, U1024, 4); generate_rsa_pair!(U2048, U1024, 4);
generate_rsa_pair!(RSA3072KeyPair, RSA3072Public, RSA3072Private, U3072, U1536, 3); generate_rsa_pair!(U3072, U1536, 3);
generate_rsa_pair!(RSA4096KeyPair, RSA4096Public, RSA4096Private, U4096, U2048, 3); generate_rsa_pair!(U4096, U2048, 3);
generate_rsa_pair!(RSA8192KeyPair, RSA8192Public, RSA8192Private, U8192, U4096, 3); generate_rsa_pair!(U8192, U4096, 3);
generate_rsa_pair!(RSA15360KeyPair, RSA15360Public, RSA15360Private, U15360, U7680, 3); generate_rsa_pair!(U15360, U7680, 3);
#[cfg(test)] #[cfg(test)]
mod generation { mod generation {
@@ -143,15 +137,15 @@ mod generation {
use std::fmt; use std::fmt;
use super::*; use super::*;
impl Clone for RSA512KeyPair { impl Clone for RSAKeyPair<U512> {
fn clone(&self) -> RSA512KeyPair { fn clone(&self) -> RSAKeyPair<U512> {
RSA512KeyPair{ RSAKeyPair {
public: RSA512Public { public: RSAPublicKey {
n: self.public.n.clone(), n: self.public.n.clone(),
nu: self.public.nu.clone(), nu: self.public.nu.clone(),
e: self.public.e.clone(), e: self.public.e.clone(),
}, },
private: RSA512Private { private: RSAPrivateKey {
nu: self.private.nu.clone(), nu: self.private.nu.clone(),
d: self.private.d.clone() d: self.private.d.clone()
} }
@@ -159,7 +153,7 @@ mod generation {
} }
} }
impl fmt::Debug for RSA512KeyPair { impl fmt::Debug for RSAKeyPair<U512> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("RSA512KeyPair") f.debug_struct("RSA512KeyPair")
.field("n", &self.public.n) .field("n", &self.public.n)
@@ -169,14 +163,14 @@ mod generation {
} }
} }
impl Arbitrary for RSA512KeyPair { impl Arbitrary for RSAKeyPair<U512> {
fn arbitrary<G: Gen>(g: &mut G) -> RSA512KeyPair { fn arbitrary<G: Gen>(g: &mut G) -> RSAKeyPair<U512> {
RSA512KeyPair::generate(g) RSAKeyPair::<U512>::generate(g)
} }
} }
quickcheck! { quickcheck! {
fn generate_and_sign(keypair: RSA512KeyPair, msg: Vec<u8>) -> bool { fn generate_and_sign(keypair: RSAKeyPair<U512>, msg: Vec<u8>) -> bool {
let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg); let sig = keypair.private.sign(&SIGNING_HASH_SHA256, &msg);
keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig) keypair.public.verify(&SIGNING_HASH_SHA256, &msg, &sig)
} }

View File

@@ -1,56 +1,36 @@
use cryptonum::unsigned::*; use cryptonum::unsigned::*;
use digest::{Digest,FixedOutput}; use digest::{Digest,FixedOutput};
use rsa::core::{drop0s,pkcs1_pad,xor_vecs}; use rsa::core::{RSAMode,drop0s,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError; use rsa::errors::RSAError;
use rsa::oaep::OAEPParams; use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash; use rsa::signing_hashes::SigningHash;
pub trait RSAPrivateKey<N> { pub struct RSAPrivateKey<R: RSAMode>
/// Generate a new private key using the given modulus and private {
/// exponent. You probably don't want to use this function directly pub(crate) nu: R::Barrett,
/// unless you're writing your own key generation routine or key pub(crate) d: R
/// parsing library.
fn new(n: N, d: N) -> Self;
/// Sign the given message with the given private key.
fn sign(&self, signhash: &SigningHash, msg: &[u8]) -> Vec<u8>;
/// Decrypt the provided message using the given OAEP parameters. As
/// mentioned in the comment for encryption, RSA decryption is really,
/// really slow. So if your plaintext is larger than about half the
/// bit size of the key, it's almost certainly a better idea to generate
/// a fresh symmetric encryption key, encrypt only the key with RSA, and
/// then encrypt the message with that key.
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where H: Default + Digest + FixedOutput;
} }
pub enum RSAPrivate { pub enum RSAPrivate {
Key512(RSA512Private), Key512(RSAPrivateKey<U512>),
Key1024(RSA1024Private), Key1024(RSAPrivateKey<U1024>),
Key2048(RSA2048Private), Key2048(RSAPrivateKey<U2048>),
Key3072(RSA3072Private), Key3072(RSAPrivateKey<U3072>),
Key4096(RSA4096Private), Key4096(RSAPrivateKey<U4096>),
Key8192(RSA8192Private), Key8192(RSAPrivateKey<U8192>),
Key15360(RSA15360Private) Key15360(RSAPrivateKey<U15360>)
} }
macro_rules! generate_rsa_private macro_rules! generate_rsa_private
{ {
($rsa: ident, $num: ident, $bar: ident, $size: expr) => { ($num: ident, $bar: ident, $size: expr) => {
pub struct $rsa { impl RSAPrivateKey<$num> {
pub(crate) nu: $bar, pub fn new(n: $num, d: $num) -> RSAPrivateKey<$num> {
pub(crate) d: $num
}
impl RSAPrivateKey<$num> for $rsa {
fn new(n: $num, d: $num) -> $rsa {
let nu = $bar::new(n.clone()); let nu = $bar::new(n.clone());
$rsa { nu: nu, d: d } RSAPrivateKey{ nu: nu, d: d }
} }
fn sign(&self, signhash: &SigningHash, msg: &[u8]) pub fn sign(&self, signhash: &SigningHash, msg: &[u8])
-> Vec<u8> -> Vec<u8>
{ {
let hash = (signhash.run)(msg); let hash = (signhash.run)(msg);
@@ -61,7 +41,7 @@ macro_rules! generate_rsa_private
sig sig
} }
fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8]) pub fn decrypt<H>(&self, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where H: Default + Digest + FixedOutput where H: Default + Digest + FixedOutput
{ {
@@ -74,9 +54,7 @@ macro_rules! generate_rsa_private
Ok(res) Ok(res)
} }
}
impl $rsa {
fn sp1(&self, m: &$num) -> $num { fn sp1(&self, m: &$num) -> $num {
m.modexp(&self.d, &self.nu) m.modexp(&self.d, &self.nu)
} }
@@ -139,17 +117,17 @@ macro_rules! generate_rsa_private
} }
} }
generate_rsa_private!(RSA512Private, U512, BarrettU512, 512); generate_rsa_private!(U512, BarrettU512, 512);
generate_rsa_private!(RSA1024Private, U1024, BarrettU1024, 1024); generate_rsa_private!(U1024, BarrettU1024, 1024);
generate_rsa_private!(RSA2048Private, U2048, BarrettU2048, 2048); generate_rsa_private!(U2048, BarrettU2048, 2048);
generate_rsa_private!(RSA3072Private, U3072, BarrettU3072, 3072); generate_rsa_private!(U3072, BarrettU3072, 3072);
generate_rsa_private!(RSA4096Private, U4096, BarrettU4096, 4096); generate_rsa_private!(U4096, BarrettU4096, 4096);
generate_rsa_private!(RSA8192Private, U8192, BarrettU8192, 8192); generate_rsa_private!(U8192, BarrettU8192, 8192);
generate_rsa_private!(RSA15360Private, U15360, BarrettU15360, 15360); generate_rsa_private!(U15360, BarrettU15360, 15360);
#[cfg(test)] #[cfg(test)]
macro_rules! sign_test_body { macro_rules! sign_test_body {
($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size); let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| { run_test(fname.to_string(), 7, |case| {
let (neg0, dbytes) = case.get("d").unwrap(); let (neg0, dbytes) = case.get("d").unwrap();
@@ -173,7 +151,7 @@ macro_rules! sign_test_body {
512 => &SIGNING_HASH_SHA512, 512 => &SIGNING_HASH_SHA512,
x => panic!("Bad signing hash: {}", x) x => panic!("Bad signing hash: {}", x)
}; };
let privkey = $rsa{ nu: $bar::from_components(k, n.clone(), nu), d: d }; let privkey = RSAPrivateKey{ nu: $bar::from_components(k, n.clone(), nu), d: d };
let sig = privkey.sign(sighash, &mbytes); let sig = privkey.sign(sighash, &mbytes);
assert_eq!(*sbytes, sig); assert_eq!(*sbytes, sig);
}); });
@@ -182,7 +160,7 @@ macro_rules! sign_test_body {
#[cfg(test)] #[cfg(test)]
macro_rules! decrypt_test_body { macro_rules! decrypt_test_body {
($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/encrypt{}.test", $size); let fname = format!("testdata/rsa/encrypt{}.test", $size);
run_test(fname.to_string(), 9, |case| { run_test(fname.to_string(), 9, |case| {
let (neg0, nbytes) = case.get("n").unwrap(); let (neg0, nbytes) = case.get("n").unwrap();
@@ -203,7 +181,7 @@ macro_rules! decrypt_test_body {
let k = usize::from(bigk); let k = usize::from(bigk);
let d = $num::from_bytes(dbytes); let d = $num::from_bytes(dbytes);
let nu = $bar::from_components(k, n64, nu); let nu = $bar::from_components(k, n64, nu);
let privkey = $rsa{ nu: nu, d: d }; let privkey = RSAPrivateKey{ nu: nu, d: d };
let lstr = String::from_utf8(lbytes.clone()).unwrap(); let lstr = String::from_utf8(lbytes.clone()).unwrap();
let message = match usize::from($num::from_bytes(hbytes)) { let message = match usize::from($num::from_bytes(hbytes)) {
224 => privkey.decrypt(&OAEPParams::<Sha224>::new(lstr), &cbytes), 224 => privkey.decrypt(&OAEPParams::<Sha224>::new(lstr), &cbytes),
@@ -219,7 +197,7 @@ macro_rules! decrypt_test_body {
} }
macro_rules! generate_tests { macro_rules! generate_tests {
($mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)] #[cfg(test)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod $mod { mod $mod {
@@ -231,16 +209,16 @@ macro_rules! generate_tests {
#[test] #[test]
fn sign() { fn sign() {
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size); sign_test_body!($mod, $num, $bar, $num64, $size);
} }
#[test] #[test]
fn decrypt() { fn decrypt() {
decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size); decrypt_test_body!($mod, $num, $bar, $num64, $size);
} }
} }
}; };
(ignore $mod: ident, $rsa: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { (ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)] #[cfg(test)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod $mod { mod $mod {
@@ -253,22 +231,22 @@ macro_rules! generate_tests {
#[ignore] #[ignore]
#[test] #[test]
fn sign() { fn sign() {
sign_test_body!($mod, $rsa, $num, $bar, $num64, $size); sign_test_body!($mod, $num, $bar, $num64, $size);
} }
#[ignore] #[ignore]
#[test] #[test]
fn decrypt() { fn decrypt() {
decrypt_test_body!($mod, $rsa, $num, $bar, $num64, $size); decrypt_test_body!($mod, $num, $bar, $num64, $size);
} }
} }
} }
} }
generate_tests!(RSA512, RSA512Private, U512, BarrettU512, U576, 512); generate_tests!( RSA512, U512, BarrettU512, U576, 512);
generate_tests!(RSA1024, RSA1024Private, U1024, BarrettU1024, U1088, 1024); generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
generate_tests!(RSA2048, RSA2048Private, U2048, BarrettU2048, U2112, 2048); generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
generate_tests!(RSA3072, RSA3072Private, U3072, BarrettU3072, U3136, 3072); generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
generate_tests!(RSA4096, RSA4096Private, U4096, BarrettU4096, U4160, 4096); generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
generate_tests!(ignore RSA8192, RSA8192Private, U8192, BarrettU8192, U8256, 8192); generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
generate_tests!(ignore RSA15360, RSA15360Private, U15360, BarrettU15360, U15424, 15360); generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);

View File

@@ -2,7 +2,7 @@ use cryptonum::unsigned::*;
use digest::{Digest,FixedOutput}; use digest::{Digest,FixedOutput};
use rand::Rng; use rand::Rng;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use rsa::core::{decode_biguint,pkcs1_pad,xor_vecs}; use rsa::core::{RSAMode,decode_biguint,pkcs1_pad,xor_vecs};
use rsa::errors::RSAError; use rsa::errors::RSAError;
use rsa::oaep::OAEPParams; use rsa::oaep::OAEPParams;
use rsa::signing_hashes::SigningHash; use rsa::signing_hashes::SigningHash;
@@ -12,62 +12,21 @@ use simple_asn1::{ASN1Block,ASN1DecodeErr,ASN1EncodeErr,
use std::fmt; use std::fmt;
use utils::TranslateNums; use utils::TranslateNums;
pub trait RSAPublicKey<N> { #[derive(PartialEq)]
/// Generate a new public key pair for the given modulus and pub struct RSAPublicKey<R: RSAMode> {
/// exponent. You should probably not call this directly unless pub(crate) n: R,
/// you're writing a key generation function or writing your own pub(crate) nu: R::Barrett,
/// public key parser. pub(crate) e: R
fn new(n: N, e: N) -> Self;
/// Verify that the provided signature is valid; that the private
/// key associated with this public key sent exactly this message.
/// The hash used here must exactly match the hash used to sign
/// the message, including its ASN.1 metadata.
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) -> bool;
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// In this variant of the function, we use an explicit random number
/// generator, just in case you have one you really like. It better be
/// cryptographically strong, though, as some of the padding protections
/// are relying on it.
fn encrypt_rng<G,H>(&self, g: &mut G, oaep: &OAEPParams<H>, msg: &[u8])
-> Result<Vec<u8>,RSAError>
where
G: Rng,
H: Default + Digest + FixedOutput;
/// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// This variant will just use the system RNG for its randomness.
fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Digest + FixedOutput
{
let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg)
}
} }
pub enum RSAPublic { pub enum RSAPublic {
Key512(RSA512Public), Key512( RSAPublicKey<U512>),
Key1024(RSA1024Public), Key1024( RSAPublicKey<U1024>),
Key2048(RSA2048Public), Key2048( RSAPublicKey<U2048>),
Key3072(RSA3072Public), Key3072( RSAPublicKey<U3072>),
Key4096(RSA4096Public), Key4096( RSAPublicKey<U4096>),
Key8192(RSA8192Public), Key8192( RSAPublicKey<U8192>),
Key15360(RSA15360Public) Key15360(RSAPublicKey<U15360>)
} }
impl RSAPublic { impl RSAPublic {
@@ -109,43 +68,43 @@ impl FromASN1 for RSAPublic {
512 => { 512 => {
let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U512::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U512::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA512Public::new(n2, e2); let res = RSAPublicKey::<U512>::new(n2, e2);
Ok((RSAPublic::Key512(res), rest)) Ok((RSAPublic::Key512(res), rest))
} }
1024 => { 1024 => {
let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U1024::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U1024::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA1024Public::new(n2, e2); let res = RSAPublicKey::<U1024>::new(n2, e2);
Ok((RSAPublic::Key1024(res), rest)) Ok((RSAPublic::Key1024(res), rest))
} }
2048 => { 2048 => {
let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U2048::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U2048::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA2048Public::new(n2, e2); let res = RSAPublicKey::<U2048>::new(n2, e2);
Ok((RSAPublic::Key2048(res), rest)) Ok((RSAPublic::Key2048(res), rest))
} }
3072 => { 3072 => {
let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U3072::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U3072::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA3072Public::new(n2, e2); let res = RSAPublicKey::<U3072>::new(n2, e2);
Ok((RSAPublic::Key3072(res), rest)) Ok((RSAPublic::Key3072(res), rest))
} }
4096 => { 4096 => {
let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U4096::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U4096::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA4096Public::new(n2, e2); let res = RSAPublicKey::<U4096>::new(n2, e2);
Ok((RSAPublic::Key4096(res), rest)) Ok((RSAPublic::Key4096(res), rest))
} }
8192 => { 8192 => {
let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U8192::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U8192::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA8192Public::new(n2, e2); let res = RSAPublicKey::<U8192>::new(n2, e2);
Ok((RSAPublic::Key8192(res), rest)) Ok((RSAPublic::Key8192(res), rest))
} }
15360 => { 15360 => {
let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?; let n2 = U15360::from_num(&n).ok_or(RSAError::InvalidKey)?;
let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?; let e2 = U15360::from_num(&e).ok_or(RSAError::InvalidKey)?;
let res = RSA15360Public::new(n2, e2); let res = RSAPublicKey::<U15360>::new(n2, e2);
Ok((RSAPublic::Key15360(res), rest)) Ok((RSAPublic::Key15360(res), rest))
} }
_ => _ =>
@@ -178,21 +137,22 @@ impl ToASN1 for RSAPublic {
macro_rules! generate_rsa_public macro_rules! generate_rsa_public
{ {
($rsa: ident, $num: ident, $bar: ident, $var: ident, $size: expr) => { ($num: ident, $bar: ident, $var: ident, $size: expr) => {
#[derive(PartialEq)] impl RSAPublicKey<$num> {
pub struct $rsa { /// Generate a new public key pair for the given modulus and
pub(crate) n: $num, /// exponent. You should probably not call this directly unless
pub(crate) nu: $bar, /// you're writing a key generation function or writing your own
pub(crate) e: $num /// public key parser.
} pub fn new(n: $num, e: $num) -> RSAPublicKey<$num> {
impl RSAPublicKey<$num> for $rsa {
fn new(n: $num, e: $num) -> $rsa {
let nu = $bar::new(n.clone()); let nu = $bar::new(n.clone());
$rsa { n: n, nu: nu, e: e } RSAPublicKey{ n: n, nu: nu, e: e }
} }
fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8]) /// Verify that the provided signature is valid; that the private
/// key associated with this public key sent exactly this message.
/// The hash used here must exactly match the hash used to sign
/// the message, including its ASN.1 metadata.
pub fn verify(&self, signhash: &SigningHash, msg: &[u8], sig: &[u8])
-> bool -> bool
{ {
let hash: Vec<u8> = (signhash.run)(msg); let hash: Vec<u8> = (signhash.run)(msg);
@@ -203,7 +163,18 @@ macro_rules! generate_rsa_public
em == em_ em == em_
} }
fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8]) /// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// In this variant of the function, we use an explicit random number
/// generator, just in case you have one you really like. It better be
/// cryptographically strong, though, as some of the padding protections
/// are relying on it.
pub fn encrypt_rng<G,H>(&self,g: &mut G,oaep: &OAEPParams<H>,msg: &[u8])
-> Result<Vec<u8>,RSAError> -> Result<Vec<u8>,RSAError>
where where
G: Rng, G: Rng,
@@ -222,9 +193,24 @@ macro_rules! generate_rsa_public
Ok(res) Ok(res)
} }
}
impl $rsa { /// Encrypt the message with a hash function, given the appropriate
/// label. Please note that RSA encryption is not particularly fast,
/// and decryption is very slow indeed. Thus, most crypto systems that
/// need asymmetric encryption should generate a symmetric key, encrypt
/// that key with RSA encryption, and then encrypt the actual message
/// with that symmetric key.
///
/// This variant will just use the system RNG for its randomness.
pub fn encrypt<H>(&self,oaep:&OAEPParams<H>,msg:&[u8])
-> Result<Vec<u8>,RSAError>
where
H: Default + Digest + FixedOutput
{
let mut g = OsRng::new()?;
self.encrypt_rng(&mut g, oaep, msg)
}
fn vp1(&self, s: &$num) -> $num { fn vp1(&self, s: &$num) -> $num {
s.modexp(&self.e, &self.nu) s.modexp(&self.e, &self.nu)
} }
@@ -283,11 +269,11 @@ macro_rules! generate_rsa_public
} }
} }
impl FromASN1 for $rsa { impl FromASN1 for RSAPublicKey<$num> {
type Error = RSAError; type Error = RSAError;
fn from_asn1(bs: &[ASN1Block]) fn from_asn1(bs: &[ASN1Block])
-> Result<($rsa,&[ASN1Block]),RSAError> -> Result<(RSAPublicKey<$num>,&[ASN1Block]),RSAError>
{ {
let (core, rest) = RSAPublic::from_asn1(bs)?; let (core, rest) = RSAPublic::from_asn1(bs)?;
@@ -298,7 +284,7 @@ macro_rules! generate_rsa_public
} }
} }
impl ToASN1 for $rsa { impl ToASN1 for RSAPublicKey<$num> {
type Error = ASN1EncodeErr; type Error = ASN1EncodeErr;
fn to_asn1_class(&self, c: ASN1Class) fn to_asn1_class(&self, c: ASN1Class)
@@ -314,7 +300,7 @@ macro_rules! generate_rsa_public
} }
#[cfg(test)] #[cfg(test)]
impl fmt::Debug for $rsa { impl fmt::Debug for RSAPublicKey<$num> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct(stringify!($rsa)) fmt.debug_struct(stringify!($rsa))
.field("n", &self.n) .field("n", &self.n)
@@ -326,17 +312,17 @@ macro_rules! generate_rsa_public
} }
} }
generate_rsa_public!(RSA512Public, U512, BarrettU512, Key512, 512); generate_rsa_public!(U512, BarrettU512, Key512, 512);
generate_rsa_public!(RSA1024Public, U1024, BarrettU1024, Key1024, 1024); generate_rsa_public!(U1024, BarrettU1024, Key1024, 1024);
generate_rsa_public!(RSA2048Public, U2048, BarrettU2048, Key2048, 2048); generate_rsa_public!(U2048, BarrettU2048, Key2048, 2048);
generate_rsa_public!(RSA3072Public, U3072, BarrettU3072, Key3072, 3072); generate_rsa_public!(U3072, BarrettU3072, Key3072, 3072);
generate_rsa_public!(RSA4096Public, U4096, BarrettU4096, Key4096, 4096); generate_rsa_public!(U4096, BarrettU4096, Key4096, 4096);
generate_rsa_public!(RSA8192Public, U8192, BarrettU8192, Key8192, 8192); generate_rsa_public!(U8192, BarrettU8192, Key8192, 8192);
generate_rsa_public!(RSA15360Public, U15360, BarrettU15360, Key15360, 15360); generate_rsa_public!(U15360, BarrettU15360, Key15360, 15360);
#[cfg(test)] #[cfg(test)]
macro_rules! new_test_body { macro_rules! new_test_body {
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size); let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| { run_test(fname.to_string(), 7, |case| {
let (neg0, nbytes) = case.get("n").unwrap(); let (neg0, nbytes) = case.get("n").unwrap();
@@ -350,8 +336,8 @@ macro_rules! new_test_body {
let bigk = $num::from_bytes(kbytes); let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk); let k = usize::from(bigk);
let e = $num::from(65537u64); let e = $num::from(65537u64);
let pubkey2 = $rsa::new(n.clone(), e.clone()); let pubkey2 = RSAPublicKey::<$num>::new(n.clone(), e.clone());
let pubkey1 = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; let pubkey1 = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
assert_eq!(pubkey1, pubkey2); assert_eq!(pubkey1, pubkey2);
}); });
}; };
@@ -359,7 +345,7 @@ macro_rules! new_test_body {
#[cfg(test)] #[cfg(test)]
macro_rules! encode_test_body { macro_rules! encode_test_body {
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size); let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| { run_test(fname.to_string(), 7, |case| {
let (neg0, nbytes) = case.get("n").unwrap(); let (neg0, nbytes) = case.get("n").unwrap();
@@ -373,9 +359,9 @@ macro_rules! encode_test_body {
let bigk = $num::from_bytes(kbytes); let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk); let k = usize::from(bigk);
let e = $num::from(65537u64); let e = $num::from(65537u64);
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let asn1 = pubkey.to_asn1().unwrap(); let asn1 = pubkey.to_asn1().unwrap();
let (pubkey2, _) = $rsa::from_asn1(&asn1).unwrap(); let (pubkey2, _) = RSAPublicKey::from_asn1(&asn1).unwrap();
assert_eq!(pubkey, pubkey2); assert_eq!(pubkey, pubkey2);
}); });
}; };
@@ -383,7 +369,7 @@ macro_rules! encode_test_body {
#[cfg(test)] #[cfg(test)]
macro_rules! verify_test_body { macro_rules! verify_test_body {
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/sign{}.test", $size); let fname = format!("testdata/rsa/sign{}.test", $size);
run_test(fname.to_string(), 7, |case| { run_test(fname.to_string(), 7, |case| {
let (neg0, nbytes) = case.get("n").unwrap(); let (neg0, nbytes) = case.get("n").unwrap();
@@ -400,7 +386,7 @@ macro_rules! verify_test_body {
let bigk = $num::from_bytes(kbytes); let bigk = $num::from_bytes(kbytes);
let k = usize::from(bigk); let k = usize::from(bigk);
let e = $num::from(65537u64); let e = $num::from(65537u64);
let pubkey = $rsa{ n: n, nu: $bar::from_components(k, n64, nu), e: e }; let pubkey = RSAPublicKey{ n: n, nu: $bar::from_components(k, n64, nu), e: e };
let hashnum = u64::from($num::from_bytes(hbytes)); let hashnum = u64::from($num::from_bytes(hbytes));
let sighash = match hashnum { let sighash = match hashnum {
160 => &SIGNING_HASH_SHA1, 160 => &SIGNING_HASH_SHA1,
@@ -417,7 +403,7 @@ macro_rules! verify_test_body {
#[cfg(test)] #[cfg(test)]
macro_rules! encrypt_test_body { macro_rules! encrypt_test_body {
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
let fname = format!("testdata/rsa/encrypt{}.test", $size); let fname = format!("testdata/rsa/encrypt{}.test", $size);
run_test(fname.to_string(), 9, |case| { run_test(fname.to_string(), 9, |case| {
let (neg0, nbytes) = case.get("n").unwrap(); let (neg0, nbytes) = case.get("n").unwrap();
@@ -438,8 +424,8 @@ macro_rules! encrypt_test_body {
let e = $num::from(65537u64); let e = $num::from(65537u64);
let d = $num::from_bytes(dbytes); let d = $num::from_bytes(dbytes);
let nu = $bar::from_components(k, n64, nu); let nu = $bar::from_components(k, n64, nu);
let pubkey = $rsa{ n: n.clone(), nu: nu.clone(), e: e }; let pubkey = RSAPublicKey{ n: n.clone(), nu: nu.clone(), e: e };
let privkey = $priv{ nu: nu, d: d }; let privkey = RSAPrivateKey{ nu: nu, d: d };
let lstr = String::from_utf8(lbytes.clone()).unwrap(); let lstr = String::from_utf8(lbytes.clone()).unwrap();
let cipher = match usize::from($num::from_bytes(hbytes)) { let cipher = match usize::from($num::from_bytes(hbytes)) {
224 => pubkey.encrypt(&OAEPParams::<Sha224>::new(lstr.clone()), mbytes), 224 => pubkey.encrypt(&OAEPParams::<Sha224>::new(lstr.clone()), mbytes),
@@ -463,7 +449,7 @@ macro_rules! encrypt_test_body {
} }
macro_rules! generate_tests { macro_rules! generate_tests {
($mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { ($mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)] #[cfg(test)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod $mod { mod $mod {
@@ -475,16 +461,16 @@ macro_rules! generate_tests {
use sha2::{Sha224,Sha256,Sha384,Sha512}; use sha2::{Sha224,Sha256,Sha384,Sha512};
#[test] #[test]
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
#[test] #[test]
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
#[test] #[test]
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
#[test] #[test]
fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
} }
}; };
(ignore $mod: ident, $rsa: ident, $priv: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => { (ignore $mod: ident, $num: ident, $bar: ident, $num64: ident, $size: expr) => {
#[cfg(test)] #[cfg(test)]
#[allow(non_snake_case)] #[allow(non_snake_case)]
mod $mod { mod $mod {
@@ -497,24 +483,24 @@ macro_rules! generate_tests {
#[ignore] #[ignore]
#[test] #[test]
fn new() { new_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn new() { new_test_body!($mod, $num, $bar, $num64, $size); }
#[ignore] #[ignore]
#[test] #[test]
fn encode() { encode_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn encode() { encode_test_body!($mod, $num, $bar, $num64, $size); }
#[ignore] #[ignore]
#[test] #[test]
fn verify() { verify_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn verify() { verify_test_body!($mod, $num, $bar, $num64, $size); }
#[ignore] #[ignore]
#[test] #[test]
fn encrypt() { encrypt_test_body!($mod, $rsa, $priv, $num, $bar, $num64, $size); } fn encrypt() { encrypt_test_body!($mod, $num, $bar, $num64, $size); }
} }
}; };
} }
generate_tests!(RSA512, RSA512Public, RSA512Private, U512, BarrettU512, U576, 512); generate_tests!( RSA512, U512, BarrettU512, U576, 512);
generate_tests!(RSA1024, RSA1024Public, RSA1024Private, U1024, BarrettU1024, U1088, 1024); generate_tests!( RSA1024, U1024, BarrettU1024, U1088, 1024);
generate_tests!(RSA2048, RSA2048Public, RSA2048Private, U2048, BarrettU2048, U2112, 2048); generate_tests!( RSA2048, U2048, BarrettU2048, U2112, 2048);
generate_tests!(RSA3072, RSA3072Public, RSA3072Private, U3072, BarrettU3072, U3136, 3072); generate_tests!( RSA3072, U3072, BarrettU3072, U3136, 3072);
generate_tests!(RSA4096, RSA4096Public, RSA4096Private, U4096, BarrettU4096, U4160, 4096); generate_tests!( RSA4096, U4096, BarrettU4096, U4160, 4096);
generate_tests!(ignore RSA8192, RSA8192Public, RSA8192Private, U8192, BarrettU8192, U8256, 8192); generate_tests!(ignore RSA8192, U8192, BarrettU8192, U8256, 8192);
generate_tests!(ignore RSA15360, RSA15360Public, RSA15360Private, U15360, BarrettU15360, U15424, 15360); generate_tests!(ignore RSA15360, U15360, BarrettU15360, U15424, 15360);