Start with RSA signing! Looks like it works against Haskell RSA test vectors.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -13,5 +13,5 @@ Cargo.lock
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# And some Haskell stuff, because I can't shake it!
|
# And some Haskell stuff, because I can't shake it!
|
||||||
tests/math/cabal.sandbox.config
|
**/cabal.sandbox.config
|
||||||
tests/math/.cabal-sandbox
|
**/.cabal-sandbox
|
||||||
|
|||||||
37
src/rsa/gold_tests.rs
Normal file
37
src/rsa/gold_tests.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
use rsa::*;
|
||||||
|
use testing::{make_unsigned,run_test};
|
||||||
|
|
||||||
|
fn get_signing_hash(s: usize) -> &'static SigningHash {
|
||||||
|
match s {
|
||||||
|
0x1 => &SIGNING_HASH_SHA1,
|
||||||
|
0x224 => &SIGNING_HASH_SHA224,
|
||||||
|
0x256 => &SIGNING_HASH_SHA256,
|
||||||
|
0x384 => &SIGNING_HASH_SHA384,
|
||||||
|
0x512 => &SIGNING_HASH_SHA512,
|
||||||
|
_ => panic!("Unacceptable hash")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsa_signature_tests()
|
||||||
|
{
|
||||||
|
run_test("tests/rsa/signature.test", 7, |case| {
|
||||||
|
let (neg0, dbytes) = case.get("d").unwrap();
|
||||||
|
let (neg1, nbytes) = case.get("n").unwrap();
|
||||||
|
let (neg2, hbytes) = case.get("h").unwrap();
|
||||||
|
let (neg2, kbytes) = case.get("k").unwrap();
|
||||||
|
let (neg3, msg) = case.get("m").unwrap();
|
||||||
|
let (neg4, sig) = case.get("s").unwrap();
|
||||||
|
|
||||||
|
assert!(!neg0 & !neg1 & !neg2 & !neg3 & !neg4);
|
||||||
|
let hash = get_signing_hash(usize::from(UCN::from_bytes(hbytes)));
|
||||||
|
let size = usize::from(UCN::from_bytes(kbytes));
|
||||||
|
let key = RSAPrivate::new(UCN::from_bytes(nbytes),
|
||||||
|
UCN::from_bytes(dbytes));
|
||||||
|
|
||||||
|
assert!(size % 8 == 0);
|
||||||
|
assert_eq!(key.byte_len * 8, size);
|
||||||
|
let sig2 = key.sign(hash, &msg);
|
||||||
|
assert_eq!(*sig, sig2);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
mod core;
|
mod core;
|
||||||
mod errors;
|
mod errors;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod gold_tests;
|
||||||
mod public;
|
mod public;
|
||||||
mod private;
|
mod private;
|
||||||
mod signing_hashes;
|
mod signing_hashes;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ impl RSAPrivate {
|
|||||||
let len = n.bits();
|
let len = n.bits();
|
||||||
|
|
||||||
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
for &(valid_bits, _) in ACCEPTABLE_KEY_SIZES.iter() {
|
||||||
if valid_bits > len {
|
if valid_bits >= len {
|
||||||
return RSAPrivate {
|
return RSAPrivate {
|
||||||
byte_len: valid_bits / 8,
|
byte_len: valid_bits / 8,
|
||||||
n: n.clone(),
|
n: n.clone(),
|
||||||
@@ -61,4 +61,14 @@ impl RSAPrivate {
|
|||||||
}
|
}
|
||||||
panic!("Invalid RSA key size in new()")
|
panic!("Invalid RSA key size in new()")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sign a message using the given hash.
|
||||||
|
pub fn sign(&self, sighash: &SigningHash, msg: &[u8]) -> Vec<u8> {
|
||||||
|
let hash = (sighash.run)(msg);
|
||||||
|
let em = pkcs1_pad(&sighash.ident, &hash, self.byte_len);
|
||||||
|
let m = UCN::from_bytes(&em);
|
||||||
|
let s = sp1(&self.nu, &self.d, &m);
|
||||||
|
let sig = s.to_bytes(self.byte_len);
|
||||||
|
sig
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
135
tests/rsa/GenerateRSATests.hs
Normal file
135
tests/rsa/GenerateRSATests.hs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
{-# LANGUAGE ScopedTypeVariables #-}
|
||||||
|
import Control.Monad
|
||||||
|
import Codec.Crypto.RSA.Pure
|
||||||
|
import Control.Concurrent
|
||||||
|
import Crypto.Random.DRBG
|
||||||
|
import Data.Bits
|
||||||
|
import qualified Data.ByteString as BS
|
||||||
|
import qualified Data.ByteString.Lazy as BSL
|
||||||
|
import Data.List
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import GHC.Integer.GMP.Internals
|
||||||
|
import Numeric
|
||||||
|
import System.IO
|
||||||
|
import System.ProgressBar
|
||||||
|
import System.Random
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
numThreads :: Int
|
||||||
|
numThreads = 4
|
||||||
|
|
||||||
|
keySizes :: [Int]
|
||||||
|
keySizes = [512,1024,2048,3072,4096,7680,8192,15360]
|
||||||
|
|
||||||
|
keyIterations :: [Int]
|
||||||
|
keyIterations = replicate 500 512 ++
|
||||||
|
replicate 500 1024 ++
|
||||||
|
replicate 250 2048 ++
|
||||||
|
replicate 125 3072 ++
|
||||||
|
replicate 50 4096 ++
|
||||||
|
replicate 5 7680 ++
|
||||||
|
replicate 2 8192 ++
|
||||||
|
replicate 1 15360
|
||||||
|
|
||||||
|
randomByteString :: CryptoRandomGen g => g -> (BS.ByteString, g)
|
||||||
|
randomByteString g =
|
||||||
|
let Right (bs, g') = genBytes 2 g
|
||||||
|
[h,l] = BS.unpack bs
|
||||||
|
x = (fromIntegral h `shiftL` 8) + (fromIntegral l)
|
||||||
|
Right (res, g'') = genBytes (x `mod` 1024) g'
|
||||||
|
in (res, g'')
|
||||||
|
|
||||||
|
randomHash :: CryptoRandomGen g => g -> ((HashInfo, String), g)
|
||||||
|
randomHash g =
|
||||||
|
randomElement g [(hashSHA1, "1"),
|
||||||
|
(hashSHA224, "224"),
|
||||||
|
(hashSHA256, "256"),
|
||||||
|
(hashSHA384, "384"),
|
||||||
|
(hashSHA512, "512")]
|
||||||
|
|
||||||
|
showBinary :: BS.ByteString -> String
|
||||||
|
showBinary v = go v
|
||||||
|
where
|
||||||
|
go bstr =
|
||||||
|
case BS.uncons bstr of
|
||||||
|
Nothing ->
|
||||||
|
""
|
||||||
|
Just (x, rest) ->
|
||||||
|
let high = showHex (x `shiftR` 4) ""
|
||||||
|
low = showHex (x .&. 0xF) ""
|
||||||
|
in high ++ low ++ go rest
|
||||||
|
|
||||||
|
dump :: Handle -> [(String,String)] -> IO ()
|
||||||
|
dump hndl = mapM_ writeItem
|
||||||
|
where
|
||||||
|
writeItem (name, value) =
|
||||||
|
do hPutStr hndl name
|
||||||
|
hPutStr hndl ": "
|
||||||
|
hPutStrLn hndl value
|
||||||
|
|
||||||
|
mkProgress x y = Progress (fromIntegral x) (fromIntegral y)
|
||||||
|
|
||||||
|
runSignatureGenerator :: Chan Int -> Chan [(String,String)] -> IO ()
|
||||||
|
runSignatureGenerator inputs outputs =
|
||||||
|
do rng0 :: GenBuffered SystemRandom <- newGenIO
|
||||||
|
go Nothing rng0
|
||||||
|
where
|
||||||
|
go Nothing rng0 =
|
||||||
|
do keySize <- readChan inputs
|
||||||
|
go (Just keySize) rng0
|
||||||
|
go (Just keySize) g0 =
|
||||||
|
do unless (keySize `elem` keySizes) $
|
||||||
|
fail ("Bad key size: " ++ show keySize)
|
||||||
|
let Right (public, private, g1) = generateKeyPair g0 keySize
|
||||||
|
unless (private_d private `shiftR` keySize == 0) $
|
||||||
|
fail ("Bad private key size.")
|
||||||
|
unless (public_n public `shiftR` keySize == 0) $
|
||||||
|
fail ("Bad private key size.")
|
||||||
|
let (message, g2) = randomByteString g1
|
||||||
|
let ((hash, hashname), g3) = randomHash g2
|
||||||
|
case rsassa_pkcs1_v1_5_sign hash private (BSL.fromStrict message) of
|
||||||
|
Left _ ->
|
||||||
|
go (Just keySize) g3
|
||||||
|
Right sig ->
|
||||||
|
do writeChan outputs [("d", showHex (private_d private) ""),
|
||||||
|
("n", showHex (public_n public) ""),
|
||||||
|
("h", hashname),
|
||||||
|
("k", showHex keySize ""),
|
||||||
|
("l", showHex (BS.length message) ""),
|
||||||
|
("m", showBinary message),
|
||||||
|
("s", showBinary (BSL.toStrict sig))]
|
||||||
|
go Nothing g3
|
||||||
|
|
||||||
|
writeData :: Chan [(String,String)] -> (Progress -> IO ()) -> Handle -> IO ()
|
||||||
|
writeData outputChan progressBar hndl = go 0
|
||||||
|
where
|
||||||
|
count = fromIntegral (length keyIterations)
|
||||||
|
go x | x == count = return ()
|
||||||
|
| otherwise = do output <- readChan outputChan
|
||||||
|
dump hndl output
|
||||||
|
hFlush hndl
|
||||||
|
progressBar (Progress (x + 1) count)
|
||||||
|
go (x + 1)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main =
|
||||||
|
do sizeChan <- newChan
|
||||||
|
outputChan <- newChan
|
||||||
|
--
|
||||||
|
replicateM_ numThreads $
|
||||||
|
void $ forkIO $ runSignatureGenerator sizeChan outputChan
|
||||||
|
--
|
||||||
|
unless (all (`elem` keySizes) keyIterations) $
|
||||||
|
fail "System setup failure."
|
||||||
|
writeList2Chan sizeChan keyIterations
|
||||||
|
--
|
||||||
|
let bar = autoProgressBar (msg "Generating test material") percentage 60
|
||||||
|
g1 <- withFile "signature.test" WriteMode (writeData outputChan bar)
|
||||||
|
return ()
|
||||||
|
|
||||||
|
randomElement :: CryptoRandomGen g => g -> [a] -> (a, g)
|
||||||
|
randomElement g xs =
|
||||||
|
let Right (bs, g') = genBytes 1 g
|
||||||
|
x = BS.head bs
|
||||||
|
idx = fromIntegral x `mod` length xs
|
||||||
|
in (xs !! idx, g')
|
||||||
10031
tests/rsa/signature.test
Normal file
10031
tests/rsa/signature.test
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user