Subject: [Classpathx-crypto] [patch] Serpent cipher

From: Casey Marshall <[email-masked]>
Date: Tue, 4 Jun 2002 17:15:08 -0700 (PDT)

Hello,

I've been doing some studying in cryptography, came across GNU classpathx,
and have been working on implementing some ciphers using the crypto API.

The patch which follows (which is longish, but I didn't want to do an
attachment---please admonish if this is poor etiquette) is an
implementation of Serpent which appears correct in a few tests. It does
not, as far as I know, refer to any non-free techniques---is uses some
optimized S-box functions found by Dag Arne Osvik which are implemented
in a GPL'd ADA implementation from http://www.ii.uib.no/~gisle/serpent.html.

The patch is based on a recent CVS checkout and updates the gcj
Makefile.{in,am}, the classes Registry and CipherFactory, and adds the
Serpent class itself. Classpathx is welcome to use it.

Cheers,

-- 
Casey Marshall < [email-masked] > http://metastatic.org/

=== cut here ===
diff -Naurw crypto/gcj/source/Makefile.am crypto.1/gcj/source/Makefile.am
--- crypto/gcj/source/Makefile.am	Wed May 29 02:02:35 2002
+++ crypto.1/gcj/source/Makefile.am	Tue Jun  4 16:04:52 2002
@@ -86,6 +86,7 @@
  gnu/crypto/cipher/Khazad.java \
  gnu/crypto/cipher/NullCipher.java \
  gnu/crypto/cipher/Rijndael.java \
+ gnu/crypto/cipher/Serpent.java \
  gnu/crypto/cipher/Square.java \
  gnu/crypto/cipher/Twofish.java \
  gnu/crypto/hash/BaseHash.java \
diff -Naurw crypto/gcj/source/Makefile.in crypto.1/gcj/source/Makefile.in
--- crypto/gcj/source/Makefile.in	Wed May 29 02:02:35 2002
+++ crypto.1/gcj/source/Makefile.in	Tue Jun  4 16:05:44 2002
@@ -203,6 +176,7 @@
  gnu/crypto/cipher/Khazad.java \
  gnu/crypto/cipher/NullCipher.java \
  gnu/crypto/cipher/Rijndael.java \
+ gnu/crypto/cipher/Serpent.java \
  gnu/crypto/cipher/Square.java \
  gnu/crypto/cipher/Twofish.java \
  gnu/crypto/hash/BaseHash.java \
@@ -297,9 +271,9 @@
 	gnu/crypto/cipher/IBlockCipher.lo \
 	gnu/crypto/cipher/IBlockCipherSpi.lo \
 	gnu/crypto/cipher/Khazad.lo gnu/crypto/cipher/NullCipher.lo \
-	gnu/crypto/cipher/Rijndael.lo gnu/crypto/cipher/Square.lo \
-	gnu/crypto/cipher/Twofish.lo gnu/crypto/hash/BaseHash.lo \
-	gnu/crypto/hash/HashFactory.lo \
+	gnu/crypto/cipher/Rijndael.lo gnu/crypto/cipher/Serpent.lo \
+	gnu/crypto/cipher/Square.lo gnu/crypto/cipher/Twofish.lo \
+	gnu/crypto/hash/BaseHash.lo gnu/crypto/hash/HashFactory.lo \
 	gnu/crypto/hash/IMessageDigest.lo gnu/crypto/hash/MD5.lo \
 	gnu/crypto/hash/RipeMD128.lo gnu/crypto/hash/RipeMD160.lo \
 	gnu/crypto/hash/Sha160.lo gnu/crypto/hash/Whirlpool.lo \
@@ -388,6 +366,7 @@
 @AMDEP_TRUE@	gnu/crypto/cipher/$(DEPDIR)/Khazad.Plo \
 @AMDEP_TRUE@	gnu/crypto/cipher/$(DEPDIR)/NullCipher.Plo \
 @AMDEP_TRUE@	gnu/crypto/cipher/$(DEPDIR)/Rijndael.Plo \
+@AMDEP_TRUE@	gnu/crypto/cipher/$(DEPDIR)/Serpent.Plo \
 @AMDEP_TRUE@	gnu/crypto/cipher/$(DEPDIR)/Square.Plo \
 @AMDEP_TRUE@	gnu/crypto/cipher/$(DEPDIR)/Twofish.Plo \
 @AMDEP_TRUE@	gnu/crypto/hash/$(DEPDIR)/BaseHash.Plo \
@@ -561,6 +534,9 @@
 gnu/crypto/cipher/Rijndael.lo: gnu/crypto/cipher/Rijndael.java \
 	gnu/crypto/cipher/.dirstamp \
 	gnu/crypto/cipher/$(DEPDIR)/.dirstamp
+gnu/crypto/cipher/Serpent.lo: gnu/crypto/cipher/Serpent.java \
+	gnu/crypto/cipher/.dirstamp \
+	gnu/crypto/cipher/$(DEPDIR)/.dirstamp
 gnu/crypto/cipher/Square.lo: gnu/crypto/cipher/Square.java \
 	gnu/crypto/cipher/.dirstamp \
 	gnu/crypto/cipher/$(DEPDIR)/.dirstamp
@@ -880,6 +852,8 @@
 	-rm -f gnu/crypto/cipher/NullCipher.lo
 	-rm -f gnu/crypto/cipher/Rijndael.$(OBJEXT)
 	-rm -f gnu/crypto/cipher/Rijndael.lo
