Fossil SCM

Add HMAC-SHA1 implementation.

dmitry 2011-10-04 15:20 trunk
Commit dcee34b25f4f4a1fc14e15b07c564cb78c2f5a6d
1 file changed +178
+178
--- src/sha1.c
+++ src/sha1.c
@@ -199,10 +199,71 @@
199199
digest[i] = (unsigned char)
200200
((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
201201
}
202202
}
203203
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
+}
204265
205266
/*
206267
** Convert a digest into base-16. digest should be declared as
207268
** "unsigned char digest[20]" in the calling function. The SHA1
208269
** digest is stored in the first 20 bytes. zBuf should
@@ -350,10 +411,103 @@
350411
SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
351412
SHA1Final(&ctx, zResult);
352413
DigestToBase16(zResult, zDigest);
353414
return mprintf("%s", zDigest);
354415
}
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
+}
355509
356510
/*
357511
** Convert a cleartext password for a specific user into a SHA1 hash.
358512
**
359513
** The algorithm here is:
@@ -460,5 +614,29 @@
460614
}
461615
fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]);
462616
blob_reset(&cksum);
463617
}
464618
}
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
+
465643
--- src/sha1.c
+++ src/sha1.c
@@ -199,10 +199,71 @@
199 digest[i] = (unsigned char)
200 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
201 }
202 }
203
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
204
205 /*
206 ** Convert a digest into base-16. digest should be declared as
207 ** "unsigned char digest[20]" in the calling function. The SHA1
208 ** digest is stored in the first 20 bytes. zBuf should
@@ -350,10 +411,103 @@
350 SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
351 SHA1Final(&ctx, zResult);
352 DigestToBase16(zResult, zDigest);
353 return mprintf("%s", zDigest);
354 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
355
356 /*
357 ** Convert a cleartext password for a specific user into a SHA1 hash.
358 **
359 ** The algorithm here is:
@@ -460,5 +614,29 @@
460 }
461 fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]);
462 blob_reset(&cksum);
463 }
464 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
465
--- src/sha1.c
+++ src/sha1.c
@@ -199,10 +199,71 @@
199 digest[i] = (unsigned char)
200 ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
201 }
202 }
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 }
265
266 /*
267 ** Convert a digest into base-16. digest should be declared as
268 ** "unsigned char digest[20]" in the calling function. The SHA1
269 ** digest is stored in the first 20 bytes. zBuf should
@@ -350,10 +411,103 @@
411 SHA1Update(&ctx, (unsigned const char*)zIn, strlen(zIn));
412 SHA1Final(&ctx, zResult);
413 DigestToBase16(zResult, zDigest);
414 return mprintf("%s", zDigest);
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 }
509
510 /*
511 ** Convert a cleartext password for a specific user into a SHA1 hash.
512 **
513 ** The algorithm here is:
@@ -460,5 +614,29 @@
614 }
615 fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]);
616 blob_reset(&cksum);
617 }
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
643

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button