1 module mysql.sha1; 2 3 import std.stdio; 4 import std.conv; 5 6 enum 7 { 8 shaSuccess = 0, 9 shaNull, /* Null pointer parameter */ 10 shaInputTooLong, /* input data too long */ 11 shaStateError /* called Input after Result */ 12 } 13 14 immutable uint SHA1HashSize = 20; 15 16 /* 17 * This structure will hold context information for the SHA-1 18 * hashing operation 19 */ 20 struct SHA1 21 { 22 private: 23 uint[SHA1HashSize/4] Intermediate_Hash; /* Message Digest */ 24 25 uint Length_Low; // Message length in bits 26 uint Length_High; // Message length in bits 27 28 // Index into message block array 29 short Message_Block_Index; 30 ubyte[64] Message_Block; /* 512-bit message blocks */ 31 32 bool Computed; /* Is the digest computed? */ 33 bool Corrupted; /* Is the message digest corrupted? */ 34 int err; 35 36 uint SHA1CircularShift(int bits, uint word) 37 { 38 return (((word) << (bits)) | ((word) >> (32-(bits)))); 39 } 40 41 42 void ProcessMessageBlock() 43 { 44 const uint K[] = [ 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 ]; 45 int t; /* Loop counter */ 46 uint temp; /* Temporary word value */ 47 uint[80] W; /* Word sequence */ 48 uint A, B, C, D, E; /* Word buffers */ 49 50 /* 51 * Initialize the first 16 words in the array W 52 */ 53 for(t = 0; t < 16; t++) 54 { 55 W[t] = Message_Block[t * 4] << 24; 56 W[t] |= Message_Block[t * 4 + 1] << 16; 57 W[t] |= Message_Block[t * 4 + 2] << 8; 58 W[t] |= Message_Block[t * 4 + 3]; 59 } 60 61 for(t = 16; t < 80; t++) 62 { 63 W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); 64 } 65 66 A = Intermediate_Hash[0]; 67 B = Intermediate_Hash[1]; 68 C = Intermediate_Hash[2]; 69 D = Intermediate_Hash[3]; 70 E = Intermediate_Hash[4]; 71 72 for(t = 0; t < 20; t++) 73 { 74 temp = SHA1CircularShift(5,A) + 75 ((B & C) | ((~B) & D)) + E + W[t] + K[0]; 76 E = D; 77 D = C; 78 C = SHA1CircularShift(30,B); 79 80 B = A; 81 A = temp; 82 } 83 84 for(t = 20; t < 40; t++) 85 { 86 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; 87 E = D; 88 D = C; 89 C = SHA1CircularShift(30,B); 90 B = A; 91 A = temp; 92 } 93 94 for(t = 40; t < 60; t++) 95 { 96 temp = SHA1CircularShift(5,A) + 97 ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; 98 E = D; 99 D = C; 100 C = SHA1CircularShift(30,B); 101 B = A; 102 A = temp; 103 } 104 105 for(t = 60; t < 80; t++) 106 { 107 temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; 108 E = D; 109 D = C; 110 C = SHA1CircularShift(30,B); 111 B = A; 112 A = temp; 113 } 114 115 Intermediate_Hash[0] += A; 116 Intermediate_Hash[1] += B; 117 Intermediate_Hash[2] += C; 118 Intermediate_Hash[3] += D; 119 Intermediate_Hash[4] += E; 120 121 Message_Block_Index = 0; 122 } 123 124 void PadMessage() 125 { 126 if (Message_Block_Index > 55) 127 { 128 Message_Block[Message_Block_Index++] = 0x80; 129 while(Message_Block_Index < 64) 130 { 131 Message_Block[Message_Block_Index++] = 0; 132 } 133 134 ProcessMessageBlock(); 135 136 while(Message_Block_Index < 56) 137 { 138 Message_Block[Message_Block_Index++] = 0; 139 } 140 } 141 else 142 { 143 Message_Block[Message_Block_Index++] = 0x80; 144 while(Message_Block_Index < 56) 145 { 146 147 Message_Block[Message_Block_Index++] = 0; 148 } 149 } 150 151 /* 152 * Store the message length as the last 8 octets 153 */ 154 Message_Block[56] = cast(ubyte) (Length_High >> 24); 155 Message_Block[57] = cast(ubyte) (Length_High >> 16); 156 Message_Block[58] = cast(ubyte) (Length_High >> 8); 157 Message_Block[59] = cast(ubyte) Length_High; 158 Message_Block[60] = cast(ubyte) (Length_Low >> 24); 159 Message_Block[61] = cast(ubyte) (Length_Low >> 16); 160 Message_Block[62] = cast(ubyte) (Length_Low >> 8); 161 Message_Block[63] = cast(ubyte) Length_Low; 162 163 ProcessMessageBlock(); 164 } 165 166 public: 167 168 this(int dummy = 0) { reset(); dummy++; } 169 170 @property error() { return err; } 171 172 void reset() 173 { 174 Length_Low = 0; 175 Length_High = 0; 176 Message_Block_Index = 0; 177 178 Intermediate_Hash = [ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 ]; 179 Computed = false; 180 Corrupted = false; 181 } 182 183 ubyte[] result() 184 { 185 if (Corrupted) 186 return null; 187 188 ubyte[] rv; 189 rv.length = SHA1HashSize; 190 191 if (!Computed) 192 { 193 PadMessage(); 194 Message_Block[] = 0; 195 Length_Low = 0; /* and clear length */ 196 Length_High = 0; 197 Computed = true; 198 } 199 200 for (int i = 0; i < SHA1HashSize; i++) 201 { 202 rv[i] = cast(ubyte) (Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ))); 203 } 204 205 return rv; 206 } 207 208 bool input(const(ubyte)* message_array, size_t length) 209 { 210 if (!length) 211 return true; 212 213 if (message_array is null) 214 { 215 err = shaNull; 216 return false; 217 } 218 219 if (Computed) 220 { 221 err = shaStateError; 222 Corrupted = true; 223 return false; 224 } 225 226 if (Corrupted) 227 return false; 228 229 while(length-- && !Corrupted) 230 { 231 Message_Block[Message_Block_Index++] = (*message_array & 0xFF); 232 233 Length_Low += 8; 234 if (Length_Low == 0) // wrapped round 235 { 236 Length_High++; 237 if (Length_High == 0) // wrapped round 238 { 239 // Message is too long 240 Corrupted = true; 241 err = shaInputTooLong; 242 return false; 243 } 244 } 245 246 if (Message_Block_Index == 64) 247 ProcessMessageBlock(); 248 249 message_array++; 250 } 251 return true; 252 } 253 } 254