+	-rm -f gnu/crypto/cipher/Serpent.$(OBJEXT)
+	-rm -f gnu/crypto/cipher/Serpent.lo
 	-rm -f gnu/crypto/cipher/Square.$(OBJEXT)
 	-rm -f gnu/crypto/cipher/Square.lo
 	-rm -f gnu/crypto/cipher/Twofish.$(OBJEXT)
@@ -1075,6 +1049,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/cipher/$(DEPDIR)/Khazad.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/cipher/$(DEPDIR)/NullCipher.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/cipher/$(DEPDIR)/Rijndael.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/cipher/$(DEPDIR)/Serpent.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/cipher/$(DEPDIR)/Square.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/cipher/$(DEPDIR)/Twofish.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@gnu/crypto/hash/$(DEPDIR)/BaseHash.Plo@am__quote@
@@ -1340,6 +1315,24 @@
 @AMDEP_TRUE@	$(GCJDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 	$(LIBTOOL) --mode=compile $(GCJ) $(AM_GCJFLAGS) $(GCJFLAGS) -c -o gnu/crypto/cipher/Rijndael.lo `test -f 'gnu/crypto/cipher/Rijndael.java' || echo '$(srcdir)/'`gnu/crypto/cipher/Rijndael.java

+gnu/crypto/cipher/Serpent.o: gnu/crypto/cipher/Serpent.java
+@AMDEP_TRUE@	source='gnu/crypto/cipher/Serpent.java' object='gnu/crypto/cipher/Serpent.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@	depfile='gnu/crypto/cipher/$(DEPDIR)/Serpent.Po' tmpdepfile='gnu/crypto/cipher/$(DEPDIR)/Serpent.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@	$(GCJDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(GCJ) $(AM_GCJFLAGS) $(GCJFLAGS) -c -o gnu/crypto/cipher/Serpent.o `test -f 'gnu/crypto/cipher/Serpent.java' || echo '$(srcdir)/'`gnu/crypto/cipher/Serpent.java
+
+gnu/crypto/cipher/Serpent.obj: gnu/crypto/cipher/Serpent.java
+@AMDEP_TRUE@	source='gnu/crypto/cipher/Serpent.java' object='gnu/crypto/cipher/Serpent.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@	depfile='gnu/crypto/cipher/$(DEPDIR)/Serpent.Po' tmpdepfile='gnu/crypto/cipher/$(DEPDIR)/Serpent.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@	$(GCJDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(GCJ) $(AM_GCJFLAGS) $(GCJFLAGS) -c -o gnu/crypto/cipher/Serpent.obj `cygpath -w gnu/crypto/cipher/Serpent.java`
+
+gnu/crypto/cipher/Serpent.lo: gnu/crypto/cipher/Serpent.java
+@AMDEP_TRUE@	source='gnu/crypto/cipher/Serpent.java' object='gnu/crypto/cipher/Serpent.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@	depfile='gnu/crypto/cipher/$(DEPDIR)/Serpent.Plo' tmpdepfile='gnu/crypto/cipher/$(DEPDIR)/Serpent.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@	$(GCJDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+	$(LIBTOOL) --mode=compile $(GCJ) $(AM_GCJFLAGS) $(GCJFLAGS) -c -o gnu/crypto/cipher/Serpent.lo `test -f 'gnu/crypto/cipher/Serpent.java' || echo '$(srcdir)/'`gnu/crypto/cipher/Serpent.java
+
 gnu/crypto/cipher/Square.o: gnu/crypto/cipher/Square.java
 @AMDEP_TRUE@	source='gnu/crypto/cipher/Square.java' object='gnu/crypto/cipher/Square.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@	depfile='gnu/crypto/cipher/$(DEPDIR)/Square.Po' tmpdepfile='gnu/crypto/cipher/$(DEPDIR)/Square.TPo' @AMDEPBACKSLASH@
diff -Naurw crypto/source/gnu/crypto/Registry.java crypto.1/source/gnu/crypto/Registry.java
--- crypto/source/gnu/crypto/Registry.java	Fri Jan 11 13:58:27 2002
+++ crypto.1/source/gnu/crypto/Registry.java	Tue Jun  4 16:24:53 2002
@@ -45,6 +45,7 @@
    String ANUBIS_CIPHER =   "anubis";
    String KHAZAD_CIPHER =   "khazad";
    String RIJNDAEL_CIPHER = "rijndael";
+   String SERPENT_CIPHER =  "serpent";
    String SQUARE_CIPHER =   "square";
    String TWOFISH_CIPHER =  "twofish";
    String NULL_CIPHER =     "null";
diff -Naurw crypto/source/gnu/crypto/cipher/CipherFactory.java crypto.1/source/gnu/crypto/cipher/CipherFactory.java
--- crypto/source/gnu/crypto/cipher/CipherFactory.java	Fri Jan 11 13:57:28 2002
+++ crypto.1/source/gnu/crypto/cipher/CipherFactory.java	Tue Jun  4 16:18:25 2002
@@ -82,6 +82,8 @@
       } else if (name.equalsIgnoreCase(RIJNDAEL_CIPHER)
               || name.equalsIgnoreCase(AES_CIPHER)) {
          result = new Rijndael();
+      } else if (name.equalsIgnoreCase(SERPENT_CIPHER)) {
+         result = new Serpent();
       } else if (name.equalsIgnoreCase(SQUARE_CIPHER)) {
          result = new Square();
       } else if (name.equalsIgnoreCase(TWOFISH_CIPHER)) {
@@ -108,6 +110,7 @@
       hs.add(ANUBIS_CIPHER);
       hs.add(KHAZAD_CIPHER);
       hs.add(RIJNDAEL_CIPHER);
+      hs.add(SERPENT_CIPHER);
       hs.add(SQUARE_CIPHER);
       hs.add(TWOFISH_CIPHER);
       hs.add(NULL_CIPHER);
diff -Naurw crypto/source/gnu/crypto/cipher/Serpent.java crypto.1/source/gnu/crypto/cipher/Serpent.java
--- crypto/source/gnu/crypto/cipher/Serpent.java	Wed Dec 31 16:00:00 1969
+++ crypto.1/source/gnu/crypto/cipher/Serpent.java	Tue Jun  4 14:21:54 2002
@@ -0,0 +1,740 @@
+package gnu.crypto.cipher;
+
+// ----------------------------------------------------------------------------
+// $Id: classpathx-crypto.mbox,v 1.1 2002/10/27 09:40:41 raif Exp $
+//
+// Copyright (C) 2001 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 of the License or (at your option) any
+// later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; see the file COPYING.  If not, write to the
+//
+//    Free Software Foundation Inc.,
+//    59 Temple Place - Suite 330,
+//    Boston, MA 02111-1307
+//    USA
+//
+// As a special exception, if you link this library with other files to produce
+// an executable, this library does not by itself cause the resulting
+// executable to be covered by the GNU General Public License.  This exception
+// does not however invalidate any other reasons why the executable file might
+// be covered by the GNU General Public License.
+// ----------------------------------------------------------------------------
+
+import gnu.crypto.Registry;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.security.InvalidKeyException;
+
+/**
+ * Serpent is a 32-round substitution-permutation network block cipher,
+ * operating on 128-bit blocks and accepting keys of 128, 192, and 256
+ * bits in length. At each round the plaintext is XORed with a 128 bit
+ * portion of the session key -- a 4224 bit key computed from the input
+ * key -- then one of eight S-boxes are applied, and finally a simple
+ * linear transformation is done. Decryption does the exact same thing
+ * in reverse order, and using the eight inverses of the S-boxes.
+ * <p>
+ * Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as
+ * a proposed cipher for the Advanced Encryption Standard.
+ * <p>
+ * Reference: <a
+ * href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent: A
+ * Candidate Block Cipher for the Advanced Encryption Standard.</a>
+ * <p>
+ * Serpent can be sped up greatly by replacing S-box substitution with a
+ * sequence of binary operations, and the optimal implementation depends
+ * upon finding the fastest sequence of binary operations that reproduce
+ * this substitution. This implementation uses the S-boxes discovered by
+ * <a href="http://www.ii.uib.no/~osvik/">Dag Arne Osvik</a>, which are
+ * optimized for the Pentium family of processors.
+ *
+ * @version $Revision: 1.1 $
+ */
+public class Serpent extends BaseCipher {
+
+ // Constants and variables
+   // -----------------------------------------------------------------
+
+   private static final String NAME = "serpent";
+
+   private static final int DEFAULT_KEY_SIZE = 32;
+   private static final int DEFAULT_BLOCK_SIZE = 16;
+   private static final int ROUNDS = 32;
+
+   /** The fractional part of the golden ratio, (sqrt(5)+1)/2. */
+   private static final int PHI = 0x9e3779b9;
+
+   // Constructors
+   // -----------------------------------------------------------------
+
+   /** Trivial zero-argument constructor. */
+   public Serpent() {
+      super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE);
+   }
+
+   // Implementation of the Cloneable interface
+   // -----------------------------------------------------------------
+
+   public Object clone() {
+      return new Serpent();
+   }
+
+ // Implementations of abstract methods from BaseCipher
+   // -----------------------------------------------------------------
+
+   public Iterator blockSizes() {
+      return Collections.singleton(new Integer(DEFAULT_BLOCK_SIZE)).iterator();
+   }
+
+   public Iterator keySizes() {
+      return new Iterator() {
+         int i = 0;
+         // Support 128, 192, and 256 bit keys.
+         Integer[] keySizes = {
+            new Integer(16), new Integer(24), new Integer(32)
+         };
+
+         public boolean hasNext() {
+            return i < keySizes.length;
+         }
+
+         public Object next() {
+            if (hasNext()) {
+               return keySizes[i++];
+            }
+            return null;
+         }
+
+         public void remove() {
+            throw new UnsupportedOperationException();
+         }
+      };
+   }
+
+   public Object
+   makeKey(byte[] key, int blockSize) throws InvalidKeyException {
+      // Not strictly true, but here to conform with the AES proposal.
+      // This restriction can be removed if deemed necessary.
+      if (key.length != 16 && key.length != 24 && key.length != 32) {
+         throw new InvalidKeyException("Key length is not 16, 24, or 32 bytes");
+      }
+
+      // Here w is our "pre-key".
+      int[] w = new int[4*(ROUNDS+1)];
+      int i, j;
+      for (i = 0, j = key.length-4; i < 8 && j >= 0; i++) {
+         w[i] = (key[j  ] & 0xff) << 24 | (key[j+1] & 0xff) << 16 |
+                (key[j+2] & 0xff) << 8  | (key[j+3] & 0xff);
+         j -= 4;
+      }
+      // Pad key if < 256 bits.
+      if (i != 8) {
+         w[i] = 1;
+      }
+      // Transform using w_i-8 ... w_i-1
+      for (i = 8; i < 16; i++) {
+         int t = w[i-8] ^ w[i-5] ^ w[i-3] ^ w[i-1] ^ PHI ^ (i-8);
+         w[i] = t << 11 | t >>> 21;
+      }
+      // Translate by 8.
+      for (i = 0; i < 8; i++) {
+         w[i] = w[i+8];
+      }
+      // Transform the rest of the key.
+      for (i = 8; i < w.length; i++) {
+         int t = w[i-8] ^ w[i-5] ^ w[i-3] ^ w[i-1] ^ PHI ^ i;
+         w[i] = t << 11 | t >>> 21;
+      }
+
+      // After these s-boxes the pre-key (w, above) will become the
+      // session key (w, below).
+      sbox3(w[  0], w[  1], w[  2], w[  3], w,   0);
+      sbox2(w[  4], w[  5], w[  6], w[  7], w,   4);
+      sbox1(w[  8], w[  9], w[ 10], w[ 11], w,   8);
+      sbox0(w[ 12], w[ 13], w[ 14], w[ 15], w,  12);
+      sbox7(w[ 16], w[ 17], w[ 18], w[ 19], w,  16);
+      sbox6(w[ 20], w[ 21], w[ 22], w[ 23], w,  20);
+      sbox5(w[ 24], w[ 25], w[ 26], w[ 27], w,  24);
+      sbox4(w[ 28], w[ 29], w[ 30], w[ 31], w,  28);
+      sbox3(w[ 32], w[ 33], w[ 34], w[ 35], w,  32);
+      sbox2(w[ 36], w[ 37], w[ 38], w[ 39], w,  36);
+      sbox1(w[ 40], w[ 41], w[ 42], w[ 43], w,  40);
+      sbox0(w[ 44], w[ 45], w[ 46], w[ 47], w,  44);
+      sbox7(w[ 48], w[ 49], w[ 50], w[ 51], w,  48);
+      sbox6(w[ 52], w[ 53], w[ 54], w[ 55], w,  52);
+      sbox5(w[ 56], w[ 57], w[ 58], w[ 59], w,  56);
+      sbox4(w[ 60], w[ 61], w[ 62], w[ 63], w,  60);
+      sbox3(w[ 64], w[ 65], w[ 66], w[ 67], w,  64);
+      sbox2(w[ 68], w[ 69], w[ 70], w[ 71], w,  68);
+      sbox1(w[ 72], w[ 73], w[ 74], w[ 75], w,  72);
+      sbox0(w[ 76], w[ 77], w[ 78], w[ 79], w,  76);
+      sbox7(w[ 80], w[ 81], w[ 82], w[ 83], w,  80);
+      sbox6(w[ 84], w[ 85], w[ 86], w[ 87], w,  84);
+      sbox5(w[ 88], w[ 89], w[ 90], w[ 91], w,  88);
+      sbox4(w[ 92], w[ 93], w[ 94], w[ 95], w,  92);
+      sbox3(w[ 96], w[ 97], w[ 98], w[ 99], w,  96);
+      sbox2(w[100], w[101], w[102], w[103], w, 100);
+      sbox1(w[104], w[105], w[106], w[107], w, 104);
+      sbox0(w[108], w[109], w[110], w[111], w, 108);
+      sbox7(w[112], w[113], w[114], w[115], w, 112);
+      sbox6(w[116], w[117], w[118], w[119], w, 116);
+      sbox5(w[120], w[121], w[122], w[123], w, 120);
+      sbox4(w[124], w[125], w[126], w[127], w, 124);
+      sbox3(w[128], w[129], w[130], w[131], w, 128);
+
+      return w;
+   }
+
+   public
+   void encrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) {
+      int[] key = (int[]) K;
+      int[] x = new int[4];
+      x[3] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+      x[2] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+      x[1] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+      x[0] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+
+      sbox0(key[  0]^x[0], key[  1]^x[1], key[  2]^x[2], key[  3]^x[3], x, 0);
+      transform(x);
+      sbox1(key[  4]^x[0], key[  5]^x[1], key[  6]^x[2], key[  7]^x[3], x, 0);
+      transform(x);
+      sbox2(key[  8]^x[0], key[  9]^x[1], key[ 10]^x[2], key[ 11]^x[3], x, 0);
+      transform(x);
+      sbox3(key[ 12]^x[0], key[ 13]^x[1], key[ 14]^x[2], key[ 15]^x[3], x, 0);
+      transform(x);
+      sbox4(key[ 16]^x[0], key[ 17]^x[1], key[ 18]^x[2], key[ 19]^x[3], x, 0);
+      transform(x);
+      sbox5(key[ 20]^x[0], key[ 21]^x[1], key[ 22]^x[2], key[ 23]^x[3], x, 0);
+      transform(x);
+      sbox6(key[ 24]^x[0], key[ 25]^x[1], key[ 26]^x[2], key[ 27]^x[3], x, 0);
+      transform(x);
+      sbox7(key[ 28]^x[0], key[ 29]^x[1], key[ 30]^x[2], key[ 31]^x[3], x, 0);
+      transform(x);
+      sbox0(key[ 32]^x[0], key[ 33]^x[1], key[ 34]^x[2], key[ 35]^x[3], x, 0);
+      transform(x);
+      sbox1(key[ 36]^x[0], key[ 37]^x[1], key[ 38]^x[2], key[ 39]^x[3], x, 0);
+      transform(x);
+      sbox2(key[ 40]^x[0], key[ 41]^x[1], key[ 42]^x[2], key[ 43]^x[3], x, 0);
+      transform(x);
+      sbox3(key[ 44]^x[0], key[ 45]^x[1], key[ 46]^x[2], key[ 47]^x[3], x, 0);
+      transform(x);
+      sbox4(key[ 48]^x[0], key[ 49]^x[1], key[ 50]^x[2], key[ 51]^x[3], x, 0);
+      transform(x);
+      sbox5(key[ 52]^x[0], key[ 53]^x[1], key[ 54]^x[2], key[ 55]^x[3], x, 0);
+      transform(x);
+      sbox6(key[ 56]^x[0], key[ 57]^x[1], key[ 58]^x[2], key[ 59]^x[3], x, 0);
+      transform(x);
+      sbox7(key[ 60]^x[0], key[ 61]^x[1], key[ 62]^x[2], key[ 63]^x[3], x, 0);
+      transform(x);
+      sbox0(key[ 64]^x[0], key[ 65]^x[1], key[ 66]^x[2], key[ 67]^x[3], x, 0);
+      transform(x);
+      sbox1(key[ 68]^x[0], key[ 69]^x[1], key[ 70]^x[2], key[ 71]^x[3], x, 0);
+      transform(x);
+      sbox2(key[ 72]^x[0], key[ 73]^x[1], key[ 74]^x[2], key[ 75]^x[3], x, 0);
+      transform(x);
+      sbox3(key[ 76]^x[0], key[ 77]^x[1], key[ 78]^x[2], key[ 79]^x[3], x, 0);
+      transform(x);
+      sbox4(key[ 80]^x[0], key[ 81]^x[1], key[ 82]^x[2], key[ 83]^x[3], x, 0);
+      transform(x);
+      sbox5(key[ 84]^x[0], key[ 85]^x[1], key[ 86]^x[2], key[ 87]^x[3], x, 0);
+      transform(x);
+      sbox6(key[ 88]^x[0], key[ 89]^x[1], key[ 90]^x[2], key[ 91]^x[3], x, 0);
+      transform(x);
+      sbox7(key[ 92]^x[0], key[ 93]^x[1], key[ 94]^x[2], key[ 95]^x[3], x, 0);
+      transform(x);
+      sbox0(key[ 96]^x[0], key[ 97]^x[1], key[ 98]^x[2], key[ 99]^x[3], x, 0);
+      transform(x);
+      sbox1(key[100]^x[0], key[101]^x[1], key[102]^x[2], key[103]^x[3], x, 0);
+      transform(x);
+      sbox2(key[104]^x[0], key[105]^x[1], key[106]^x[2], key[107]^x[3], x, 0);
+      transform(x);
+      sbox3(key[108]^x[0], key[109]^x[1], key[110]^x[2], key[111]^x[3], x, 0);
+      transform(x);
+      sbox4(key[112]^x[0], key[113]^x[1], key[114]^x[2], key[115]^x[3], x, 0);
+      transform(x);
+      sbox5(key[116]^x[0], key[117]^x[1], key[118]^x[2], key[119]^x[3], x, 0);
+      transform(x);
+      sbox6(key[120]^x[0], key[121]^x[1], key[122]^x[2], key[123]^x[3], x, 0);
+      transform(x);
+      sbox7(key[124]^x[0], key[125]^x[1], key[126]^x[2], key[127]^x[3], x, 0);
+
+      x[0] ^= key[128];
+      x[1] ^= key[129];
+      x[2] ^= key[130];
+      x[3] ^= key[131];
+
+      for (int j = x.length-1; j >= 0; j--) {
+         out[o++] = (byte) (x[j] >>> 24);
+         out[o++] = (byte) (x[j] >>> 16);
+         out[o++] = (byte) (x[j] >>>  8);
+         out[o++] = (byte)  x[j];
+      }
+   }
+
+   public
+   void decrypt(byte[] in, int i, byte[] out, int o, Object K, int bs) {
+      int[] key = (int[]) K;
+      int[] x = new int[4];
+      x[3] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+      x[2] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+      x[1] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+      x[0] = (in[i++] & 0xff) << 24 | (in[i++] & 0xff) << 16 |
+             (in[i++] & 0xff) <<  8 | (in[i++] & 0xff);
+
+      sboxI7(key[128]^x[0], key[129]^x[1], key[130]^x[2], key[131]^x[3], x, 0);
+      transformInv(x, key, 124);
+      sboxI6(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key, 120);
+      sboxI5(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key, 116);
+      sboxI4(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key, 112);
+      sboxI3(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key, 108);
+      sboxI2(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key, 104);
+      sboxI1(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key, 100);
+      sboxI0(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  96);
+      sboxI7(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  92);
+      sboxI6(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  88);
+      sboxI5(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  84);
+      sboxI4(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  80);
+      sboxI3(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  76);
+      sboxI2(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  72);
+      sboxI1(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  68);
+      sboxI0(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  64);
+      sboxI7(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  60);
+      sboxI6(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  56);
+      sboxI5(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  52);
+      sboxI4(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  48);
+      sboxI3(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  44);
+      sboxI2(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  40);
+      sboxI1(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  36);
+      sboxI0(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  32);
+      sboxI7(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  28);
+      sboxI6(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  24);
+      sboxI5(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  20);
+      sboxI4(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  16);
+      sboxI3(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,  12);
+      sboxI2(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,   8);
+      sboxI1(x[0], x[1], x[2], x[3], x, 0);
+      transformInv(x, key,   4);
+      sboxI0(x[0], x[1], x[2], x[3], x, 0);
+
+      x[0] ^= key[0];
+      x[1] ^= key[1];
+      x[2] ^= key[2];
+      x[3] ^= key[3];
+
+      for (int j = x.length-1; j >= 0; j--) {
+         out[o++] = (byte) (x[j] >>> 24);
+         out[o++] = (byte) (x[j] >>> 16);
+         out[o++] = (byte) (x[j] >>>  8);
+         out[o++] = (byte)  x[j];
+      }
+   }
+
+ // Own methods
+   // -----------------------------------------------------------------
+
+   /** Serpent's linear transformation. */
+   private void transform(int[] x) {
+      x[0] = x[0] << 13 | x[0] >>> 19;
+      x[2] = x[2] << 3 | x[2] >>> 29;
+      x[1] = x[1] ^ x[0] ^ x[2];
+      x[3] = x[3] ^ x[2] ^ (x[0] << 3);
+      x[1] = x[1] << 1 | x[1] >>> 31;
+      x[3] = x[3] << 7 | x[3] >>> 25;
+      x[0] = x[0] ^ x[1] ^ x[3];
+      x[2] = x[2] ^ x[3] ^ (x[1] << 7);
+      x[0] = x[0] << 5 | x[0] >>> 27;
+      x[2] = x[2] << 22 | x[2] >>> 10;
+   }
+
+   /**
+    * The inverse linear transformation. The XOR with the key is done
+    * here to save space above.
+    *
+    * @param x The current block being decrypted.
+    * @param key The session key.
+    * @param off The index in the key to start from.
+    */
+   private void transformInv(int[] x, int[] key, int off) {
+      x[0] ^= key[off++];
+      x[1] ^= key[off++];
+      x[2] ^= key[off++];
+      x[3] ^= key[off++];
+
+      x[2] = x[2] >>> 22 | x[2] << 10;
+      x[0] = x[0] >>> 5 | x[0] << 27;
+      x[2] = x[2] ^ x[3] ^ (x[1] << 7);
+      x[0] = x[0] ^ x[1] ^ x[3];
+      x[3] = x[3] >>> 7 | x[3] << 25;
+      x[1] = x[1] >>> 1 | x[1] << 31;
+      x[3] = x[3] ^ x[2] ^ (x[0] << 3);
+      x[1] = x[1] ^ x[0] ^ x[2];
+      x[2] = x[2] >>> 3 | x[2] << 29;
+      x[0] = x[0] >>> 13 | x[0] << 19;
+   }
+
+   // Bit-flip madness methods
+   //
+   // The following S-Box functions were developed by Dag Arne Osvik,
+   // and are described in his paper, "Speeding up Serpent". They are
+   // optimized to perform on the Pentium chips, but work well here too.
+   //
+   // The methods below are Copyright (C) 2000 Dag Arne Osvik.
+
+   // These methods may be de-assembler-ized (more than one operation in
+   // each statement) for readability (?) and speed (??).
+
+   /** S-Box 0. */
+   private void sbox0(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r1 ^ r2;
+      r3 ^= r0;
+      r1 = r1 & r3 ^ r0;
+      r0 = (r0 | r3) ^ r4;
+      r4 ^= r3;
+      r3 ^= r2;
+      r2 = (r2 | r1) ^ r4;
+      r4 = ~r4 | r1;
+      r1 ^= r3 ^ r4;
+      r3 |= r0;
+      w[off  ] = r1 ^ r3;
+      w[off+1] = r4 ^ r3;
+      w[off+2] = r2;
+      w[off+3] = r0;
+   }
+
+   /** The inverse of S-Box 0. */
+   private void sboxI0(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r1;
+      r2 = ~r2;
+      r1 = (r1 | r0) ^ r2;
+      r4 = ~r4;
+      r2 |= r4;
+      r1 ^= r3;
+      r0 ^= r4;
+      r2 ^= r0;
+      r0 &= r3;
+      r4 ^= r0;
+      r0 = (r0 | r1) ^ r2;
+      r3 = r3 ^ r4 ^ r0 ^ r1;
+      r2 = (r2 ^ r1) & r3;
+      w[off  ] = r0;
+      w[off+1] = r4 ^ r2;
+      w[off+2] = r1;
+      w[off+3] = r3;
+   }
+
+   /** S-Box 1. */
+   private void sbox1(int r0, int r1, int r2, int r3, int[] w, int off) {
+      r0 = ~r0;
+      int r4 = r0;
+      r2 = ~r2;
+      r0 &= r1;
+      r2 ^= r0;
+      r0 |= r3;
+      r3 ^= r2;
+      r1 ^= r0;
+      r0 ^= r4;
+      r4 |= r1;
+      r1 ^= r3;
+      r2 = (r2 | r0) & r4;
+      r0 ^= r1;
+      w[off  ] = r2;
+      w[off+1] = r0 & r2 ^ r4;
+      w[off+2] = r3;
+      w[off+3] = r1 & r2 ^ r0;
+   }
+
+   /** The inverse of S-Box 1. */
+   private void sboxI1(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r1;
+      r1 ^= r3;
+      r3 = r3 & r1 ^ r0;
+      r4 ^= r2;
+      r2 ^= r3;
+      r0 = (r0 | r1) ^ r4 | r2;
+      r1 ^= r3;
+      r0 ^= r1;
+      r1 = (r1 | r3) ^ r0;
+      r4 = ~r4 ^ r1;
+      w[off  ] = r4;
+      w[off+1] = r0;
+      w[off+2] = r3 ^ ((r1 | r0) ^ r0 | r4);
+      w[off+3] = r2;
+   }
+
+   /** S-Box 2. */
+   private void sbox2(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r0;
+      r0 = r0 & r2 ^ r3;
+      r2 = r2 ^ r1 ^ r0;
+      r3 = (r3 | r4) ^ r1;
+      r4 ^= r2;
+      r1 = r3;
+      r3 = (r3 | r4) ^ r0;
+      r0 &= r1;
+      r4 ^= r0;
+      w[off  ] = r2;
+      w[off+1] = r3;
+      w[off+2] = r1 ^ r3 ^ r4;
+      w[off+3] = ~r4;
+   }
+
+   /** The inverse of S-Box 2. */
+   private void sboxI2(int r0, int r1, int r2, int r3, int[] w, int off) {
+      r2 ^= r3;
+      r3 ^= r0;
+      int r4 = r3;
+      r3 = r3 & r2 ^ r1;
+      r1 = (r1 | r2) ^ r4;
+      r4 &= r3;
+      r2 ^= r3;
+      r4 = r4 & r0 ^ r2;
+      r3 = ~r3;
+      r2 = (r2 & r1 | r0) ^ r3;
+      r0 = (r0 ^ r3) & r1;
+      w[off  ] = r1;
+      w[off+1] = r4;
+      w[off+2] = r2;
+      w[off+3] = r3 ^ r4 ^ r0;
+   }
+
+   /** S-Box 3. */
+   private void sbox3(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r0;
+      r0 |= r3;
+      r3 ^= r1;
+      r1 &= r4;
+      r4 = r4 ^ r2 | r1;
+      r2 ^= r3;
+      r3 = r3 & r0 ^ r4;
+      r0 ^= r1;
+      r4 = r4 & r0 ^ r2;
+      r1 = (r1 ^ r3 | r0) ^ r2;
+      r0 ^= r3;
+      w[off  ] = (r1 | r3) ^ r0;
+      w[off+1] = r1;
+      w[off+2] = r3;
+      w[off+3] = r4;
+   }
+
+   /** Inverse of S-Box 3. */
+   private void sboxI3(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r2;
+      r2 ^= r1;
+      r0 ^= r2;
+      r4 = r4 & r2 ^ r0;
+      r0 &= r1;
+      r1 ^= r3;
+      r3 |= r4;
+      r2 ^= r3;
+      r0 ^= r3;
+      r1 ^= r4;
+      r3 = r3 & r2 ^ r1;
+      r1 = (r1 ^ r0 | r2) ^ r4;
+      w[off  ] = r2;
+      w[off+1] = r1;
+      w[off+2] = r3;
+      w[off+3] = r0 ^ r3 ^ r1;
+   }
+
+   /** S-Box 4. */
+   private void sbox4(int r0, int r1, int r2, int r3, int[] w, int off) {
+      r1 ^= r3;
+      int r4 = r1;
+      r3 = ~r3;
+      r2 ^= r3;
+      r3 ^= r0;
+      r1 = r1 & r3 ^ r2;
+      r4 ^= r3;
+      r0 ^= r4;
+      r2 = r2 & r4 ^ r0;
+      r0 &= r1;
+      r3 ^= r0;
+      r4 = (r4 | r1) ^ r0;
+      w[off  ] = r1;
+      w[off+1] = r4 ^ (r2 & r3);
+      w[off+2] = ~((r0 | r3) ^ r2);
+      w[off+3] = r3;
+   }
+
+   /** Inverse of S-Box 4. */
+   private void sboxI4(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r2;
+      r2 = r2 & r3 ^ r1;
+      r1 = (r1 | r3) & r0;
+      r4 = r4 ^ r2 ^ r1;
+      r1 &= r2;
+      r0 = ~r0;
+      r3 ^= r4;
+      r1 ^= r3;
+      r3 = r3 & r0 ^ r2;
+      r0 ^= r1;
+      r3 ^= r0;
+      w[off  ] = r0;
+      w[off+1] = r3 ^ r0;
+      w[off+2] = (r2 & r0 ^ r4 | r3) ^ r1;
+      w[off+3] = r4;
+   }
+
+   /** S-Box 5. */
+   private void sbox5(int r0, int r1, int r2, int r3, int[] w, int off) {
+      r0 ^= r1;
+      r1 ^= r3;
+      int r4 = r1;
+      r3 = ~r3;
+      r1 &= r0;
+      r2 ^= r3;
+      r1 ^= r2;
+      r2 |= r4;
+      r4 ^= r3;
+      r3 = r3 & r1 ^ r0;
+      r4 = r4 ^ r1 ^ r2;
+      w[off  ] = r1;
+      w[off+1] = r3;
+      w[off+2] = r0 & r3 ^ r4;
+      w[off+3] = ~(r2 ^ r0) ^ (r4 | r3);
+   }
+
+   /** Inverse of S-Box 5. */
+   private void sboxI5(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r3;
+      r1 = ~r1;
+      r2 ^= r1;
+      r3 = (r3 | r0) ^ r2;
+      r4 ^= r3;
+      r2 = (r2 | r1) & r0 ^ r4;
+      r4 = (r4 | r0) ^ r1 ^ r2;
+      r1 = r1 & r2 ^ r3;
+      r3 &= r4;
+      r4 ^= r1;
+      w[off  ] = r1;
+      w[off+1] = ~r4;
+      w[off+2] = r3 ^ r4 ^ r0;
+      w[off+3] = r2;
+   }
+
+   /** S-Box 6. */
+   private void sbox6(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r3;
+      r2 = ~r2;
+      r3 = r3 & r0 ^ r2;
+      r0 ^= r4;
+      r2 = (r2 | r4) ^ r0;
+      r1 ^= r3;
+      r0 |= r1;
+      r2 ^= r1;
+      r4 ^= r0;
+      r0 = (r0 | r3) ^ r2;
+      r4 = r4 ^ r3 ^ r0;
+      w[off  ] = r0;
+      w[off+1] = r1;
+      w[off+2] = r4;
+      w[off+3] = r2 & r4 ^ ~r3;
+   }
+
+   /** Inverse of S-Box 6. */
+   private void sboxI6(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r2;
+      r0 ^= r2;
+      r2 &= r0;
+      r4 ^= r3;
+      r3 ^= r1;
+      r2 = ~r2 ^ r3;
+      r4 |= r0;
+      r0 ^= r2;
+      r3 ^= r4;
+      r4 ^= r1;
+      r1 = r1 & r3 ^ r0;
+      r0 = r0 ^ r3 | r2;
+      w[off  ] = r1;
+      w[off+1] = r2;
+      w[off+2] = r4 ^ r0;
+      w[off+3] = r3 ^ r1;
+   }
+
+   /** S-Box 7. */
+   private void sbox7(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r1;
+      r1 = (r1 | r2) ^ r3;
+      r4 ^= r2;
+      r2 ^= r1;
+      r3 = (r3 | r4) & r0;
+      r4 ^= r2;
+      r3 ^= r1;
+      r1 = (r1 | r4) ^ r0;
+      r0 = (r0 | r4) ^ r2;
+      r1 ^= r4;
+      r2 ^= r1;
+      w[off  ] = r4 ^ (~r2 | r0);
+      w[off+1] = r3;
+      w[off+2] = r1 & r0 ^ r4;
+      w[off+3] = r0;
+   }
+
+   /** Inverse of S-Box 7. */
+   private void sboxI7(int r0, int r1, int r2, int r3, int[] w, int off) {
+      int r4 = r2;
+      r2 = ~(r2 ^ r0);
+      r0 &= r3;
+      r4 |= r3;
+      r3 ^= r1;
+      r1 |= r0;
+      r0 ^= r2;
+      r2 &= r4;
+      r3 &= r4;
+      r1 ^= r2;
+      r2 ^= r0;
+      r0 = (r0 | r2) ^ r3;
+      r4 ^= r1;
+      w[off  ] = r3 ^ r4 ^ r2;
+      w[off+1] = r0;
+      w[off+2] = r1;
+      w[off+3] = (r4 | r0) ^ r2;
+   }
+}

---

From: "Raif S. Naffah" <[email-masked]>
Date: Thu, 6 Jun 2002 21:10:34 +1000

hello Casey,

----- Original Message -----
From: "Casey Marshall" <[email-masked]>
To: <[email-masked]>
Sent: Wednesday, June 05, 2002 10:15 AM
Subject: [Classpathx-crypto] [patch] Serpent cipher

> in a GPL'd ADA implementation from
http://www.ii.uib.no/~gisle/serpent.html.

thanks a bunch for your contribution :-)

we dont have an established etiquette for contributions in this project,
besides the coding style :-) but i'm sure we'll come up with something
intelligent as we go.

