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