--- rsaref/rdemo/rdemo.c 2018/04/24 16:37:52 1.1 +++ rsaref/rdemo/rdemo.c 2018/04/24 16:37:52 1.1.1.2 @@ -1,7 +1,7 @@ /* RDEMO.C - RSAREF demonstration program */ -/* Copyright (C) 1991-2 RSA Laboratories, a division of RSA Data +/* Copyright (C) 1991-4 RSA Laboratories, a division of RSA Data Security, Inc. All rights reserved. */ @@ -14,26 +14,32 @@ int main PROTO_LIST ((int, char **)); static int SetOptions PROTO_LIST ((int, char **)); static void InitRandomStruct PROTO_LIST ((R_RANDOM_STRUCT *)); static void DoSignFile PROTO_LIST ((void)); -static void DoSealFile PROTO_LIST ((R_RANDOM_STRUCT *)); static void DoVerifyFile PROTO_LIST ((void)); +static void DoSealFile PROTO_LIST ((R_RANDOM_STRUCT *)); static void DoOpenFile PROTO_LIST ((void)); static void DoGenerateKeys PROTO_LIST ((R_RANDOM_STRUCT *)); static void WriteKeypair3 PROTO_LIST ((void)); static void WriteBigInteger PROTO_LIST ((FILE *, unsigned char *, unsigned int)); +static int ReadInit PROTO_LIST ((FILE **, char *)); +static int ReadUpdate PROTO_LIST + ((FILE *, unsigned char *, unsigned int *, unsigned int)); +static void ReadFinal PROTO_LIST ((FILE *)); static int ReadBlock PROTO_LIST ((unsigned char *, unsigned int *, unsigned int, char *)); -static int ReadText PROTO_LIST - ((unsigned char *, unsigned int *, unsigned int, char *)); +static int WriteInit PROTO_LIST ((FILE **, char *)); +static int WriteUpdate PROTO_LIST ((FILE *, unsigned char *, unsigned int)); +static void WriteFinal PROTO_LIST ((FILE *)); static int WriteBlock PROTO_LIST ((unsigned char *, unsigned int, char *)); -static int GetPublicKey PROTO_LIST ((R_RSA_PUBLIC_KEY **, char *)); -static int GetPrivateKey PROTO_LIST ((R_RSA_PRIVATE_KEY **, char *)); +static int GetPublicKey PROTO_LIST ((R_RSA_PUBLIC_KEY **)); +static int GetPrivateKey PROTO_LIST ((R_RSA_PRIVATE_KEY **)); +static int GetDigestAlgorithm PROTO_LIST ((int *)); +static int GetEncryptionAlgorithm PROTO_LIST ((int *)); static void PrintMessage PROTO_LIST ((char *)); static void PrintError PROTO_LIST ((char *, int)); static void GetCommand PROTO_LIST ((char *, unsigned int, char *)); static int SILENT_PROMPT = 0; -static int DIGEST_ALGORITHM = DA_MD5; static R_RSA_PUBLIC_KEY PUBLIC_KEY1 = { 512, @@ -243,17 +249,16 @@ char *argv[]; while (!done) { PrintMessage (""); PrintMessage ("S - Sign a file"); - PrintMessage ("E - sEal a file"); PrintMessage ("V - Verify a signed file"); + PrintMessage ("E - sEal a file"); PrintMessage ("O - Open a sealed file"); - PrintMessage ("G - Generate a keypair (at least 2 minutes)"); + PrintMessage ("G - Generate a keypair (may take a long time)"); PrintMessage ("Q - Quit"); - GetCommand (command, sizeof (command), " Enter choice: "); + GetCommand (command, sizeof (command), " Enter choice"); switch (*command) { - case '\0': case '#': - /* entered a blank line or a comment */ + /* entered a comment */ break; case 's': @@ -261,16 +266,16 @@ char *argv[]; DoSignFile (); break; - case 'e': - case 'E': - DoSealFile (&randomStruct); - break; - case 'v': case 'V': DoVerifyFile (); break; + case 'e': + case 'E': + DoSealFile (&randomStruct); + break; + case 'o': case 'O': DoOpenFile (); @@ -281,6 +286,7 @@ char *argv[]; DoGenerateKeys (&randomStruct); break; + case '\0': case 'Q': case 'q': done = 1; @@ -293,7 +299,7 @@ char *argv[]; } R_RandomFinal (&randomStruct); - memset ((POINTER)&PRIVATE_KEY3, 0, sizeof (PRIVATE_KEY3)); + R_memset ((POINTER)&PRIVATE_KEY3, 0, sizeof (PRIVATE_KEY3)); return (0); } @@ -313,8 +319,6 @@ char *argv[]; if (argv[i][1] == 's') SILENT_PROMPT = 1; - else if (argv[i][1] == '2') - DIGEST_ALGORITHM = DA_MD2; else { status = 1; break; @@ -322,9 +326,8 @@ char *argv[]; } if (status) - puts ("Usage: rdemo [-s] [-2]\n\ - -s silent prompts\n\ - -2 use MD2 (not MD5)"); + puts ("Usage: rdemo [-s]\n\ + -s silent prompts\n"); return (status); } @@ -356,250 +359,231 @@ R_RANDOM_STRUCT *randomStruct; static void DoSignFile () { + FILE *file; R_RSA_PRIVATE_KEY *privateKey; - char command[80]; - int status, recodeFlag; - unsigned char content[1000], encodedContent[1000], - encodedSignature[MAX_PEM_SIGNATURE_LEN]; - unsigned int contentLen, encodedContentLen, encodedSignatureLen; - - if (ReadText - (content, &contentLen, sizeof (content), - " Enter filename of content to sign (blank to cancel): ")) - return; - GetCommand - (command, sizeof (command), - " ASCII recode the content [y/n] ? (blank to cancel): "); - if (! *command) - return; - else if (*command == 'y' || *command == 'Y') { - if (ENCODED_CONTENT_LEN (contentLen) > sizeof (encodedContent)) { - PrintError ("ERROR: Not enough room to recode the content", 0); - return; - } - else - recodeFlag = 1; - } - else - recodeFlag = 0; - - if (GetPrivateKey - (&privateKey, - " Sign as user with private key 1, 2, or 3? (blank to cancel): ")) + R_SIGNATURE_CTX context; + int digestAlgorithm, status; + unsigned char partIn[24], signature[MAX_SIGNATURE_LEN]; + unsigned int partInLen, signatureLen; + + status = 0; + + if (ReadInit (&file, " Enter filename of content to sign")) return; - - if (status = R_SignPEMBlock - (encodedContent, &encodedContentLen, encodedSignature, - &encodedSignatureLen, content, contentLen, recodeFlag, - DIGEST_ALGORITHM, privateKey)) { + + do { + if (GetPrivateKey (&privateKey)) + break; + + if (GetDigestAlgorithm (&digestAlgorithm)) + break; + + if ((status = R_SignInit (&context, digestAlgorithm)) != 0) + break; + + while (!ReadUpdate (file, partIn, &partInLen, sizeof (partIn))) + if ((status = R_SignUpdate (&context, partIn, partInLen)) != 0) + break; + if (status) + break; + + if ((status = R_SignFinal + (&context, signature, &signatureLen, privateKey)) != 0) + break; + + if (WriteBlock + (signature, signatureLen, " Enter filename to save the signature")) + break; + } while (0); + + ReadFinal (file); + + if (status) PrintError ("signing file", status); + + R_memset ((POINTER)&context, 0, sizeof (context)); + R_memset ((POINTER)partIn, 0, sizeof (partIn)); +} + +static void DoVerifyFile () +{ + FILE *file; + R_RSA_PUBLIC_KEY *publicKey; + R_SIGNATURE_CTX context; + int digestAlgorithm, status; + unsigned char partIn[16], signature[MAX_SIGNATURE_LEN]; + unsigned int partInLen, signatureLen; + + status = 0; + + if (ReadInit (&file, " Enter name of file to verify")) return; - } - - if (WriteBlock - (encodedSignature, encodedSignatureLen, - " Enter filename to save the signature (blank to cancel): ")) - return; - - if (recodeFlag) { - if (WriteBlock - (encodedContent, encodedContentLen, - " Enter filename to save the encoded content (blank to cancel): ")) - return; - } + + do { + if (GetPublicKey (&publicKey)) + break; + + if (GetDigestAlgorithm (&digestAlgorithm)) + break; + + if (ReadBlock + (signature, &signatureLen, sizeof (signature), + " Enter filename of signature")) + break; + + if ((status = R_VerifyInit (&context, digestAlgorithm)) != 0) + break; + + while (!ReadUpdate (file, partIn, &partInLen, sizeof (partIn))) + if ((status = R_VerifyUpdate (&context, partIn, partInLen)) != 0) + break; + if (status) + break; + + if ((status = R_VerifyFinal + (&context, signature, signatureLen, publicKey)) != 0) + break; + + PrintMessage ("Signature verified."); + } while (0); + + ReadFinal (file); + + if (status) + PrintError ("verifying file", status); + + R_memset ((POINTER)&context, 0, sizeof (context)); + R_memset ((POINTER)partIn, 0, sizeof (partIn)); } static void DoSealFile (randomStruct) R_RANDOM_STRUCT *randomStruct; { - R_RSA_PRIVATE_KEY *privateKey; + FILE *inFile, *outFile; + R_ENVELOPE_CTX context; R_RSA_PUBLIC_KEY *publicKey; - int status; - unsigned char content[1000], encryptedContent[1000], - encryptedSignature[MAX_PEM_ENCRYPTED_SIGNATURE_LEN], - encryptedKey[MAX_PEM_ENCRYPTED_KEY_LEN], iv[8]; - unsigned int contentLen, encryptedContentLen, encryptedSignatureLen, - encryptedKeyLen; + int encryptionAlgorithm, status; + unsigned char encryptedKey[MAX_ENCRYPTED_KEY_LEN], *encryptedKeys[1], + iv[8], partIn[24], partOut[31]; + unsigned int encryptedKeyLen, partInLen, partOutLen; + + status = 0; + + if (ReadInit (&inFile, " Enter filename of content to seal")) + return; + if (WriteInit (&outFile, " Enter filename to save the encrypted content")) { + ReadFinal (inFile); + return; + } - /* Set up a break point with a do {} while (0) so that we can - zeroize the sensitive buffers before exiting. - */ do { - if (ReadText - (content, &contentLen, sizeof (content), - " Enter filename of content to seal (blank to cancel): ")) + if (GetPublicKey (&publicKey)) break; - if (ENCRYPTED_CONTENT_LEN (contentLen) > sizeof (encryptedContent)) { - PrintError ("ERROR: Not enough room to encrypt the content.", 0); + + if (GetEncryptionAlgorithm (&encryptionAlgorithm)) break; + + encryptedKeys[0] = encryptedKey; + + if ((status = R_SealInit + (&context, encryptedKeys, &encryptedKeyLen, iv, 1, &publicKey, + encryptionAlgorithm, randomStruct)) != 0) + break; + + while (!ReadUpdate (inFile, partIn, &partInLen, sizeof (partIn))) { + if ((status = R_SealUpdate + (&context, partOut, &partOutLen, partIn, partInLen)) != 0) + break; + WriteUpdate (outFile, partOut, partOutLen); } - - if (GetPrivateKey - (&privateKey, - " Sign as user with private key 1, 2, or 3? (blank to cancel): ")) - break; - if (GetPublicKey - (&publicKey, - " Seal for user with public key 1, 2, or 3? (blank to cancel): ")) + if (status) break; - - if (status = R_SealPEMBlock - (encryptedContent, &encryptedContentLen, encryptedKey, - &encryptedKeyLen, encryptedSignature, &encryptedSignatureLen, iv, - content, contentLen, DIGEST_ALGORITHM, publicKey, privateKey, - randomStruct)) { - PrintError ("sealing file", status); + + if ((status = R_SealFinal (&context, partOut, &partOutLen))) break; - } + WriteUpdate (outFile, partOut, partOutLen); if (WriteBlock - (encryptedSignature, encryptedSignatureLen, - " Enter filename to save the signature (blank to cancel): ")) - break; - if (WriteBlock (encryptedKey, encryptedKeyLen, - " Enter filename to save the encrypted key (blank to cancel): ")) + " Enter filename to save the encrypted key")) break; if (WriteBlock - (iv, 8, " Enter filename to save the key's IV (blank to cancel): ")) - break; - if (WriteBlock - (encryptedContent, encryptedContentLen, - " Enter filename to save the encrypted content (blank to cancel): ")) + (iv, 8, " Enter filename to save the initializing vector")) break; } while (0); - memset ((POINTER)content, 0, sizeof (content)); + ReadFinal (inFile); + WriteFinal (outFile); + + if (status) + PrintError ("sealing file", status); + + R_memset ((POINTER)&context, 0, sizeof (context)); + R_memset ((POINTER)partIn, 0, sizeof (partIn)); } -static void DoVerifyFile () +static void DoOpenFile () { - R_RSA_PUBLIC_KEY *publicKey; - char command[80]; - int status, recodeFlag; - unsigned char content[1000], encodedContent[1000], - encodedSignature[MAX_PEM_SIGNATURE_LEN]; - unsigned int contentLen, encodedContentLen, encodedSignatureLen; - - GetCommand - (command, sizeof (command), - " Is the file to verify ASCII recoded [y/n] ? (blank to cancel): "); - if (! *command) - return; - - if (*command == 'y' || *command == 'Y') { - recodeFlag = 1; + FILE *inFile, *outFile; + R_ENVELOPE_CTX context; + R_RSA_PRIVATE_KEY *privateKey; + int encryptionAlgorithm, status; + unsigned char encryptedKey[MAX_ENCRYPTED_KEY_LEN], iv[8], partIn[24], + partOut[31]; + unsigned int encryptedKeyLen, ivLen, partInLen, partOutLen; - if (ReadBlock - (encodedContent, &encodedContentLen, sizeof (encodedContent), - " Enter name of file to decode and verify (blank to cancel): ")) - return; - if (DECODED_CONTENT_LEN (encodedContentLen) > sizeof (content)) { - PrintError ("ERROR: Not enough room to recode the content", 0); - return; - } - } - else { - recodeFlag = 0; - if (ReadText - (encodedContent, &encodedContentLen, sizeof (encodedContent), - " Enter name of file to verify (blank to cancel): ")) - return; - } + status = 0; - if (ReadBlock - (encodedSignature, &encodedSignatureLen, sizeof (encodedSignature), - " Enter filename of signature (blank to cancel): ")) + if (ReadInit (&inFile, " Enter filename of encrypted content to open")) return; - if (GetPublicKey - (&publicKey, - " Verify signature from user with public key 1, 2, or 3? (blank to cancel): ")) - return; - - if (status = R_VerifyPEMSignature - (content, &contentLen, encodedContent, encodedContentLen, - encodedSignature, encodedSignatureLen, recodeFlag, DIGEST_ALGORITHM, - publicKey)) { - PrintError ("verifying file", status); + if (WriteInit (&outFile, " Enter filename to save the recovered content")) { + ReadFinal (inFile); return; } - else - PrintMessage ("Signature verified."); - - if (recodeFlag) { - if (WriteBlock - (content, contentLen, - " Enter filename to save the content (blank to cancel): ")) - return; - } -} - -static void DoOpenFile () -{ - R_RSA_PRIVATE_KEY *privateKey; - R_RSA_PUBLIC_KEY *publicKey; - int status; - unsigned char content[1000], encryptedContent[1000], - encryptedSignature[MAX_PEM_ENCRYPTED_SIGNATURE_LEN], - encryptedKey[MAX_PEM_ENCRYPTED_KEY_LEN], iv[8]; - unsigned int contentLen, encryptedContentLen, encryptedSignatureLen, - encryptedKeyLen, ivLen; - /* Set up a break point with a do {} while (0) so that we can - zeroize the sensitive buffers before exiting. - */ do { - if (ReadBlock - (encryptedContent, &encryptedContentLen, sizeof (encryptedContent), - " Enter filename of content to open (blank to cancel): ")) + if (GetPrivateKey (&privateKey)) break; - if (DECRYPTED_CONTENT_LEN (encryptedContentLen) > sizeof (content)) { - PrintError ("ERROR: Not enough room to decrypt the content.", 0); + + if (GetEncryptionAlgorithm (&encryptionAlgorithm)) break; - } - - if (ReadBlock - (encryptedSignature, &encryptedSignatureLen, - sizeof (encryptedSignature), - " Enter filename the signature (blank to cancel): ")) - break; + if (ReadBlock (encryptedKey, &encryptedKeyLen, sizeof (encryptedKey), - " Enter filename of the encrypted key (blank to cancel): ")) + " Enter filename of the encrypted key")) break; if (ReadBlock - (iv, &ivLen, 8, - " Enter filename of the key's IV (blank to cancel): ")) - break; + (iv, &ivLen, 8, " Enter filename of the initializing vector")) + break; - if (GetPublicKey - (&publicKey, - " Verify signature from user with public key 1, 2, or 3? (blank to cancel): ")) - break; - if (GetPrivateKey - (&privateKey, - " Open for user with private key 1, 2, or 3? (blank to cancel): ")) + if ((status = R_OpenInit + (&context, encryptionAlgorithm, encryptedKey, encryptedKeyLen, iv, + privateKey)) != 0) break; - if (status = R_OpenPEMBlock - (content, &contentLen, encryptedContent, encryptedContentLen, - encryptedKey, encryptedKeyLen, encryptedSignature, - encryptedSignatureLen, iv, DIGEST_ALGORITHM, privateKey, - publicKey)) { - PrintError ("opening enveloped file", status); - break; + while (!ReadUpdate (inFile, partIn, &partInLen, sizeof (partIn))) { + if ((status = R_OpenUpdate + (&context, partOut, &partOutLen, partIn, partInLen)) != 0) + break; + WriteUpdate (outFile, partOut, partOutLen); } - else - PrintMessage ("Signature verified."); - - if (WriteBlock - (content, contentLen, - " Enter filename to save the decrypted content (blank to cancel): ")) + if (status) + break; + + if ((status = R_OpenFinal (&context, partOut, &partOutLen)) != 0) break; + WriteUpdate (outFile, partOut, partOutLen); } while (0); - memset ((POINTER)content, 0, sizeof (content)); + ReadFinal (inFile); + WriteFinal (outFile); + + if (status) + PrintError ("opening file", status); + + R_memset ((POINTER)&context, 0, sizeof (context)); + R_memset ((POINTER)partOut, 0, sizeof (partOut)); } static void DoGenerateKeys (randomStruct) @@ -611,7 +595,7 @@ R_RANDOM_STRUCT *randomStruct; GetCommand (command, sizeof (command), - " Enter key size in bits, (508 to 1024) (blank to cancel): "); + " Enter key size in bits, (508 to 1024)"); if (! *command) return; sscanf (command, "%d", &keySize); @@ -639,7 +623,7 @@ static void WriteKeypair3 () while (1) { GetCommand (filename, sizeof (filename), - "Enter filename to save the keypair (blank to not save): "); + " Enter filename to save the keypair"); if (! *filename) return; @@ -716,18 +700,20 @@ unsigned int integerLen; fprintf (file, "\n"); } -/* Use the prompt to ask the user to use public key 1, 2 or 3 and - point publicKey to the answer. +/* Ask the user to use public key 1, 2 or 3 and point publicKey to + the answer. Return 0 on success or 1 if user cancels by entering a blank. */ -static int GetPublicKey (publicKey, prompt) +static int GetPublicKey (publicKey) R_RSA_PUBLIC_KEY **publicKey; -char *prompt; { char command[80]; while (1) { - GetCommand (command, sizeof (command), prompt); + if (!KEYPAIR3_READY) + GetCommand (command, sizeof (command), " Public key 1 or 2?"); + else + GetCommand (command, sizeof (command), " Public key 1, 2 or 3?"); switch (*command) { case '\0': @@ -742,15 +728,10 @@ char *prompt; return (0); case '3': - if (!KEYPAIR3_READY) { - PrintError - ("ERROR: Public key 3 has not been generated yet. Try Again.", 0); + if (!KEYPAIR3_READY) break; - } - else { - *publicKey = &PUBLIC_KEY3; - return (0); - } + *publicKey = &PUBLIC_KEY3; + return (0); default: if (KEYPAIR3_READY) @@ -762,18 +743,20 @@ char *prompt; } } -/* Use the prompt to ask the user to use private key 1, 2 or 3 and - point privateKey to the answer. +/* Ask the user to use private key 1, 2 or 3 and point privateKey to + the answer. Return 0 on success or 1 if user cancels by entering a blank. */ -static int GetPrivateKey (privateKey, prompt) +static int GetPrivateKey (privateKey) R_RSA_PRIVATE_KEY **privateKey; -char *prompt; { char command[80]; while (1) { - GetCommand (command, sizeof (command), prompt); + if (!KEYPAIR3_READY) + GetCommand (command, sizeof (command), " Public key 1 or 2?"); + else + GetCommand (command, sizeof (command), " Public key 1, 2 or 3?"); switch (*command) { case '\0': @@ -788,15 +771,10 @@ char *prompt; return (0); case '3': - if (!KEYPAIR3_READY) { - PrintError - ("ERROR: Private key 3 has not been generated yet. Try Again.", 0); + if (!KEYPAIR3_READY) break; - } - else { - *privateKey = &PRIVATE_KEY3; - return (0); - } + *privateKey = &PRIVATE_KEY3; + return (0); default: if (KEYPAIR3_READY) @@ -808,63 +786,145 @@ char *prompt; } } -/* Read a file of up to length maxBlockLen bytes, storing it in - block and returning its length in blockLen. - Ask for the filename using the given prompt string. +/* Ask the user to use MD2 or MD5 and point digestAlgorithm to the + answer. + Return 0 on success or 1 if user cancels by entering a blank. + */ +static int GetDigestAlgorithm (digestAlgorithm) +int *digestAlgorithm; +{ + char command[80]; + + while (1) { + GetCommand (command, sizeof (command), " MD2 or MD5 (2 or 5)?"); + + switch (*command) { + case '\0': + return (1); + + case '2': + *digestAlgorithm = DA_MD2; + return (0); + + case '5': + *digestAlgorithm = DA_MD5; + return (0); + + default: + PrintError ("ERROR: Please enter 2 or 5. Try again.", 0); + break; + } + } +} + +/* Ask the user to use DES, DESX, DES-EDE2, or DES-EDE3, and point + encryptionAlgorithm to the answer. + Return 0 on success or 1 if user cancels by entering a blank. + */ +static int GetEncryptionAlgorithm (encryptionAlgorithm) +int *encryptionAlgorithm; +{ + char command[80]; + + while (1) { + GetCommand + (command, sizeof (command), + " DES, DESX, DES-EDE2 or DES-EDE3 (1, X, 2 or 3)?"); + + switch (*command) { + case '\0': + return (1); + + case '1': + *encryptionAlgorithm = EA_DES_CBC; + return (0); + + case 'x': + case 'X': + *encryptionAlgorithm = EA_DESX_CBC; + return (0); + + case '2': + *encryptionAlgorithm = EA_DES_EDE2_CBC; + return (0); + + case '3': + *encryptionAlgorithm = EA_DES_EDE3_CBC; + return (0); + + default: + PrintError ("ERROR: Please enter 1, X, 2 or 3. Try again.", 0); + break; + } + } +} + +/* Ask for the filename using the given prompt string and open it + for reading. Return 0 on success or 1 if error or if user cancels by entering a blank. */ -static int ReadBlock (block, blockLen, maxBlockLen, prompt) -unsigned char *block; -unsigned int *blockLen; -unsigned int maxBlockLen; +static int ReadInit (file, prompt) +FILE **file; char *prompt; { - FILE *file; - int status; char filename[256]; - unsigned char dummy; while (1) { GetCommand (filename, sizeof (filename), prompt); if (! *filename) return (1); - if ((file = fopen (filename, "rb")) != NULL) + if ((*file = fopen (filename, "rb")) != NULL) /* successfully opened */ break; PrintError ("ERROR: Cannot open a file with that name. Try again.", 0); } + + return (0); +} + +/* Read a block of up to length maxPartOutLen bytes from file, storing + it in partOut and returning its length in partOutLen. + Return 0 on success or 1 if error or end of file. + */ +static int ReadUpdate (file, partOut, partOutLen, maxPartOutLen) +FILE *file; +unsigned char *partOut; +unsigned int *partOutLen; +unsigned int maxPartOutLen; +{ + int status; - /* fread () returns the number of items read in. Expect an end of file - after the read. + /* fread () returns the number of items read in. */ - *blockLen = fread (block, 1, maxBlockLen, file); - if (*blockLen == maxBlockLen) - /* Read exactly maxBlockLen bytes, so reading one more will set - end of file if there were exactly maxBlockLen bytes in the file. - */ - fread (&dummy, 1, 1, file); - - if (!feof (file)) { - PrintError ("ERROR: Cannot read file or file is too large.", 0); + *partOutLen = fread (partOut, 1, maxPartOutLen, file); + + status = 0; + if (ferror (file)) { + PrintError ("ERROR: Cannot read file.", 0); status = 1; } - else - status = 0; - - fclose (file); + if (*partOutLen == 0 && feof (file)) + status = 1; + return (status); } +/* Close file. + */ +static void ReadFinal (file) +FILE *file; +{ + fclose (file); +} + /* Read a file of up to length maxBlockLen bytes, storing it in block and returning its length in blockLen. Ask for the filename using the given prompt string. - Read the file using fgets and convert all end of line characters to the - canonical CR/LF. Return 0 on success or 1 if error or if user cancels by entering a blank. */ -static int ReadText (block, blockLen, maxBlockLen, prompt) +static int ReadBlock (block, blockLen, maxBlockLen, prompt) unsigned char *block; unsigned int *blockLen; unsigned int maxBlockLen; @@ -872,60 +932,87 @@ char *prompt; { FILE *file; int status; + unsigned char *dummy; + unsigned int dummyLen; + + if (ReadInit (&file, prompt)) + return (1); + + if ((status = ReadUpdate (file, block, blockLen, maxBlockLen)) == 0) { + if (*blockLen == maxBlockLen) + /* Read exactly maxBlockLen bytes, so reading one more will set + end of file if there were exactly maxBlockLen bytes in the file. + */ + if (!ReadUpdate (file, dummy, &dummyLen, 1)) { + PrintError ("ERROR: File is too large.", 0); + status = 1; + } + } + + ReadFinal (file); + + return (status); +} + +/* Ask for the filename using the given prompt string and open it + for writing. + Return 0 on success or 1 if error or if user cancels by entering a blank. + */ +static int WriteInit (file, prompt) +FILE **file; +char *prompt; +{ char filename[256]; - unsigned int lineLen; while (1) { GetCommand (filename, sizeof (filename), prompt); if (! *filename) return (1); - if ((file = fopen (filename, "rb")) != NULL) + if (filename[0] == '-' && filename[1] == '\0') { + /* use stdout */ + *file = stdout; + break; + } + if ((*file = fopen (filename, "wb")) != NULL) /* successfully opened */ break; PrintError ("ERROR: Cannot open a file with that name. Try again.", 0); } + return (0); +} + +/* Write block of length partOutLen to a file. + Return 0 on success or 1 if error. + */ +static int WriteUpdate (file, partOut, partOutLen) +FILE *file; +unsigned char *partOut; +unsigned int partOutLen; +{ + int status; + status = 0; - *blockLen = 0; - while (1) { - /* fgets returns a null-terminated string which includes the end of - line characters. - */ - if (fgets ((char *)(block + *blockLen), maxBlockLen - *blockLen, file) - == NULL) { - if (!feof (file)) - status = 1; - break; - } - - /* Strip of end of line characters. - */ - lineLen = strlen ((char *)(block + *blockLen)); - while (lineLen > 0 && block[*blockLen + lineLen - 1] == 10 || - block[*blockLen + lineLen - 1] == 13) - lineLen --; - - /* Now try to add CR/LF. - */ - (*blockLen) += lineLen; - if (*blockLen + 2 > maxBlockLen) { - /* Not enough room for CR/LF. */ - status = 1; - break; - } - block[(*blockLen)++] = 13; - block[(*blockLen)++] = 10; + if (fwrite (partOut, 1, partOutLen, file) < partOutLen) { + PrintError ("ERROR: Cannot write file.", 0); + status = 1; } - if (status) - PrintError ("ERROR: Cannot read file or file is too large.", 0); - fclose (file); return (status); } -/* Write block oflength blockLen to a file. +/* Close file. + */ +static void WriteFinal (file) +FILE *file; +{ + if (file != stdout) + fclose (file); +} + +/* Write block of length blockLen to a file. Ask for the filename using the given prompt string. Return 0 on success or 1 if error or if user cancels by entering a blank. */ @@ -936,38 +1023,21 @@ char *prompt; { FILE *file; int status; - char filename[256]; - - while (1) { - GetCommand (filename, sizeof (filename), prompt); - if (! *filename) - return (1); - - if (filename[0] == '-' && filename[1] == '\0') { - /* use stdout */ - file = stdout; - break; - } - if ((file = fopen (filename, "wb")) != NULL) - /* successfully opened */ + + if (WriteInit (&file, prompt)) + return (1); + + do { + if ((status = WriteUpdate (file, block, blockLen)) != 0) break; - - PrintError ("ERROR: Cannot open a file with that name. Try again.", 0); - } - status = 0; - if (fwrite (block, 1, blockLen, file) < blockLen) { - PrintError ("ERROR: Cannot write file.", 0); - status = 1; - } - else { if (file == stdout) /* Printing to screen, so print a new line. */ printf ("\n"); - } + } while (0); + + WriteFinal (file); - if (file != stdout) - fclose (file); return (status); } @@ -997,35 +1067,23 @@ int type; /* Convert the type to a string if it is recognized. */ switch (type) { - case RE_CONTENT_ENCODING: - typeString = "(Encrypted) content has RFC 1113 encoding error"; - break; - case RE_DIGEST_ALGORITHM: - typeString = "Message-digest algorithm is invalid"; - break; case RE_KEY: - typeString = "Recovered DES key cannot decrypt encrypted content or encrypt signature"; + typeString = "Recovered DES key cannot decrypt encrypted content"; break; - case RE_KEY_ENCODING: - typeString = "Encrypted key has RFC 1113 encoding error"; + case RE_LEN: + typeString = "Encrypted key length or signature length is out of range"; break; case RE_MODULUS_LEN: - typeString = "Modulus length is invalid"; - break; - case RE_NEED_RANDOM: - typeString = "Random structure is not seeded"; + typeString = "Modulus length is out of range"; break; case RE_PRIVATE_KEY: typeString = "Private key cannot encrypt message digest, or cannot decrypt encrypted key"; break; case RE_PUBLIC_KEY: - typeString = "Public key cannot encrypt DES key, or cannot decrypt signature"; + typeString = "Public key cannot encrypt data encryption key, or cannot decrypt signature"; break; case RE_SIGNATURE: - typeString = "Signature on content or block is incorrect"; - break; - case RE_SIGNATURE_ENCODING: - typeString = "(Encrypted) signature has RFC 1113 encoding error"; + typeString = "Signature is incorrect"; break; default: @@ -1045,7 +1103,7 @@ char *prompt; unsigned int i; if (!SILENT_PROMPT) { - printf ("%s\n", prompt); + printf ("%s (blank to cancel): \n", prompt); fflush (stdout); } @@ -1061,4 +1119,3 @@ char *prompt; } } } -