123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- /*
- 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();
- }
- }
|