136 lines
4.4 KiB
Haskell
136 lines
4.4 KiB
Haskell
{-# 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')
|