> Serpent class itself. Classpathx is welcome to use it...

i'll add the patches during this weekend, along with some classes and
algorithms i've been working on (HMAC, UMAC, etc...).

btw, do you have (access to) the test vectors for Serpent?  we should have a
junit test case to exercise and produce/compare some of the test vectors for
every algorithm so as to certify correctness (e.g.
source/test/cipher/TestOfSquare).

thanks again for your contribution + cheers;
rsn

---

From: Casey Marshall <[email-masked]>
Date: Thu, 6 Jun 2002 15:45:55 -0700 (PDT)

> source/test/cipher/TestOfSquare).

Earlier today I generated some KAT and Monte-Carlo test vectors and
compared them to those included in the Serpent team's AES submission.
The implementation appears correct (at least, my faith in it is a bit
stronger). I'll see about putting together a test case for it, however.

Also, a question: it appears as though the library is working with the
assumption that all of its ciphers are not stateful, ie something like:

	cipher.encryptBlock(pt, 0, ct, 0);
	cipher.decryptBlock(ct, 0, cpt, 0);

will result in pt==cpt (and this is the case, I think, with all the
current cipher algorithms, as well as most others that I'm familiar with).
This isn't strictly true, for example, for ARCFOUR, whose s-boxes evolve
over time. So would stateful ciphers need to be careful about this (e.g.
keeping s-boxes for encryption and decryption), or could one assume that
this is not, in practice, the case?

(Bonus: yes, ARCFOUR is a stream cipher, so would a seperate interface
(IStreamCipher) be a solution?)

Cheers,

---

From: "Raif S. Naffah" <[email-masked]>
Date: Fri, 7 Jun 2002 23:20:11 +1000

hello Casey,

my comments are in-lined below.

cheers;
rsn
----- Original Message -----
From: "Casey Marshall" <[email-masked]>
To: "Raif S. Naffah" <[email-masked]>
Cc: <[email-masked]>
Sent: Friday, June 07, 2002 8:45 AM
Subject: Re: [Classpathx-crypto] [patch] Serpent cipher

> stronger). I'll see about putting together a test case for it, however.

thanks again :-)

> This isn't strictly true...

this is always true with symmetric key block ciphers.

>..., for example, for ARCFOUR, whose s-boxes evolve

the thing to clarify here is that:

a. both types of ciphers are stateful, yet
b. one type (the symmetric-key block-ciphers eg. aes, rijndael, serpent, and
all gnu.crypto.cipher classes) is invertible, while the other (not yet
implemented in gnu.crypto) is not.

> (IStreamCipher) be a solution?)

yes! as far as i know, it's the only solution.

for other types of stream ciphers, have a look at some newly designed stream
ciphers, submitted in the NESSIE project --see
https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions.html.

> _______________________________________________
> Classpathx-crypto mailing list
> [email-masked]
> http://mail.gnu.org/mailman/listinfo/classpathx-crypto
>