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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user