|
| 1 | +/* |
| 2 | + * md5.c |
| 3 | + * |
| 4 | + * Implements the MD5 Message-Digest Algorithm as specified in |
| 5 | + * RFC 1321. This implementation is a simple one, in that it |
| 6 | + * needs every input byte to be buffered before doing any |
| 7 | + * calculations. I do not expect this file to be used for |
| 8 | + * general purpose MD5'ing of large amounts of data, only for |
| 9 | + * generating hashed passwords from limited input. |
| 10 | + * |
| 11 | + * Sverre H. Huseby <sverrehu@online.no> |
| 12 | + */ |
| 13 | + |
| 14 | + |
| 15 | +#include<stdio.h> |
| 16 | +#include<stdlib.h> |
| 17 | +#include<string.h> |
| 18 | +#include<errno.h> |
| 19 | + |
| 20 | +#include"postgres.h" |
| 21 | +#include"libpq/md5.h" |
| 22 | + |
| 23 | +/* |
| 24 | + *PRIVATE FUNCTIONS |
| 25 | + */ |
| 26 | + |
| 27 | +typedefunsignedcharunsigned8; |
| 28 | +typedefunsignedintunsigned32; |
| 29 | +typedefunsigned longunsigned64; |
| 30 | + |
| 31 | +/* |
| 32 | + *The returned array is allocated using malloc. the caller should free it |
| 33 | + * when it is no longer needed. |
| 34 | + */ |
| 35 | +staticunsigned8* |
| 36 | +createPaddedCopyWithLength(unsigned8*b,unsigned32*l) |
| 37 | +{ |
| 38 | +unsigned8*ret; |
| 39 | +unsigned32q; |
| 40 | +unsigned32len,newLen448; |
| 41 | +unsigned64len64; |
| 42 | + |
| 43 | +len= ((b==NULL) ?0 :*l); |
| 44 | +newLen448=len+64- (len %64)-8; |
| 45 | +if (newLen448 <=len) |
| 46 | +newLen448+=64; |
| 47 | + |
| 48 | +*l=newLen448+8; |
| 49 | +if ((ret= (unsigned8*)malloc(sizeof(unsigned8)**l))==NULL) |
| 50 | +returnNULL; |
| 51 | + |
| 52 | +if (b!=NULL) |
| 53 | +memcpy(ret,b,sizeof(unsigned8)*len); |
| 54 | + |
| 55 | +/* pad */ |
| 56 | +ret[len]=0x80; |
| 57 | +for (q=len+1;q<newLen448;q++) |
| 58 | +ret[q]=0x00; |
| 59 | + |
| 60 | +/* append length as a 64 bit bitcount */ |
| 61 | +len64=len; |
| 62 | +len64 <<=3; |
| 63 | +q=newLen448; |
| 64 | +ret[q++]= (len64&0xFF); |
| 65 | +len64 >>=8; |
| 66 | +ret[q++]= (len64&0xFF); |
| 67 | +len64 >>=8; |
| 68 | +ret[q++]= (len64&0xFF); |
| 69 | +len64 >>=8; |
| 70 | +ret[q++]= (len64&0xFF); |
| 71 | +len64 >>=8; |
| 72 | +ret[q++]= (len64&0xFF); |
| 73 | +len64 >>=8; |
| 74 | +ret[q++]= (len64&0xFF); |
| 75 | +len64 >>=8; |
| 76 | +ret[q++]= (len64&0xFF); |
| 77 | +len64 >>=8; |
| 78 | +ret[q]= (len64&0xFF); |
| 79 | + |
| 80 | +returnret; |
| 81 | +} |
| 82 | + |
| 83 | +#defineF(x,y,z) (((x) & (y)) | (~(x) & (z))) |
| 84 | +#defineG(x,y,z) (((x) & (z)) | ((y) & ~(z))) |
| 85 | +#defineH(x,y,z) ((x) ^ (y) ^ (z)) |
| 86 | +#defineI(x,y,z) ((y) ^ ((x) | ~(z))) |
| 87 | +#defineROT_LEFT(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) |
| 88 | + |
| 89 | +staticvoid |
| 90 | +doTheRounds(unsigned32X[16],unsigned32state[4]) |
| 91 | +{ |
| 92 | +unsigned32a,b,c,d; |
| 93 | + |
| 94 | +a=state[0]; |
| 95 | +b=state[1]; |
| 96 | +c=state[2]; |
| 97 | +d=state[3]; |
| 98 | + |
| 99 | +/* round 1 */ |
| 100 | +a=b+ROT_LEFT((a+F(b,c,d)+X[0]+0xd76aa478),7);/* 1 */ |
| 101 | +d=a+ROT_LEFT((d+F(a,b,c)+X[1]+0xe8c7b756),12);/* 2 */ |
| 102 | +c=d+ROT_LEFT((c+F(d,a,b)+X[2]+0x242070db),17);/* 3 */ |
| 103 | +b=c+ROT_LEFT((b+F(c,d,a)+X[3]+0xc1bdceee),22);/* 4 */ |
| 104 | +a=b+ROT_LEFT((a+F(b,c,d)+X[4]+0xf57c0faf),7);/* 5 */ |
| 105 | +d=a+ROT_LEFT((d+F(a,b,c)+X[5]+0x4787c62a),12);/* 6 */ |
| 106 | +c=d+ROT_LEFT((c+F(d,a,b)+X[6]+0xa8304613),17);/* 7 */ |
| 107 | +b=c+ROT_LEFT((b+F(c,d,a)+X[7]+0xfd469501),22);/* 8 */ |
| 108 | +a=b+ROT_LEFT((a+F(b,c,d)+X[8]+0x698098d8),7);/* 9 */ |
| 109 | +d=a+ROT_LEFT((d+F(a,b,c)+X[9]+0x8b44f7af),12);/* 10 */ |
| 110 | +c=d+ROT_LEFT((c+F(d,a,b)+X[10]+0xffff5bb1),17);/* 11 */ |
| 111 | +b=c+ROT_LEFT((b+F(c,d,a)+X[11]+0x895cd7be),22);/* 12 */ |
| 112 | +a=b+ROT_LEFT((a+F(b,c,d)+X[12]+0x6b901122),7);/* 13 */ |
| 113 | +d=a+ROT_LEFT((d+F(a,b,c)+X[13]+0xfd987193),12);/* 14 */ |
| 114 | +c=d+ROT_LEFT((c+F(d,a,b)+X[14]+0xa679438e),17);/* 15 */ |
| 115 | +b=c+ROT_LEFT((b+F(c,d,a)+X[15]+0x49b40821),22);/* 16 */ |
| 116 | + |
| 117 | +/* round 2 */ |
| 118 | +a=b+ROT_LEFT((a+G(b,c,d)+X[1]+0xf61e2562),5);/* 17 */ |
| 119 | +d=a+ROT_LEFT((d+G(a,b,c)+X[6]+0xc040b340),9);/* 18 */ |
| 120 | +c=d+ROT_LEFT((c+G(d,a,b)+X[11]+0x265e5a51),14);/* 19 */ |
| 121 | +b=c+ROT_LEFT((b+G(c,d,a)+X[0]+0xe9b6c7aa),20);/* 20 */ |
| 122 | +a=b+ROT_LEFT((a+G(b,c,d)+X[5]+0xd62f105d),5);/* 21 */ |
| 123 | +d=a+ROT_LEFT((d+G(a,b,c)+X[10]+0x02441453),9);/* 22 */ |
| 124 | +c=d+ROT_LEFT((c+G(d,a,b)+X[15]+0xd8a1e681),14);/* 23 */ |
| 125 | +b=c+ROT_LEFT((b+G(c,d,a)+X[4]+0xe7d3fbc8),20);/* 24 */ |
| 126 | +a=b+ROT_LEFT((a+G(b,c,d)+X[9]+0x21e1cde6),5);/* 25 */ |
| 127 | +d=a+ROT_LEFT((d+G(a,b,c)+X[14]+0xc33707d6),9);/* 26 */ |
| 128 | +c=d+ROT_LEFT((c+G(d,a,b)+X[3]+0xf4d50d87),14);/* 27 */ |
| 129 | +b=c+ROT_LEFT((b+G(c,d,a)+X[8]+0x455a14ed),20);/* 28 */ |
| 130 | +a=b+ROT_LEFT((a+G(b,c,d)+X[13]+0xa9e3e905),5);/* 29 */ |
| 131 | +d=a+ROT_LEFT((d+G(a,b,c)+X[2]+0xfcefa3f8),9);/* 30 */ |
| 132 | +c=d+ROT_LEFT((c+G(d,a,b)+X[7]+0x676f02d9),14);/* 31 */ |
| 133 | +b=c+ROT_LEFT((b+G(c,d,a)+X[12]+0x8d2a4c8a),20);/* 32 */ |
| 134 | + |
| 135 | +/* round 3 */ |
| 136 | +a=b+ROT_LEFT((a+H(b,c,d)+X[5]+0xfffa3942),4);/* 33 */ |
| 137 | +d=a+ROT_LEFT((d+H(a,b,c)+X[8]+0x8771f681),11);/* 34 */ |
| 138 | +c=d+ROT_LEFT((c+H(d,a,b)+X[11]+0x6d9d6122),16);/* 35 */ |
| 139 | +b=c+ROT_LEFT((b+H(c,d,a)+X[14]+0xfde5380c),23);/* 36 */ |
| 140 | +a=b+ROT_LEFT((a+H(b,c,d)+X[1]+0xa4beea44),4);/* 37 */ |
| 141 | +d=a+ROT_LEFT((d+H(a,b,c)+X[4]+0x4bdecfa9),11);/* 38 */ |
| 142 | +c=d+ROT_LEFT((c+H(d,a,b)+X[7]+0xf6bb4b60),16);/* 39 */ |
| 143 | +b=c+ROT_LEFT((b+H(c,d,a)+X[10]+0xbebfbc70),23);/* 40 */ |
| 144 | +a=b+ROT_LEFT((a+H(b,c,d)+X[13]+0x289b7ec6),4);/* 41 */ |
| 145 | +d=a+ROT_LEFT((d+H(a,b,c)+X[0]+0xeaa127fa),11);/* 42 */ |
| 146 | +c=d+ROT_LEFT((c+H(d,a,b)+X[3]+0xd4ef3085),16);/* 43 */ |
| 147 | +b=c+ROT_LEFT((b+H(c,d,a)+X[6]+0x04881d05),23);/* 44 */ |
| 148 | +a=b+ROT_LEFT((a+H(b,c,d)+X[9]+0xd9d4d039),4);/* 45 */ |
| 149 | +d=a+ROT_LEFT((d+H(a,b,c)+X[12]+0xe6db99e5),11);/* 46 */ |
| 150 | +c=d+ROT_LEFT((c+H(d,a,b)+X[15]+0x1fa27cf8),16);/* 47 */ |
| 151 | +b=c+ROT_LEFT((b+H(c,d,a)+X[2]+0xc4ac5665),23);/* 48 */ |
| 152 | + |
| 153 | +/* round 4 */ |
| 154 | +a=b+ROT_LEFT((a+I(b,c,d)+X[0]+0xf4292244),6);/* 49 */ |
| 155 | +d=a+ROT_LEFT((d+I(a,b,c)+X[7]+0x432aff97),10);/* 50 */ |
| 156 | +c=d+ROT_LEFT((c+I(d,a,b)+X[14]+0xab9423a7),15);/* 51 */ |
| 157 | +b=c+ROT_LEFT((b+I(c,d,a)+X[5]+0xfc93a039),21);/* 52 */ |
| 158 | +a=b+ROT_LEFT((a+I(b,c,d)+X[12]+0x655b59c3),6);/* 53 */ |
| 159 | +d=a+ROT_LEFT((d+I(a,b,c)+X[3]+0x8f0ccc92),10);/* 54 */ |
| 160 | +c=d+ROT_LEFT((c+I(d,a,b)+X[10]+0xffeff47d),15);/* 55 */ |
| 161 | +b=c+ROT_LEFT((b+I(c,d,a)+X[1]+0x85845dd1),21);/* 56 */ |
| 162 | +a=b+ROT_LEFT((a+I(b,c,d)+X[8]+0x6fa87e4f),6);/* 57 */ |
| 163 | +d=a+ROT_LEFT((d+I(a,b,c)+X[15]+0xfe2ce6e0),10);/* 58 */ |
| 164 | +c=d+ROT_LEFT((c+I(d,a,b)+X[6]+0xa3014314),15);/* 59 */ |
| 165 | +b=c+ROT_LEFT((b+I(c,d,a)+X[13]+0x4e0811a1),21);/* 60 */ |
| 166 | +a=b+ROT_LEFT((a+I(b,c,d)+X[4]+0xf7537e82),6);/* 61 */ |
| 167 | +d=a+ROT_LEFT((d+I(a,b,c)+X[11]+0xbd3af235),10);/* 62 */ |
| 168 | +c=d+ROT_LEFT((c+I(d,a,b)+X[2]+0x2ad7d2bb),15);/* 63 */ |
| 169 | +b=c+ROT_LEFT((b+I(c,d,a)+X[9]+0xeb86d391),21);/* 64 */ |
| 170 | + |
| 171 | +state[0]+=a; |
| 172 | +state[1]+=b; |
| 173 | +state[2]+=c; |
| 174 | +state[3]+=d; |
| 175 | +} |
| 176 | + |
| 177 | +staticint |
| 178 | +calculateDigestFromBuffer(unsigned8*b,unsigned32len,unsigned8sum[16]) |
| 179 | +{ |
| 180 | +registerunsigned32i,j,k,newI; |
| 181 | +unsigned32l; |
| 182 | +unsigned8*input; |
| 183 | +registerunsigned32*wbp; |
| 184 | +unsigned32workBuff[16],state[4]; |
| 185 | + |
| 186 | +l=len; |
| 187 | + |
| 188 | +state[0]=0x67452301; |
| 189 | +state[1]=0xEFCDAB89; |
| 190 | +state[2]=0x98BADCFE; |
| 191 | +state[3]=0x10325476; |
| 192 | + |
| 193 | +if ((input=createPaddedCopyWithLength(b,&l))==NULL) |
| 194 | +return0; |
| 195 | + |
| 196 | +for (i=0;;) { |
| 197 | +if ((newI=i+16*4)>l) |
| 198 | +break; |
| 199 | +k=i+3; |
| 200 | +for (j=0;j<16;j++) { |
| 201 | +wbp= (workBuff+j); |
| 202 | +*wbp=input[k--]; |
| 203 | +*wbp <<=8; |
| 204 | +*wbp |=input[k--]; |
| 205 | +*wbp <<=8; |
| 206 | +*wbp |=input[k--]; |
| 207 | +*wbp <<=8; |
| 208 | +*wbp |=input[k]; |
| 209 | +k+=7; |
| 210 | +} |
| 211 | +doTheRounds(workBuff,state); |
| 212 | +i=newI; |
| 213 | +} |
| 214 | +free(input); |
| 215 | + |
| 216 | +j=0; |
| 217 | +for (i=0;i<4;i++) { |
| 218 | +k=state[i]; |
| 219 | +sum[j++]= (k&0xFF); |
| 220 | +k >>=8; |
| 221 | +sum[j++]= (k&0xFF); |
| 222 | +k >>=8; |
| 223 | +sum[j++]= (k&0xFF); |
| 224 | +k >>=8; |
| 225 | +sum[j++]= (k&0xFF); |
| 226 | +} |
| 227 | +return1; |
| 228 | +} |
| 229 | + |
| 230 | +staticvoid |
| 231 | +bytesToHex(unsigned8b[16],char*s) |
| 232 | +{ |
| 233 | +staticchar*hex="0123456789abcdef"; |
| 234 | +intq,w; |
| 235 | + |
| 236 | +for (q=0,w=0;q<16;q++) { |
| 237 | +s[w++]=hex[(b[q] >>4)&0x0F]; |
| 238 | +s[w++]=hex[b[q]&0x0F]; |
| 239 | +} |
| 240 | +s[w]='\0'; |
| 241 | +} |
| 242 | + |
| 243 | +/* |
| 244 | + * PUBLIC FUNCTIONS |
| 245 | + */ |
| 246 | + |
| 247 | +/* |
| 248 | + * md5_hash |
| 249 | + * |
| 250 | + * Calculates the MD5 sum of the bytes in a buffer. |
| 251 | + * |
| 252 | + * SYNOPSIS #include "md5.h" |
| 253 | + * int md5_hash(const void *buff, size_t len, char *hexsum) |
| 254 | + * |
| 255 | + * INPUT buff the buffer containing the bytes that you want |
| 256 | + * the MD5 sum of. |
| 257 | + * len number of bytes in the buffer. |
| 258 | + * |
| 259 | + * OUTPUT hexsum the MD5 sum as a '\0'-terminated string of |
| 260 | + * hexadecimal digits. an MD5 sum is 16 bytes long. |
| 261 | + * each byte is represented by two heaxadecimal |
| 262 | + * characters. you thus need to provide an array |
| 263 | + * of 33 characters, including the trailing '\0'. |
| 264 | + * |
| 265 | + * RETURNS 0 on failure (out of memory for internal buffers) or |
| 266 | + * non-zero on success. |
| 267 | + * |
| 268 | + * STANDARDS MD5 is described in RFC 1321. |
| 269 | + * |
| 270 | + * AUTHOR Sverre H. Huseby <sverrehu@online.no> |
| 271 | + * |
| 272 | + */ |
| 273 | +bool |
| 274 | +md5_hash(constvoid*buff,size_tlen,char*hexsum) |
| 275 | +{ |
| 276 | +unsigned8sum[16]; |
| 277 | + |
| 278 | +if (!calculateDigestFromBuffer((unsigned8*)buff,len,sum)) |
| 279 | +return false; |
| 280 | + |
| 281 | +bytesToHex(sum,hexsum); |
| 282 | +return true; |
| 283 | +} |
| 284 | + |
| 285 | + |
| 286 | + |
| 287 | +/* |
| 288 | + * puts md5(username+passwd) in buf provided buflen is at least 36 bytes |
| 289 | + * returns 1 on success, 0 on any kind of failure and sets errno accordingly |
| 290 | + */ |
| 291 | +boolEncryptMD5(constchar*passwd,constchar*salt,char*buf) |
| 292 | +{ |
| 293 | +charcrypt_buf[128]; |
| 294 | + |
| 295 | +if (strlen(salt)+strlen(passwd)>127) |
| 296 | +return false; |
| 297 | + |
| 298 | +strcpy(buf,"md5"); |
| 299 | +memset(crypt_buf,0,128); |
| 300 | +sprintf(crypt_buf,"%s%s",salt,passwd); |
| 301 | + |
| 302 | +returnmd5_hash(crypt_buf,strlen(crypt_buf),buf+3); |
| 303 | +} |