1 /******************************************************************************* 2 3 copyright: Copyright (c) 2006 Tango. All rights reserved 4 5 license: BSD style: see doc/license.txt for details 6 7 version: Initial release: Feb 2006 8 9 author: Regan Heath, Oskar Linde 10 11 This module implements the MD2 Message Digest Algorithm as described 12 by RFC 1319 The MD2 Message-Digest Algorithm. B. Kaliski. April 1992. 13 14 *******************************************************************************/ 15 16 module tango.util.digest.Md2; 17 18 public import tango.util.digest.Digest; 19 20 private import tango.util.digest.MerkleDamgard; 21 22 /******************************************************************************* 23 24 *******************************************************************************/ 25 26 class Md2 : MerkleDamgard 27 { 28 private ubyte[16] C, 29 state; 30 31 /*********************************************************************** 32 33 Construct an Md2 34 35 ***********************************************************************/ 36 37 this() { } 38 39 /*********************************************************************** 40 41 Initialize the cipher 42 43 Remarks: 44 Returns the cipher state to it's initial value 45 46 ***********************************************************************/ 47 48 protected override void reset() 49 { 50 super.reset(); 51 state[] = 0; 52 C[] = 0; 53 } 54 55 /*********************************************************************** 56 57 Obtain the digest 58 59 Returns: 60 the digest 61 62 Remarks: 63 Returns a digest of the current cipher state, this may 64 be the final digest, or a digest of the state between 65 calls to update() 66 67 ***********************************************************************/ 68 69 protected override void createDigest(ubyte[] buf) 70 { 71 buf[] = state[]; 72 } 73 74 /*********************************************************************** 75 76 The MD 2 digest size is 16 bytes 77 78 ***********************************************************************/ 79 80 override uint digestSize() { return 16; } 81 82 /*********************************************************************** 83 84 block size 85 86 Returns: 87 the block size 88 89 Remarks: 90 Specifies the size (in bytes) of the block of data to pass to 91 each call to transform(). For MD2 the blockSize is 16. 92 93 ***********************************************************************/ 94 95 protected override uint blockSize() 96 { 97 return 16; 98 } 99 100 /*********************************************************************** 101 102 Length padding size 103 104 Returns: 105 the length padding size 106 107 Remarks: 108 Specifies the size (in bytes) of the padding which uses the 109 length of the data which has been ciphered, this padding is 110 carried out by the padLength method. For MD2 the addSize is 111 0 112 113 ***********************************************************************/ 114 115 protected override uint addSize() 116 { 117 return 0; 118 } 119 120 /*********************************************************************** 121 122 Pads the cipher data 123 124 Params: 125 data = a slice of the cipher buffer to fill with padding 126 127 Remarks: 128 Fills the passed buffer slice with the appropriate padding 129 for the final call to transform(). This padding will fill 130 the cipher buffer up to blockSize()-addSize(). 131 132 ***********************************************************************/ 133 134 protected override void padMessage (ubyte[] data) 135 { 136 /* Padding is performed as follows: "i" bytes of value "i" 137 * are appended to the message so that the length in bytes 138 * of the padded message becomes congruent to 0, modulo 16. 139 * At least one byte and at most 16 bytes are appended. 140 */ 141 data[0..$] = cast(ubyte) data.length; 142 } 143 144 /*********************************************************************** 145 146 Performs the cipher on a block of data 147 148 Params: 149 data = the block of data to cipher 150 151 Remarks: 152 The actual cipher algorithm is carried out by this method on 153 the passed block of data. This method is called for every 154 blockSize() bytes of input data and once more with the 155 remaining data padded to blockSize(). 156 157 ***********************************************************************/ 158 159 protected override void transform (const(ubyte[]) input) 160 { 161 ubyte[48] X; 162 uint t,i,j; 163 164 X[0..16] = state[]; 165 X[16..32] = input[]; 166 167 for (i = 0; i < 16; i++) 168 X[i+32] = cast(ubyte) (state[i] ^ input[i]); 169 170 t = 0; 171 for (i = 0; i < 18; i++) 172 { 173 for (j = 0; j < 48; j++) 174 t = X[j] ^= PI[t]; 175 t = (t + i) & 0xff; 176 } 177 178 state[] = X[0..16]; 179 180 t = C[15]; 181 182 for (i = 0; i < 16; i++) 183 t = C[i] ^= PI[input[i] ^ t]; 184 } 185 186 /*********************************************************************** 187 188 Final processing of cipher. 189 190 Remarks: 191 This method is called after the final transform just prior to 192 the creation of the final digest. The MD2 algorithm requires 193 an additional step at this stage. Future ciphers may or may not 194 require this method. 195 196 ***********************************************************************/ 197 198 protected override void extend() 199 { 200 transform(C); 201 } 202 } 203 204 205 /******************************************************************************* 206 207 *******************************************************************************/ 208 209 private __gshared immutable ubyte[256] PI = 210 [ 211 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, 212 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, 213 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, 214 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, 215 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, 216 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, 217 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, 218 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, 219 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, 220 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, 221 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, 222 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, 223 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, 224 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, 225 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, 226 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, 227 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, 228 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 229 ]; 230 231 232 /******************************************************************************* 233 234 *******************************************************************************/ 235 236 debug(UnitTest) 237 { 238 unittest 239 { 240 __gshared immutable immutable(char)[][] strings = 241 [ 242 "", 243 "a", 244 "abc", 245 "message digest", 246 "abcdefghijklmnopqrstuvwxyz", 247 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 248 "12345678901234567890123456789012345678901234567890123456789012345678901234567890" 249 ]; 250 251 __gshared immutable immutable(char)[][] results = 252 [ 253 "8350e5a3e24c153df2275c9f80692773", 254 "32ec01ec4a6dac72c0ab96fb34c0b5d1", 255 "da853b0d3f88d99b30283a69e6ded6bb", 256 "ab4f496bfb2a530b219ff33031fe06b0", 257 "4e8ddff3650292ab5a4108c3aa47940b", 258 "da33def2a42df13975352846c30338cd", 259 "d5976f79d83d3a0dc9806c3c66f3efd8" 260 ]; 261 262 Md2 h = new Md2(); 263 264 foreach (int i, immutable(char)[] s; strings) 265 { 266 h.update(s); 267 char[] d = h.hexDigest(); 268 assert(d == results[i],":("~s~")("~d~")!=("~results[i]~")"); 269 } 270 } 271 } 272