Switch to a Java-based test generator, which seems to work better.

This commit is contained in:
2018-05-06 21:22:10 -07:00
parent a2b4baa087
commit 3d767c3e13
3 changed files with 5767 additions and 4458 deletions

View File

@@ -1,128 +0,0 @@
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Monad
import Codec.Crypto.DSA.Pure
import Control.Concurrent
import Crypto.Random.DRBG
import Data.Bits
import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as BSC
import qualified Data.ByteString.Lazy as BSL
import Data.Char
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
keyIterations :: [ParameterSizes]
keyIterations = replicate 500 L1024_N160 ++
replicate 500 L2048_N224 ++
replicate 200 L2048_N256 ++
replicate 100 L3072_N256
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 -> ((HashFunction, String), g)
randomHash g =
randomElement g [(SHA1, "1"),
(SHA224, "224"),
(SHA256, "256"),
(SHA384, "384"),
(SHA512, "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 ParameterSizes ->
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 let Right (public, private, _, g1) = generateKeyPair g0 keySize
let (msg, g2) = randomByteString g1
let msg' = BSL.fromStrict msg
let ((hash, hashname), g3) = randomHash g2
case signMessage' hash kViaRFC6979 g3 private msg' of
Left _ ->
go (Just keySize) g3
Right (sig, g4) ->
do unless (verifyMessage' hash public msg' sig) $
fail "DSA verification failed internally."
let params = private_params private
writeChan outputs [("p", showHex (params_p params) ""),
("g", showHex (params_g params) ""),
("q", showHex (params_q params) ""),
("x", showHex (private_x private) ""),
("y", showHex (public_y public) ""),
("h", hashname),
("m", showBinary msg),
("r", showHex (sign_r sig) ""),
("s", showHex (sign_s sig) "")]
go Nothing g4
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
--
sigthrs <- replicateM numThreads $
forkIO $ runSignatureGenerator sizeChan outputChan
let bar = autoProgressBar (msg "Generating signature tests") percentage 60
writeList2Chan sizeChan keyIterations
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')

195
tests/dsa/Generator.java Normal file
View File

@@ -0,0 +1,195 @@
// Just because I always forget Java compilation:
// javac Generator.java -cp bcprov-ext-jdk15on-159.jar
// java -cp "bcprov-ext-jdk15on-159.jar:." Generator
// Also, go here:
// https://www.bouncycastle.org/latest_releases.html
//
import java.io.FileWriter;
import java.io.IOException;
import java.lang.InterruptedException;
import java.lang.Math;
import java.lang.Thread;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA384Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.generators.DSAKeyPairGenerator;
import org.bouncycastle.crypto.generators.DSAParametersGenerator;
import org.bouncycastle.crypto.params.DSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameterGenerationParameters;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
import org.bouncycastle.crypto.params.DSAPublicKeyParameters;
import org.bouncycastle.crypto.signers.DSASigner;
import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
class Generator {
private FileWriter out;
private SecureRandom rng;
final static int NUM_THREADS = 4;
public Generator(SecureRandom r, FileWriter o) {
rng = r;
out = o;
}
public void runTests(int lsize, int nsize, int count)
throws IOException, InterruptedException
{
Thread threads[] = new Thread[NUM_THREADS];
System.out.print("Generating L" + lsize + "N" + nsize + " tests ");
for(int i = 0; i < NUM_THREADS; i++) {
Runner runner = new Runner(lsize, nsize, count / NUM_THREADS, this);
Thread runThread = new Thread(runner);
runThread.start();
threads[i] = runThread;
}
for(Thread thread : threads) {
thread.join();
}
System.out.println(" done.");
}
public synchronized void output(DSAParameters params,
AsymmetricCipherKeyPair kp,
int digestsize,
byte[] message,
BigInteger[] rs)
throws IOException
{
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
out.write("p: " + params.getP().toString(16) + "\n");
out.write("q: " + params.getQ().toString(16) + "\n");
out.write("g: " + params.getG().toString(16) + "\n");
out.write("x: " + priv.getX().toString(16) + "\n");
out.write("y: " + pub.getY().toString(16) + "\n");
out.write("h: " + digestsize + "\n");
out.write("m: " + asHex(message) + "\n");
out.write("r: " + rs[0].toString(16) + "\n");
out.write("s: " + rs[1].toString(16) + "\n");
out.flush();
System.out.print(".");
System.out.flush();
}
private Digest appropriateDigest(int nsize)
throws IOException
{
switch(nsize) {
case 1: return new SHA1Digest();
case 160: return new SHA1Digest();
case 224: return new SHA224Digest();
case 256: return new SHA256Digest();
case 384: return new SHA384Digest();
case 512: return new SHA512Digest();
default:
throw new IOException("Bad digest size!");
}
}
private int randomDigestSize()
throws IOException
{
switch(getRandomChoice(5)) {
case 0: return 1;
case 1: return 224;
case 2: return 256;
case 3: return 384;
case 4: return 512;
default:
throw new IOException("The world broke.");
}
}
private int getRandomChoice(int modulus) {
byte randoms[] = new byte[2];
rng.nextBytes(randoms);
int random = ((int)randoms[0] << 8) + ((int)randoms[1]);
return (Math.abs(random) % modulus);
}
private String asHex(byte[] data) {
String result = "";
for(byte value : data) {
result = result + String.format("%02x", value);
}
return result;
}
public static void main(String[] args)
throws IOException, InterruptedException
{
SecureRandom rng = new SecureRandom();
FileWriter outfile = new FileWriter("signatures.test", false);
Generator gen = new Generator(rng, outfile);
gen.runTests(1024, 160, 500);
gen.runTests(2047, 224, 500);
gen.runTests(2048, 256, 250);
gen.runTests(3072, 256, 100);
}
private class Runner implements Runnable {
private int lsize;
private int nsize;
private int count;
private Generator parent;
public Runner(int lsize, int nsize, int count, Generator parent)
{
this.lsize = lsize;
this.nsize = nsize;
this.count = count;
this.parent = parent;
}
public void run()
{
for(int i = 0; i < count; i++) {
runTest();
}
}
private void runTest()
{
try {
DSAParameterGenerationParameters genparams =
new DSAParameterGenerationParameters(lsize, nsize, 80, rng);
DSAParametersGenerator gen =
new DSAParametersGenerator(parent.appropriateDigest(nsize));
gen.init(genparams);
DSAParameters params = gen.generateParameters();
DSAKeyGenerationParameters dsakeygenparams =
new DSAKeyGenerationParameters(rng, params);
DSAKeyPairGenerator keygen = new DSAKeyPairGenerator();
keygen.init(dsakeygenparams);
AsymmetricCipherKeyPair kp = keygen.generateKeyPair();
DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic();
DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate();
int msgsize = getRandomChoice(1024);
byte message[] = new byte[msgsize];
rng.nextBytes(message);
int digestsize = randomDigestSize();
Digest msgdigest = appropriateDigest(digestsize);
HMacDSAKCalculator kgen = new HMacDSAKCalculator(msgdigest);
DSASigner signer = new DSASigner(kgen);
signer.init(true, priv);
BigInteger rs[] = signer.generateSignature(message);
parent.output(params, kp, digestsize, message, rs);
} catch(IOException exc) {
System.out.println("EXCEPTION!");
run();
}
}
}
}

File diff suppressed because it is too large Load Diff