Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch multisession Excluding Merge-Ins
This is equivalent to a diff from d4a341b49d to dcee34b25f
2011-10-04
| ||
23:07 | Merge the --args FILENAME patch into trunk. check-in: c0274f9962 user: drh tags: trunk | |
21:28 | merging with trunk [d4a341b49dd1b701] before applying --args FILENAME patch, to simplify downstream merge. check-in: 312d522fe4 user: stephan tags: stephan-hack | |
15:20 | Add HMAC-SHA1 implementation. Leaf check-in: dcee34b25f user: dmitry tags: multisession | |
15:15 | Merge protection against timing attacks into trunk. check-in: d4a341b49d user: dmitry tags: trunk | |
14:38 | Merge trunk into dmitry-security branch. Closed-Leaf check-in: f4eb0f5afc user: dmitry tags: dmitry-security | |
2011-10-03
| ||
16:34 | Disabling Cache-control: no-store, as it made firefox forget about form field contents on back/forward in history. Resolution achieved by a minimal consensus at this thread on the mailing list. check-in: 3fac77d7b0 user: viriketo tags: trunk | |
Changes to src/sha1.c.
197 197 if (digest) { 198 198 for (i = 0; i < 20; i++) 199 199 digest[i] = (unsigned char) 200 200 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); 201 201 } 202 202 } 203 203 204 +typedef struct HMAC_SHA1Context HMAC_SHA1Context; 205 +struct HMAC_SHA1Context { 206 + SHA1Context inner; 207 + SHA1Context outer; 208 +}; 209 + 210 +static void HMAC_SHA1Init( 211 + HMAC_SHA1Context *context, 212 + const unsigned char *key, 213 + unsigned int keylen 214 +){ 215 + unsigned char pad[64]; /* 64 is SHA-1 block length */ 216 + unsigned char keyhash[20]; 217 + unsigned int i; 218 + const unsigned char *k = key; 219 + 220 + if( keylen > sizeof(pad) ){ 221 + /* Key is too big, hash it, and use this hash as a key */ 222 + SHA1Init(&context->inner); 223 + SHA1Update(&context->inner, k, keylen); 224 + SHA1Final(&context->inner, keyhash); 225 + k = keyhash; 226 + keylen = sizeof(keyhash); 227 + } 228 + 229 + /* Initialize inner hash */ 230 + SHA1Init(&context->inner); 231 + memset(pad, 0x36, sizeof(pad)); 232 + for( i=0; i<keylen; i++ ){ pad[i] ^= k[i]; } 233 + SHA1Update(&context->inner, pad, sizeof(pad)); 234 + 235 + /* Initialize outer hash */ 236 + SHA1Init(&context->outer); 237 + memset(pad, 0x5C, sizeof(pad)); 238 + for( i=0; i<keylen; i++ ){ pad[i] ^= k[i]; } 239 + SHA1Update(&context->outer, pad, sizeof(pad)); 240 + 241 + /* Cleanup */ 242 + memset(keyhash, 0, sizeof(keyhash)); 243 +} 244 + 245 +static void HMAC_SHA1Update( 246 + HMAC_SHA1Context *context, 247 + const unsigned char *data, 248 + unsigned int len 249 +){ 250 + SHA1Update(&context->inner, data, len); 251 +} 252 + 253 +static void HMAC_SHA1Final( 254 + HMAC_SHA1Context *context, 255 + unsigned char digest[20] 256 +){ 257 + unsigned char innerDigest[20]; 258 + SHA1Final(&context->inner, innerDigest); 259 + /* Mix inner into outer */ 260 + SHA1Update(&context->outer, innerDigest, sizeof(innerDigest)); 261 + SHA1Final(&context->outer, digest); 262 + /* Cleanup */ 263 + memset(innerDigest, 0, sizeof(innerDigest)); 264 +} 204 265 205 266 /* 206 267 ** Convert a digest into base-16. digest should be declared as 207 268 ** "unsigned char digest[20]" in the calling function. The SHA1 208 269 ** digest is stored in the first 20 bytes. zBuf should 209 270 ** be "char zBuf[41]". 210 271 */ ................................................................................ 348 409 349 410 SHA1Init(&ctx); 350 411 SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn)); 351 412 SHA1Final(&ctx, zResult); 352 413 DigestToBase16(zResult, zDigest); 353 414 return mprintf("%s", zDigest); 354 415 } 416 + 417 +/* 418 +** Compute HMAC-SHA1 of a zero-terminated string. The 419 +** result (hex string) is held in memory obtained from mprintf(). 420 +*/ 421 +char *hmac_sign(const char *zKey, const char *zData){ 422 + HMAC_SHA1Context ctx; 423 + unsigned char zResult[20]; 424 + char zDigest[41]; 425 + 426 + HMAC_SHA1Init(&ctx, (unsigned const char *)zKey, strlen(zKey)); 427 + HMAC_SHA1Update(&ctx, (unsigned const char*)zData, strlen(zData)); 428 + HMAC_SHA1Final(&ctx, zResult); 429 + DigestToBase16(zResult, zDigest); 430 + return mprintf("%s", zDigest); 431 +} 432 + 433 +/* 434 +** Like hmac_sign(), but uses double-HMAC construction: 435 +** HMAC(HMAC(zKey, zData), zData) 436 +*/ 437 +char *hmac_double_sign(const char *zKey, const char *zData){ 438 + HMAC_SHA1Context ctx; 439 + unsigned char zInterKey[20], zResult[20]; 440 + char zDigest[41]; 441 + 442 + /* First derive intermediate key */ 443 + HMAC_SHA1Init(&ctx, (unsigned const char *)zKey, strlen(zKey)); 444 + HMAC_SHA1Update(&ctx, (unsigned const char*)zData, strlen(zData)); 445 + HMAC_SHA1Final(&ctx, zInterKey); 446 + /* Use intermediate key to sign data */ 447 + HMAC_SHA1Init(&ctx, zInterKey, sizeof(zInterKey)); 448 + HMAC_SHA1Update(&ctx, (unsigned const char *)zData, strlen(zData)); 449 + HMAC_SHA1Final(&ctx, zResult); 450 + 451 + DigestToBase16(zResult, zDigest); 452 + return mprintf("%s", zDigest); 453 +} 454 + 455 +/* 456 +** Constant-time comparison of buffers b1 and b2, which both have length len 457 +** Returns 0 on successful verification, any other number on failure. 458 +*/ 459 +static int verify_bytes( 460 + const unsigned char *b1, 461 + const unsigned char *b2, 462 + unsigned int len 463 +){ 464 + unsigned int i; 465 + unsigned char rc = 0; 466 + if( len==0 ) return 1; 467 + for( i=0; i<len; i++){ 468 + rc |= b1[i] ^ b2[i]; 469 + } 470 + return rc; 471 +} 472 + 473 +/* 474 +** Verify that hex string zDigest (result of hmac_sign) is the one 475 +** that was used to sign zData with secret key zKey. 476 +** All strings are zero-terminated. 477 +** Returns 0 on successful verification, any other number on failure. 478 +*/ 479 +int hmac_verify(const char *zDigest, const char *zKey, const char *zData) 480 +{ 481 + char *zCalcDigest; 482 + unsigned int len, i, rc = 0; 483 + 484 + zCalcDigest = hmac_sign(zKey, zData); 485 + len = strlen(zCalcDigest); 486 + if( len==0 || len != strlen(zDigest) ) return 1; 487 + rc = verify_bytes((const unsigned char*)zDigest, 488 + (const unsigned char*)zCalcDigest, len); 489 + fossil_free(zCalcDigest); 490 + return rc; 491 +} 492 + 493 +/* 494 +** Like hmac_verify(), but uses double-HMAC. 495 +*/ 496 +int hmac_double_verify(const char *zDigest, const char *zKey, const char *zData) 497 +{ 498 + char *zCalcDigest; 499 + unsigned int len, i, rc = 0; 500 + 501 + zCalcDigest = hmac_double_sign(zKey, zData); 502 + len = strlen(zCalcDigest); 503 + if( len==0 || len != strlen(zDigest) ) return 1; 504 + rc = verify_bytes((const unsigned char*)zDigest, 505 + (const unsigned char*)zCalcDigest, len); 506 + fossil_free(zCalcDigest); 507 + return rc; 508 +} 355 509 356 510 /* 357 511 ** Convert a cleartext password for a specific user into a SHA1 hash. 358 512 ** 359 513 ** The algorithm here is: 360 514 ** 361 515 ** SHA1( project-code + "/" + login + "/" + password ) ................................................................................ 458 612 }else{ 459 613 sha1sum_file(g.argv[i], &cksum); 460 614 } 461 615 fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]); 462 616 blob_reset(&cksum); 463 617 } 464 618 } 619 + 620 +/* 621 +** COMMAND: test-hmac 622 +** %fossil test-hmac secret data 623 +*/ 624 +void hmac_test(void){ 625 + assert( g.argc==4 ); 626 + fossil_print("HMAC(%s, %s) = ", g.argv[2], g.argv[3]); 627 + fossil_print("%s\n", hmac_sign(g.argv[2], g.argv[3])); 628 +} 629 + 630 +/* 631 +** COMMAND: test-hmac-verify 632 +** %fossil test-hmac-verify digest secret data 633 +*/ 634 +void hmac_verify_test(void){ 635 + assert( g.argc==5 ); 636 + if( hmac_verify(g.argv[2], g.argv[3], g.argv[4])==0 ){ 637 + fossil_print("successfuly verified\n"); 638 + }else{ 639 + fossil_print("not verified\n"); 640 + } 641 +} 642 +