diff libtomcrypt/notes/etc/NoekeonVects.java @ 1471:6dba84798cd5

Update to libtomcrypt 1.18.1, merged with Dropbear changes
author Matt Johnston <matt@ucc.asn.au>
date Fri, 09 Feb 2018 21:44:05 +0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libtomcrypt/notes/etc/NoekeonVects.java	Fri Feb 09 21:44:05 2018 +0800
@@ -0,0 +1,249 @@
+/*
+    NoekeonVects.java - Generate Noekeon test vectors using BouncyCastle.
+
+    Written in 2011 by Patrick Pelletier <[email protected]>
+
+    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();
+    }
+}