Source for gnu.java.security.hash.MD2

   1: /* MD2.java --
   2:    Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2 of the License, or (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.java.security.hash;
  40: 
  41: import gnu.java.security.Registry;
  42: import gnu.java.security.util.Util;
  43: 
  44: /**
  45:  * An implementation of the MD2 message digest algorithm.
  46:  * <p>
  47:  * MD2 is not widely used. Unless it is needed for compatibility with
  48:  * existing systems, it is not recommended for use in new applications.
  49:  * <p>
  50:  * References:
  51:  * <ol>
  52:  *    <li>The <a href="http://www.ietf.org/rfc/rfc1319.txt">MD2</a>
  53:  *    Message-Digest Algorithm.<br>
  54:  *    B. Kaliski.</li>
  55:  *    <li>The <a href="http://www.rfc-editor.org/errata.html">RFC ERRATA PAGE</a>
  56:  *    under section RFC 1319.</li>
  57:  * </ol>
  58:  */
  59: public class MD2
  60:     extends BaseHash
  61: {
  62:   /** An MD2 message digest is always 128-bits long, or 16 bytes. */
  63:   private static final int DIGEST_LENGTH = 16;
  64: 
  65:   /** The MD2 algorithm operates on 128-bit blocks, or 16 bytes. */
  66:   private static final int BLOCK_LENGTH = 16;
  67: 
  68:   /** 256 byte "random" permutation of the digits of pi. */
  69:   private static final byte[] PI = {
  70:         41,   46,   67,  -55,  -94,  -40,  124,   1,
  71:         61,   54,   84,  -95,  -20,  -16,    6,  19,
  72:         98,  -89,    5,  -13,  -64,  -57,  115, -116,
  73:       -104, -109,   43,  -39,  -68,   76, -126,  -54,
  74:         30, -101,   87,   60,   -3,  -44,  -32,   22,
  75:        103,   66,  111,   24, -118,   23,  -27,   18,
  76:        -66,   78,  -60,  -42,  -38,  -98,  -34,   73,
  77:        -96,   -5,  -11, -114,  -69,   47,  -18,  122,
  78:        -87,  104,  121, -111,   21,  -78,    7,   63,
  79:       -108,  -62,   16, -119,   11,   34,   95,   33,
  80:       -128,  127,   93, -102,   90, -112,   50,   39,
  81:         53,   62,  -52,  -25,  -65,   -9, -105,    3,
  82:         -1,   25,   48,  -77,   72,  -91,  -75,  -47,
  83:        -41,   94, -110,   42,  -84,   86,  -86,  -58,
  84:         79,  -72,   56,  -46, -106,  -92,  125,  -74,
  85:        118,   -4,  107,  -30, -100,  116,    4,  -15,
  86:         69,  -99,  112,   89,  100,  113, -121,   32,
  87:       -122,   91,  -49,  101,  -26,   45,  -88,    2,
  88:         27,   96,   37,  -83,  -82,  -80,  -71,  -10,
  89:         28,   70,   97,  105,   52,   64,  126,   15,
  90:         85,   71,  -93,   35,  -35,   81,  -81,   58,
  91:        -61,   92,   -7,  -50,  -70,  -59,  -22,   38,
  92:         44,   83,   13,  110, -123,   40, -124,    9,
  93:        -45,  -33,  -51,  -12,   65, -127,   77,   82,
  94:        106,  -36,   55,  -56,  108,  -63,  -85,   -6,
  95:         36,  -31,  123,    8,   12,  -67,  -79,   74,
  96:        120, -120, -107, -117,  -29,   99,  -24,  109,
  97:        -23,  -53,  -43,   -2,   59,    0,   29,   57,
  98:        -14,  -17,  -73,   14,  102,   88,  -48,  -28,
  99:        -90,  119,  114,   -8,  -21,  117,   75,   10,
 100:         49,   68,   80,  -76, -113,  -19,   31,   26,
 101:        -37, -103, -115,   51, - 97,   17, -125,   20 };
 102: 
 103:   /** The output of this message digest when no data has been input. */
 104:   private static final String DIGEST0 = "8350E5A3E24C153DF2275C9F80692773";
 105: 
 106:   /** caches the result of the correctness test, once executed. */
 107:   private static Boolean valid;
 108: 
 109:   /** The checksum computed so far. */
 110:   private byte[] checksum;
 111: 
 112:   /**
 113:    * Work array needed by encrypt method. First <code>BLOCK_LENGTH</code> bytes
 114:    * are also used to store the running digest.
 115:    */
 116:   private byte[] work;
 117: 
 118:   /** Creates a new MD2 digest ready for use. */
 119:   public MD2()
 120:   {
 121:     super(Registry.MD2_HASH, DIGEST_LENGTH, BLOCK_LENGTH);
 122:   }
 123: 
 124:   /**
 125:    * Private constructor used for cloning.
 126:    *
 127:    * @param md2 the instance to clone.
 128:    */
 129:   private MD2(MD2 md2)
 130:   {
 131:     this();
 132: 
 133:     // superclass field
 134:     this.count = md2.count;
 135:     this.buffer = (byte[]) md2.buffer.clone();
 136:     // private field
 137:     this.checksum = (byte[]) md2.checksum.clone();
 138:     this.work = (byte[]) md2.work.clone();
 139:   }
 140: 
 141:   public Object clone()
 142:   {
 143:     return new MD2(this);
 144:   }
 145: 
 146:   protected byte[] getResult()
 147:   {
 148:     byte[] result = new byte[DIGEST_LENGTH];
 149:     // Encrypt checksum as last block.
 150:     encryptBlock(checksum, 0);
 151:     for (int i = 0; i < BLOCK_LENGTH; i++)
 152:       result[i] = work[i];
 153: 
 154:     return result;
 155:   }
 156: 
 157:   protected void resetContext()
 158:   {
 159:     checksum = new byte[BLOCK_LENGTH];
 160:     work = new byte[BLOCK_LENGTH * 3];
 161:   }
 162: 
 163:   public boolean selfTest()
 164:   {
 165:     if (valid == null)
 166:       {
 167:         String d = Util.toString(new MD2().digest());
 168:         valid = Boolean.valueOf(DIGEST0.equals(d));
 169:       }
 170:     return valid.booleanValue();
 171:   }
 172: 
 173:   /**
 174:    * Generates an array of padding bytes. The padding is defined as
 175:    * <code>i</code> bytes of value <code>i</code>, where <code>i</code> is the
 176:    * number of bytes to fill the last block of the message to
 177:    * <code>BLOCK_LENGTH</code> bytes (or <code>BLOCK_LENGTH</code> bytes when
 178:    * the last block was completely full).
 179:    *
 180:    * @return the bytes to pad the remaining bytes in the buffer before
 181:    * completing a hash operation.
 182:    */
 183:   protected byte[] padBuffer()
 184:   {
 185:     int length = BLOCK_LENGTH - (int) (count % BLOCK_LENGTH);
 186:     if (length == 0)
 187:       length = BLOCK_LENGTH;
 188: 
 189:     byte[] pad = new byte[length];
 190:     for (int i = 0; i < length; i++)
 191:       pad[i] = (byte) length;
 192: 
 193:     return pad;
 194:   }
 195: 
 196:   /**
 197:    * Adds <code>BLOCK_LENGTH</code> bytes to the running digest.
 198:    *
 199:    * @param in the byte array to take the <code>BLOCK_LENGTH</code> bytes from.
 200:    * @param off the offset to start from in the given byte array.
 201:    */
 202:   protected void transform(byte[] in, int off)
 203:   {
 204:     updateCheckSumAndEncryptBlock(in, off);
 205:   }
 206: 
 207:   /**
 208:    * Adds a new block (<code>BLOCK_LENGTH</code> bytes) to the running digest
 209:    * from the given byte array starting from the given offset.
 210:    */
 211:   private void encryptBlock(byte[] in, int off)
 212:   {
 213:     for (int i = 0; i < BLOCK_LENGTH; i++)
 214:       {
 215:         byte b = in[off + i];
 216:         work[BLOCK_LENGTH + i] = b;
 217:         work[BLOCK_LENGTH * 2 + i] = (byte)(work[i] ^ b);
 218:       }
 219:     byte t = 0;
 220:     for (int i = 0; i < 18; i++)
 221:       {
 222:         for (int j = 0; j < 3 * BLOCK_LENGTH; j++)
 223:           {
 224:             t = (byte)(work[j] ^ PI[t & 0xFF]);
 225:             work[j] = t;
 226:           }
 227:         t = (byte)(t + i);
 228:       }
 229:   }
 230: 
 231:   /**
 232:    * Optimized method that combines a checksum update and encrypt of a block.
 233:    */
 234:   private void updateCheckSumAndEncryptBlock(byte[] in, int off)
 235:   {
 236:     byte l = checksum[BLOCK_LENGTH - 1];
 237:     for (int i = 0; i < BLOCK_LENGTH; i++)
 238:       {
 239:         byte b = in[off + i];
 240:         work[BLOCK_LENGTH + i] = b;
 241:         work[BLOCK_LENGTH * 2 + i] = (byte)(work[i] ^ b);
 242:         l = (byte)(checksum[i] ^ PI[(b ^ l) & 0xFF]);
 243:         checksum[i] = l;
 244:       }
 245:     byte t = 0;
 246:     for (int i = 0; i < 18; i++)
 247:       {
 248:         for (int j = 0; j < 3 * BLOCK_LENGTH; j++)
 249:           {
 250:             t = (byte)(work[j] ^ PI[t & 0xFF]);
 251:             work[j] = t;
 252:           }
 253:         t = (byte)(t + i);
 254:       }
 255:   }
 256: }