|
|
1.1 ! root 1: /* DHDEMO.C - demonstration program for Diffie-Hellman extensions to ! 2: RSAREF ! 3: */ ! 4: ! 5: /* Copyright (C) 1993 RSA Laboratories, a division of RSA Data ! 6: Security, Inc. All rights reserved. ! 7: */ ! 8: ! 9: #include <stdio.h> ! 10: #include <string.h> ! 11: #include <stdlib.h> ! 12: #include "global.h" ! 13: #include "rsaref.h" ! 14: ! 15: int main PROTO_LIST ((int, char **)); ! 16: static int SetOptions PROTO_LIST ((int, char **)); ! 17: static void InitRandomStruct PROTO_LIST ((R_RANDOM_STRUCT *)); ! 18: static void DoSetupAgreement PROTO_LIST ((R_RANDOM_STRUCT *)); ! 19: static void DoComputeAgreedKey PROTO_LIST ((void)); ! 20: static void DoGenerateParams PROTO_LIST ((R_RANDOM_STRUCT *)); ! 21: static void WriteParams2 PROTO_LIST ((void)); ! 22: static void WriteBigInteger PROTO_LIST ! 23: ((FILE *, unsigned char *, unsigned int)); ! 24: static int ReadBlock PROTO_LIST ! 25: ((unsigned char *, unsigned int *, unsigned int, char *)); ! 26: static int WriteBlock PROTO_LIST ((unsigned char *, unsigned int, char *)); ! 27: static int GetParams PROTO_LIST ((R_DH_PARAMS **, char *)); ! 28: static void PrintMessage PROTO_LIST ((char *)); ! 29: static void PrintError PROTO_LIST ((char *, int)); ! 30: static void GetCommand PROTO_LIST ((char *, unsigned int, char *)); ! 31: ! 32: static int SILENT_PROMPT = 0; ! 33: ! 34: static unsigned char PRIME1[64] = { ! 35: 0xd0, 0x45, 0x1f, 0xfe, 0x2c, 0x64, 0xc4, 0xed, 0x6b, 0x0a, 0xe6, ! 36: 0x36, 0x5b, 0x7f, 0xef, 0x9c, 0x15, 0x42, 0x5e, 0x40, 0xa3, 0x7c, ! 37: 0xa5, 0xf8, 0x39, 0x86, 0x5e, 0x2c, 0xfb, 0x41, 0x69, 0xa0, 0xd8, ! 38: 0x25, 0xc9, 0x13, 0x0f, 0x88, 0x64, 0xff, 0xfc, 0xf3, 0xbf, 0xbe, ! 39: 0xb0, 0x27, 0x36, 0x60, 0x67, 0xaa, 0x27, 0xe2, 0x7b, 0xfc, 0xaf, ! 40: 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ! 41: }; ! 42: static unsigned char GENERATOR1[64] = { ! 43: 0x0a, 0xcf, 0x95, 0x8c, 0x40, 0xd3, 0x01, 0xef, 0xc5, 0x15, 0x3e, ! 44: 0x7d, 0xcd, 0x5e, 0xf7, 0x5f, 0xec, 0x9e, 0x8f, 0xb0, 0xfa, 0xe6, ! 45: 0xa8, 0x0e, 0xe5, 0xc3, 0xb8, 0x4b, 0x9c, 0x0e, 0x51, 0x30, 0x51, ! 46: 0xb2, 0xb7, 0x54, 0x2e, 0x66, 0xb8, 0xd3, 0xa2, 0x5e, 0x93, 0x89, ! 47: 0x11, 0xad, 0x6b, 0xe5, 0xc2, 0x43, 0x95, 0x09, 0x9c, 0x6d, 0xda, ! 48: 0xa8, 0x6e, 0x18, 0x94, 0x2f, 0x29, 0x84, 0x27, 0x5a ! 49: }; ! 50: ! 51: static R_DH_PARAMS PARAMS1 = { ! 52: PRIME1, sizeof (PRIME1), GENERATOR1, sizeof (GENERATOR1) ! 53: }; ! 54: R_DH_PARAMS PARAMS2; ! 55: int PARAMS2_READY = 0; ! 56: ! 57: int main (argc, argv) ! 58: int argc; ! 59: char *argv[]; ! 60: { ! 61: R_RANDOM_STRUCT randomStruct; ! 62: char command[80]; ! 63: int done = 0; ! 64: ! 65: if (SetOptions (argc, argv)) ! 66: return (0); ! 67: ! 68: InitRandomStruct (&randomStruct); ! 69: PrintMessage ! 70: ("NOTE: When saving to a file, a filename of \"-\" will output to the screen."); ! 71: ! 72: while (!done) { ! 73: PrintMessage (""); ! 74: PrintMessage ("S - Set up a key agreement"); ! 75: PrintMessage ("C - Compute an agreed-upon key"); ! 76: PrintMessage ("G - Generate parameters (may take a long time)"); ! 77: PrintMessage ("Q - Quit"); ! 78: GetCommand (command, sizeof (command), " Enter choice: "); ! 79: ! 80: switch (*command) { ! 81: case '\0': ! 82: case '#': ! 83: /* entered a blank line or a comment */ ! 84: break; ! 85: ! 86: case 's': ! 87: case 'S': ! 88: DoSetupAgreement (&randomStruct); ! 89: break; ! 90: ! 91: case 'c': ! 92: case 'C': ! 93: DoComputeAgreedKey (); ! 94: break; ! 95: ! 96: case 'g': ! 97: case 'G': ! 98: DoGenerateParams (&randomStruct); ! 99: break; ! 100: ! 101: case 'Q': ! 102: case 'q': ! 103: done = 1; ! 104: break; ! 105: ! 106: default: ! 107: PrintError ("ERROR: Unrecognized command. Try again.", 0); ! 108: break; ! 109: } ! 110: } ! 111: ! 112: R_RandomFinal (&randomStruct); ! 113: return (0); ! 114: } ! 115: ! 116: /* Set options from command line and return 0 for success, 1 for bad format. ! 117: */ ! 118: static int SetOptions (argc, argv) ! 119: int argc; ! 120: char *argv[]; ! 121: { ! 122: int i, status = 0; ! 123: ! 124: for (i = 1; i < argc; i++) { ! 125: if (argv[i][0] != '-') { ! 126: status = 1; ! 127: break; ! 128: } ! 129: ! 130: if (argv[i][1] == 's') ! 131: SILENT_PROMPT = 1; ! 132: else { ! 133: status = 1; ! 134: break; ! 135: } ! 136: } ! 137: ! 138: if (status) ! 139: puts ("Usage: dhdemo [-s]\n\ ! 140: -s silent prompts"); ! 141: ! 142: return (status); ! 143: } ! 144: ! 145: /* Initialize the random structure with all zero seed bytes for test purposes. ! 146: NOTE that this will cause the output of the "random" process to be ! 147: the same every time. To produce random bytes, the random struct ! 148: needs random seeds! ! 149: */ ! 150: static void InitRandomStruct (randomStruct) ! 151: R_RANDOM_STRUCT *randomStruct; ! 152: { ! 153: static unsigned char seedByte = 0; ! 154: unsigned int bytesNeeded; ! 155: ! 156: R_RandomInit (randomStruct); ! 157: ! 158: /* Initialize with all zero seed bytes, which will not yield an actual ! 159: random number output. ! 160: */ ! 161: while (1) { ! 162: R_GetRandomBytesNeeded (&bytesNeeded, randomStruct); ! 163: if (bytesNeeded == 0) ! 164: break; ! 165: ! 166: R_RandomUpdate (randomStruct, &seedByte, 1); ! 167: } ! 168: } ! 169: ! 170: static void DoSetupAgreement (randomStruct) ! 171: R_RANDOM_STRUCT *randomStruct; ! 172: { ! 173: R_DH_PARAMS *params; ! 174: char command[80]; ! 175: int status; ! 176: unsigned char *privateValue, *publicValue; ! 177: unsigned int privateValueLen; ! 178: ! 179: if (GetParams ! 180: (¶ms, " Set up with parameters 1 or 2? (blank to cancel): ")) ! 181: return; ! 182: ! 183: GetCommand ! 184: (command, sizeof (command), ! 185: " Enter length in bytes of private value (blank to cancel): "); ! 186: if (! *command) ! 187: return; ! 188: sscanf (command, "%d", &privateValueLen); ! 189: ! 190: privateValue = (unsigned char *)malloc (privateValueLen); ! 191: publicValue = (unsigned char *)malloc (params->primeLen); ! 192: ! 193: /* Set up a break point with a do {} while (0) so that we can ! 194: zeroize the sensitive buffers before exiting. ! 195: */ ! 196: do { ! 197: if (status = R_SetupDHAgreement ! 198: (publicValue, privateValue, privateValueLen, params, randomStruct)) { ! 199: PrintError ("setting up key agreement", status); ! 200: break; ! 201: } ! 202: ! 203: if (WriteBlock ! 204: (publicValue, params->primeLen, ! 205: " Enter filename to save the public value (blank to cancel): ")) ! 206: break; ! 207: ! 208: if (WriteBlock ! 209: (privateValue, privateValueLen, ! 210: " Enter filename to save the private value (blank to cancel): ")) ! 211: break; ! 212: } while (0); ! 213: ! 214: memset ((POINTER)privateValue, 0, privateValueLen); ! 215: free (privateValue); ! 216: free (publicValue); ! 217: } ! 218: ! 219: static void DoComputeAgreedKey () ! 220: { ! 221: R_DH_PARAMS *params; ! 222: int status; ! 223: unsigned char *agreedKey, *otherPublicValue, *privateValue; ! 224: unsigned int otherPublicValueLen, privateValueLen; ! 225: ! 226: if (GetParams ! 227: (¶ms, " Compute with parameters 1 or 2? (blank to cancel): ")) ! 228: return; ! 229: ! 230: otherPublicValue = (unsigned char *)malloc (params->primeLen); ! 231: privateValue = (unsigned char *)malloc (params->primeLen); ! 232: agreedKey = (unsigned char *)malloc (params->primeLen); ! 233: ! 234: /* Set up a break point with a do {} while (0) so that we can ! 235: zeroize the sensitive buffers before exiting. ! 236: */ ! 237: do { ! 238: if (ReadBlock ! 239: (otherPublicValue, &otherPublicValueLen, params->primeLen, ! 240: " Enter filename of other party's public value (blank to cancel): ")) ! 241: break; ! 242: if (otherPublicValueLen != params->primeLen) { ! 243: PrintError ("ERROR: Other party's public value has wrong length", 0); ! 244: break; ! 245: } ! 246: ! 247: if (ReadBlock ! 248: (privateValue, &privateValueLen, params->primeLen, ! 249: " Enter filename of private value (blank to cancel): ")) ! 250: break; ! 251: ! 252: if (status = R_ComputeDHAgreedKey ! 253: (agreedKey, otherPublicValue, privateValue, privateValueLen, params)) { ! 254: PrintError ("computing agreed-upon key", status); ! 255: break; ! 256: } ! 257: ! 258: if (WriteBlock ! 259: (agreedKey, params->primeLen, ! 260: " Enter filename to save the agreed-upon key (blank to cancel): ")) ! 261: break; ! 262: } while (0); ! 263: ! 264: memset ((POINTER)privateValue, 0, privateValueLen); ! 265: memset ((POINTER)agreedKey, 0, params->primeLen); ! 266: free (otherPublicValue); ! 267: free (privateValue); ! 268: free (agreedKey); ! 269: } ! 270: ! 271: static void DoGenerateParams (randomStruct) ! 272: R_RANDOM_STRUCT *randomStruct; ! 273: { ! 274: char command[80]; ! 275: int status, primeBits, subPrimeBits; ! 276: ! 277: GetCommand ! 278: (command, sizeof (command), ! 279: " Enter prime size in bits, (16 to 1024) (blank to cancel): "); ! 280: if (! *command) ! 281: return; ! 282: sscanf (command, "%d", &primeBits); ! 283: ! 284: GetCommand ! 285: (command, sizeof (command), ! 286: " Enter subprime size in bits, (16 to 1024) (blank to cancel): "); ! 287: if (! *command) ! 288: return; ! 289: sscanf (command, "%d", &subPrimeBits); ! 290: ! 291: if (PARAMS2_READY) { ! 292: free (PARAMS2.prime); ! 293: free (PARAMS2.generator); ! 294: } ! 295: PARAMS2.prime = (unsigned char *)malloc (DH_PRIME_LEN (primeBits)); ! 296: PARAMS2.generator = (unsigned char *)malloc (DH_PRIME_LEN (primeBits)); ! 297: ! 298: if (status = R_GenerateDHParams ! 299: (&PARAMS2, primeBits, subPrimeBits, randomStruct)) { ! 300: PrintError ("generating parameters", status); ! 301: return; ! 302: } ! 303: ! 304: PrintMessage ("Parameters 2 are now ready to use."); ! 305: PARAMS2_READY = 1; ! 306: ! 307: WriteParams2 (); ! 308: } ! 309: ! 310: static void WriteParams2 () ! 311: { ! 312: FILE *file; ! 313: char filename[256]; ! 314: ! 315: while (1) { ! 316: GetCommand ! 317: (filename, sizeof (filename), ! 318: "Enter filename to save the parameters (blank to not save): "); ! 319: if (! *filename) ! 320: return; ! 321: ! 322: if (filename[0] == '-' && filename[1] == '\0') { ! 323: /* use stdout */ ! 324: file = stdout; ! 325: break; ! 326: } ! 327: if ((file = fopen (filename, "w")) != NULL) ! 328: /* successfully opened */ ! 329: break; ! 330: ! 331: PrintError ("ERROR: Cannot open a file with that name. Try again.", 0); ! 332: } ! 333: ! 334: fprintf (file, "Parameters:\n"); ! 335: fprintf (file, " prime: "); ! 336: WriteBigInteger (file, PARAMS2.prime, PARAMS2.primeLen); ! 337: fprintf (file, " generator: "); ! 338: WriteBigInteger (file, PARAMS2.generator, PARAMS2.generatorLen); ! 339: ! 340: if (file != stdout) ! 341: fclose (file); ! 342: } ! 343: ! 344: /* Write the byte string 'integer' to 'file', skipping over leading zeros. ! 345: */ ! 346: static void WriteBigInteger (file, integer, integerLen) ! 347: FILE *file; ! 348: unsigned char *integer; ! 349: unsigned int integerLen; ! 350: { ! 351: while (*integer == 0 && integerLen > 0) { ! 352: integer++; ! 353: integerLen--; ! 354: } ! 355: ! 356: if (integerLen == 0) { ! 357: /* Special case, just print a zero. */ ! 358: fprintf (file, "00\n"); ! 359: return; ! 360: } ! 361: ! 362: for (; integerLen > 0; integerLen--) ! 363: fprintf (file, "%02x ", (unsigned int)(*integer++)); ! 364: ! 365: fprintf (file, "\n"); ! 366: } ! 367: ! 368: /* Use the prompt to ask the user to use parameters 1 or 2 and ! 369: point params to the answer. ! 370: Return 0 on success or 1 if user cancels by entering a blank. ! 371: */ ! 372: static int GetParams (params, prompt) ! 373: R_DH_PARAMS **params; ! 374: char *prompt; ! 375: { ! 376: char command[80]; ! 377: ! 378: while (1) { ! 379: GetCommand (command, sizeof (command), prompt); ! 380: ! 381: switch (*command) { ! 382: case '\0': ! 383: return (1); ! 384: ! 385: case '1': ! 386: *params = &PARAMS1; ! 387: return (0); ! 388: ! 389: case '2': ! 390: if (!PARAMS2_READY) { ! 391: PrintError ! 392: ("ERROR: Parameters 2 have not been generated yet. Try Again.", 0); ! 393: break; ! 394: } ! 395: else { ! 396: *params = &PARAMS2; ! 397: return (0); ! 398: } ! 399: ! 400: default: ! 401: if (PARAMS2_READY) ! 402: PrintError ("ERROR: Please enter 1 or 2. Try again.", 0); ! 403: else ! 404: PrintError ("ERROR: Please enter 1. Try again.", 0); ! 405: break; ! 406: } ! 407: } ! 408: } ! 409: ! 410: /* Read a file of up to length maxBlockLen bytes, storing it in ! 411: block and returning its length in blockLen. ! 412: Ask for the filename using the given prompt string. ! 413: Return 0 on success or 1 if error or if user cancels by entering a blank. ! 414: */ ! 415: static int ReadBlock (block, blockLen, maxBlockLen, prompt) ! 416: unsigned char *block; ! 417: unsigned int *blockLen; ! 418: unsigned int maxBlockLen; ! 419: char *prompt; ! 420: { ! 421: FILE *file; ! 422: int status; ! 423: char filename[256]; ! 424: unsigned char dummy; ! 425: ! 426: while (1) { ! 427: GetCommand (filename, sizeof (filename), prompt); ! 428: if (! *filename) ! 429: return (1); ! 430: ! 431: if ((file = fopen (filename, "rb")) != NULL) ! 432: /* successfully opened */ ! 433: break; ! 434: ! 435: PrintError ("ERROR: Cannot open a file with that name. Try again.", 0); ! 436: } ! 437: ! 438: /* fread () returns the number of items read in. Expect an end of file ! 439: after the read. ! 440: */ ! 441: *blockLen = fread (block, 1, maxBlockLen, file); ! 442: if (*blockLen == maxBlockLen) ! 443: /* Read exactly maxBlockLen bytes, so reading one more will set ! 444: end of file if there were exactly maxBlockLen bytes in the file. ! 445: */ ! 446: fread (&dummy, 1, 1, file); ! 447: ! 448: if (!feof (file)) { ! 449: PrintError ("ERROR: Cannot read file or file is too large.", 0); ! 450: status = 1; ! 451: } ! 452: else ! 453: status = 0; ! 454: ! 455: fclose (file); ! 456: return (status); ! 457: } ! 458: ! 459: /* Write block oflength blockLen to a file. ! 460: Ask for the filename using the given prompt string. ! 461: Return 0 on success or 1 if error or if user cancels by entering a blank. ! 462: */ ! 463: static int WriteBlock (block, blockLen, prompt) ! 464: unsigned char *block; ! 465: unsigned int blockLen; ! 466: char *prompt; ! 467: { ! 468: FILE *file; ! 469: int status; ! 470: char filename[256]; ! 471: ! 472: while (1) { ! 473: GetCommand (filename, sizeof (filename), prompt); ! 474: if (! *filename) ! 475: return (1); ! 476: ! 477: if (filename[0] == '-' && filename[1] == '\0') { ! 478: /* use stdout */ ! 479: file = stdout; ! 480: break; ! 481: } ! 482: if ((file = fopen (filename, "wb")) != NULL) ! 483: /* successfully opened */ ! 484: break; ! 485: ! 486: PrintError ("ERROR: Cannot open a file with that name. Try again.", 0); ! 487: } ! 488: ! 489: status = 0; ! 490: if (fwrite (block, 1, blockLen, file) < blockLen) { ! 491: PrintError ("ERROR: Cannot write file.", 0); ! 492: status = 1; ! 493: } ! 494: else { ! 495: if (file == stdout) ! 496: /* Printing to screen, so print a new line. */ ! 497: printf ("\n"); ! 498: } ! 499: ! 500: if (file != stdout) ! 501: fclose (file); ! 502: return (status); ! 503: } ! 504: ! 505: static void PrintMessage (message) ! 506: char *message; ! 507: { ! 508: if (!SILENT_PROMPT) { ! 509: puts (message); ! 510: fflush (stdout); ! 511: } ! 512: } ! 513: ! 514: /* If type is zero, simply print the task string, otherwise convert the ! 515: type to a string and print task and type. ! 516: */ ! 517: static void PrintError (task, type) ! 518: char *task; ! 519: int type; ! 520: { ! 521: char *typeString, buf[80]; ! 522: ! 523: if (type == 0) { ! 524: puts (task); ! 525: return; ! 526: } ! 527: ! 528: /* Convert the type to a string if it is recognized. ! 529: */ ! 530: switch (type) { ! 531: case RE_CONTENT_ENCODING: ! 532: typeString = "(Encrypted) content has RFC 1113 encoding error"; ! 533: break; ! 534: case RE_DIGEST_ALGORITHM: ! 535: typeString = "Message-digest algorithm is invalid"; ! 536: break; ! 537: case RE_KEY: ! 538: typeString = "Recovered DES key cannot decrypt encrypted content or encrypt signature"; ! 539: break; ! 540: case RE_KEY_ENCODING: ! 541: typeString = "Encrypted key has RFC 1113 encoding error"; ! 542: break; ! 543: case RE_MODULUS_LEN: ! 544: typeString = "Modulus length is invalid"; ! 545: break; ! 546: case RE_NEED_RANDOM: ! 547: typeString = "Random structure is not seeded"; ! 548: break; ! 549: case RE_PRIVATE_KEY: ! 550: typeString = "Private key cannot encrypt message digest, or cannot decrypt encrypted key"; ! 551: break; ! 552: case RE_PUBLIC_KEY: ! 553: typeString = "Public key cannot encrypt DES key, or cannot decrypt signature"; ! 554: break; ! 555: case RE_SIGNATURE: ! 556: typeString = "Signature on content or block is incorrect"; ! 557: break; ! 558: case RE_SIGNATURE_ENCODING: ! 559: typeString = "(Encrypted) signature has RFC 1113 encoding error"; ! 560: break; ! 561: ! 562: default: ! 563: sprintf (buf, "Code 0x%04x", type); ! 564: typeString = buf; ! 565: } ! 566: ! 567: printf ("ERROR: %s while %s\n", typeString, task); ! 568: fflush (stdout); ! 569: } ! 570: ! 571: static void GetCommand (command, maxCommandSize, prompt) ! 572: char *command; ! 573: unsigned int maxCommandSize; ! 574: char *prompt; ! 575: { ! 576: unsigned int i; ! 577: ! 578: if (!SILENT_PROMPT) { ! 579: printf ("%s\n", prompt); ! 580: fflush (stdout); ! 581: } ! 582: ! 583: fgets (command, maxCommandSize, stdin); ! 584: ! 585: /* Replace the line terminator with a '\0'. ! 586: */ ! 587: for (i = 0; command[i] != '\0'; i++) { ! 588: if (command[i] == '\012' || command[i] == '\015' || ! 589: i == (maxCommandSize - 1)) { ! 590: command[i] = '\0'; ! 591: return; ! 592: } ! 593: } ! 594: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.