Checked in program which generates Noekeon vectors using BouncyCastle.
This commit is contained in:
parent
e7b4705fca
commit
80ef95f3c1
249
notes/etc/NoekeonVects.java
Normal file
249
notes/etc/NoekeonVects.java
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
NoekeonVects.java - Generate Noekeon test vectors using BouncyCastle.
|
||||
|
||||
Written in 2011 by Patrick Pelletier <code@funwithsoftware.org>
|
||||
|
||||
To the extent possible under law, the author(s) have dedicated all
|
||||
copyright and related and neighboring rights to this software to
|
||||
the public domain worldwide. This software is distributed without
|
||||
any warranty.
|
||||
|
||||
This file is dedicated to the public domain with the CC0 Public Domain
|
||||
Dedication: http://creativecommons.org/publicdomain/zero/1.0/legalcode.txt
|
||||
|
||||
You may also consider this file to be covered by the WTFPL, as contained
|
||||
in the LibTomCrypt LICENSE file, if that makes you happier for some reason.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This program was inspired by the comment in Botan 1.10.1's
|
||||
doc/examples/eax_test.cpp:
|
||||
|
||||
// Noekeon: unknown cause, though LTC's lone test vector does not
|
||||
// match Botan
|
||||
|
||||
So, I investigated the discrepancy by comparing them with a third
|
||||
implementation, BouncyCastle: http://www.bouncycastle.org/java.html
|
||||
|
||||
I determined that there are two reasons why LibTomCrypt's Noekeon does
|
||||
not match Botan:
|
||||
|
||||
1) Botan uses "indirect Noekeon" (with a key schedule), while
|
||||
LibTomCrypt and BouncyCastle both use "direct Noekeon" (without
|
||||
a key schedule). See slide 14 of
|
||||
http://gro.noekeon.org/Noekeon-slides.pdf
|
||||
|
||||
2) However, LibTomCrypt's direct Noekeon still does not match
|
||||
BouncyCastle's direct Noekeon. This is because of a bug in
|
||||
LibTomCrypt's PI1 and PI2 functions:
|
||||
https://github.com/libtom/libtomcrypt/issues/5
|
||||
|
||||
This program uses BouncyCastle to produce test vectors which are
|
||||
suitable for Botan (by explicitly scheduling the key, thus
|
||||
building indirect Noekeon out of BouncyCastle's direct Noekeon),
|
||||
and also produces test vectors which would be suitable for
|
||||
LibTomCrypt (direct Noekeon) once its PI1 and PI2 functions are
|
||||
fixed to match the Noekeon specification.
|
||||
|
||||
Although this program uses a PRNG from BouncyCastle to generate
|
||||
data for the test vectors, it uses a fixed seed and thus will
|
||||
produce the same output every time it is run.
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import org.bouncycastle.crypto.digests.RIPEMD128Digest;
|
||||
import org.bouncycastle.crypto.engines.NoekeonEngine;
|
||||
import org.bouncycastle.crypto.modes.EAXBlockCipher;
|
||||
import org.bouncycastle.crypto.params.AEADParameters;
|
||||
import org.bouncycastle.crypto.params.KeyParameter;
|
||||
import org.bouncycastle.crypto.prng.DigestRandomGenerator;
|
||||
import org.bouncycastle.util.encoders.HexEncoder;
|
||||
|
||||
public class NoekeonVects
|
||||
{
|
||||
private final DigestRandomGenerator r =
|
||||
new DigestRandomGenerator(new RIPEMD128Digest());
|
||||
|
||||
private final HexEncoder h = new HexEncoder();
|
||||
|
||||
private final NoekeonEngine noekeon = new NoekeonEngine();
|
||||
|
||||
private final KeyParameter null_key = new KeyParameter(new byte[16]);
|
||||
|
||||
private final boolean schedule_key;
|
||||
|
||||
private final boolean botan_format;
|
||||
|
||||
private byte[] randomBytes(int n)
|
||||
{
|
||||
byte[] b = new byte[n];
|
||||
r.nextBytes(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
private void hexOut(byte[] b) throws IOException
|
||||
{
|
||||
// HexEncoder uses lowercase, and Botan's test vectors must
|
||||
// be in uppercase, so...
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
h.encode(b, 0, b.length, os);
|
||||
String s = os.toString("US-ASCII");
|
||||
System.out.print(s.toUpperCase(Locale.US));
|
||||
}
|
||||
|
||||
private void printCArray(byte[] a) throws IOException
|
||||
{
|
||||
byte[] b = new byte[1];
|
||||
for (int i = 0; i < a.length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
System.out.print(", ");
|
||||
System.out.print("0x");
|
||||
b[0] = a[i];
|
||||
hexOut(b);
|
||||
}
|
||||
}
|
||||
|
||||
private void printVector(byte[] key, byte[] plaintext, byte[] ciphertext)
|
||||
throws IOException
|
||||
{
|
||||
if (botan_format)
|
||||
{
|
||||
hexOut(plaintext);
|
||||
System.out.print(":");
|
||||
hexOut(ciphertext);
|
||||
System.out.println(":\\");
|
||||
hexOut(key);
|
||||
System.out.println();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.out.println(" {");
|
||||
System.out.println(" 16,");
|
||||
System.out.print(" { ");
|
||||
printCArray (key);
|
||||
System.out.println(" },");
|
||||
System.out.print(" { ");
|
||||
printCArray (plaintext);
|
||||
System.out.println(" },");
|
||||
System.out.print(" { ");
|
||||
printCArray (ciphertext);
|
||||
System.out.println(" }");
|
||||
System.out.println(" },");
|
||||
}
|
||||
}
|
||||
|
||||
private KeyParameter maybe_schedule_key(byte[] key)
|
||||
{
|
||||
if (schedule_key)
|
||||
{
|
||||
noekeon.init(true, null_key);
|
||||
byte[] scheduled = new byte[16];
|
||||
noekeon.processBlock(key, 0, scheduled, 0);
|
||||
return new KeyParameter(scheduled);
|
||||
}
|
||||
else
|
||||
return new KeyParameter(key);
|
||||
}
|
||||
|
||||
private byte[] encrypt(byte[] plaintext, byte[] key)
|
||||
{
|
||||
KeyParameter kp = maybe_schedule_key(key);
|
||||
noekeon.init(true, kp);
|
||||
byte[] ciphertext = new byte[16];
|
||||
noekeon.processBlock(plaintext, 0, ciphertext, 0);
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
public NoekeonVects(long seed, boolean schedule_key, boolean botan_format)
|
||||
{
|
||||
this.schedule_key = schedule_key;
|
||||
this.botan_format = botan_format;
|
||||
r.addSeedMaterial(seed);
|
||||
}
|
||||
|
||||
public void ecb_vectors() throws IOException
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
byte[] key = randomBytes(16);
|
||||
byte[] plaintext = randomBytes(16);
|
||||
byte[] ciphertext = encrypt(plaintext, key);
|
||||
printVector(key, plaintext, ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
public void eax_vectors() throws Exception
|
||||
{
|
||||
System.out.println("EAX-noekeon (16 byte key)");
|
||||
EAXBlockCipher eax = new EAXBlockCipher(new NoekeonEngine());
|
||||
byte[] output = new byte[48];
|
||||
byte[] tag = new byte[16];
|
||||
|
||||
for (int j = 0; j < 16; j++)
|
||||
tag[j] = (byte) j;
|
||||
|
||||
for (int i = 0; i <= 32; i++)
|
||||
{
|
||||
byte[] header_nonce_plaintext = new byte[i];
|
||||
for (int j = 0; j < i; j++)
|
||||
header_nonce_plaintext[j] = (byte) j;
|
||||
AEADParameters params =
|
||||
new AEADParameters(maybe_schedule_key(tag),
|
||||
128,
|
||||
header_nonce_plaintext,
|
||||
header_nonce_plaintext);
|
||||
eax.init(true, params);
|
||||
int off = eax.processBytes(header_nonce_plaintext, 0, i,
|
||||
output, 0);
|
||||
off += eax.doFinal(output, off);
|
||||
if (off != i + 16)
|
||||
throw new RuntimeException("didn't expect that");
|
||||
byte[] ciphertext = new byte[i];
|
||||
for (int j = 0; j < i; j++)
|
||||
ciphertext[j] = output[j];
|
||||
for (int j = 0; j < 16; j++)
|
||||
tag[j] = output[i + j];
|
||||
System.out.print(i < 10 ? " " : " ");
|
||||
System.out.print(i);
|
||||
System.out.print(": ");
|
||||
hexOut(ciphertext);
|
||||
System.out.print(", ");
|
||||
hexOut(tag);
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] argv) throws Exception
|
||||
{
|
||||
NoekeonVects bot = new NoekeonVects(0xdefacedbadfacadeL, true, true);
|
||||
NoekeonVects tom = new NoekeonVects(0xdefacedbadfacadeL, false, false);
|
||||
System.out.println("# ECB vectors for indirect Noekeon, in Botan's");
|
||||
System.out.println("# test vector format, suitable for insertion");
|
||||
System.out.println("# into Botan's file checks/validate.dat");
|
||||
System.out.println("# Block cipher format is plaintext:ciphertext:key");
|
||||
bot.ecb_vectors();
|
||||
System.out.println();
|
||||
System.out.println("/* ECB vectors for direct Noekeon, as C arrays");
|
||||
System.out.println(" * suitable for insertion into LibTomCrypt's");
|
||||
System.out.println(" * noekeon_test() in src/ciphers/noekeon.c,");
|
||||
System.out.println(" * once LTC's PI1/PI2 bug is fixed. */");
|
||||
tom.ecb_vectors();
|
||||
System.out.println();
|
||||
System.out.println("# EAX vectors for indirect Noekeon, in the format");
|
||||
System.out.println("# generated by LTC's demos/tv_gen.c and consumed");
|
||||
System.out.println("# by Botan's doc/examples/eax_test.cpp, suitable");
|
||||
System.out.println("# for insertion in Botan's doc/examples/eax.vec");
|
||||
bot.eax_vectors();
|
||||
System.out.println();
|
||||
System.out.println("# EAX vectors for direct Noekeon, in the format");
|
||||
System.out.println("# generated by LTC's demos/tv_gen.c and consumed");
|
||||
System.out.println("# by Botan's doc/examples/eax_test.cpp, which");
|
||||
System.out.println("# should match LTC's notes/eax_tv.txt, once");
|
||||
System.out.println("# LTC's PI1/PI2 bug is fixed.");
|
||||
tom.eax_vectors();
|
||||
System.out.flush();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user