/* RDEMO.C - RSAREF demonstration program
 */

/* Copyright (C) 1991-2 RSA Laboratories, a division of RSA Data
   Security, Inc. All rights reserved.
 */

#include <stdio.h>
#include <string.h>
#include "global.h"
#include "rsaref.h"

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 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 ReadBlock PROTO_LIST
  ((unsigned char *, unsigned int *, unsigned int, char *));
static int ReadText PROTO_LIST
  ((unsigned char *, unsigned int *, unsigned int, char *));
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 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,
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xc0, 0x76, 0x47, 0x97, 0xb8, 0xbe, 0xc8, 0x97,
   0x2a, 0x0e, 0xd8, 0xc9, 0x0a, 0x8c, 0x33, 0x4d, 0xd0, 0x49, 0xad, 0xd0,
   0x22, 0x2c, 0x09, 0xd2, 0x0b, 0xe0, 0xa7, 0x9e, 0x33, 0x89, 0x10, 0xbc,
   0xae, 0x42, 0x20, 0x60, 0x90, 0x6a, 0xe0, 0x22, 0x1d, 0xe3, 0xf3, 0xfc,
   0x74, 0x7c, 0xcf, 0x98, 0xae, 0xcc, 0x85, 0xd6, 0xed, 0xc5, 0x2d, 0x93,
   0xd5, 0xb7, 0x39, 0x67, 0x76, 0x16, 0x05, 0x25},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01}
};

static R_RSA_PRIVATE_KEY PRIVATE_KEY1 = {
  512,
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xc0, 0x76, 0x47, 0x97, 0xb8, 0xbe, 0xc8, 0x97,
   0x2a, 0x0e, 0xd8, 0xc9, 0x0a, 0x8c, 0x33, 0x4d, 0xd0, 0x49, 0xad, 0xd0,
   0x22, 0x2c, 0x09, 0xd2, 0x0b, 0xe0, 0xa7, 0x9e, 0x33, 0x89, 0x10, 0xbc,
   0xae, 0x42, 0x20, 0x60, 0x90, 0x6a, 0xe0, 0x22, 0x1d, 0xe3, 0xf3, 0xfc,
   0x74, 0x7c, 0xcf, 0x98, 0xae, 0xcc, 0x85, 0xd6, 0xed, 0xc5, 0x2d, 0x93,
   0xd5, 0xb7, 0x39, 0x67, 0x76, 0x16, 0x05, 0x25},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x1a, 0xe3, 0x6b, 0x75, 0x22, 0xf6, 0x64, 0x87,
   0xd9, 0xf4, 0x61, 0x0d, 0x15, 0x50, 0x29, 0x0a, 0xc2, 0x02, 0xc9, 0x29,
   0xbe, 0xdc, 0x70, 0x32, 0xcc, 0x3e, 0x02, 0xac, 0xf3, 0x7e, 0x3e, 0xbc,
   0x1f, 0x86, 0x6e, 0xe7, 0xef, 0x7a, 0x08, 0x68, 0xd2, 0x3a, 0xe2, 0xb1,
   0x84, 0xc1, 0xab, 0xd6, 0xd4, 0xdb, 0x8e, 0xa9, 0xbe, 0xc0, 0x46, 0xbd,
   0x82, 0x80, 0x37, 0x27, 0xf2, 0x88, 0x87, 0x01},
  {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x02, 0xb6, 0x15,
    0xfe, 0x15, 0x92, 0x8f, 0x41, 0xb0, 0x2b, 0x58, 0x6b, 0x51, 0xc2, 0xc0,
    0x22, 0x60, 0xca, 0x39, 0x68, 0x18, 0xca, 0x4c, 0xba, 0x60, 0xbb, 0x89,
    0x24, 0x65, 0xbe, 0x35},
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0xee, 0xb6, 0x0d,
    0x54, 0x35, 0x18, 0xb4, 0xac, 0x74, 0x83, 0x4a, 0x05, 0x46, 0xc5, 0x07,
    0xf2, 0xe9, 0x1e, 0x38, 0x9a, 0x87, 0xe2, 0xf2, 0xbe, 0xcc, 0x6f, 0x8c,
    0x67, 0xd1, 0xc9, 0x31}},
  {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x48, 0x7e, 0x99,
    0xe3, 0x75, 0xc3, 0x8d, 0x73, 0x21, 0x12, 0xd9, 0x7d, 0x6d, 0xe8, 0x68,
    0x7f, 0xda, 0xfc, 0x5b, 0x6b, 0x5f, 0xb1, 0x6e, 0x72, 0x97, 0xd3, 0xbd,
    0x1e, 0x43, 0x55, 0x99},
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0xb5, 0x50, 0xde,
    0x64, 0x37, 0x77, 0x4d, 0xb0, 0x57, 0x77, 0x18, 0xed, 0x6c, 0x77, 0x07,
    0x24, 0xee, 0xe4, 0x66, 0xb4, 0x31, 0x14, 0xb5, 0xb6, 0x9c, 0x43, 0x59,
    0x1d, 0x31, 0x32, 0x81}},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x4c, 0x79, 0xc4,
   0xb9, 0xbe, 0xa9, 0x7c, 0x25, 0xe5, 0x63, 0xc9, 0x40, 0x7a, 0x2d, 0x09,
   0xb5, 0x73, 0x58, 0xaf, 0xe0, 0x9a, 0xf6, 0x7d, 0x71, 0xf8, 0x19, 0x8c,
   0xb7, 0xc9, 0x56, 0xb8}
};

static R_RSA_PUBLIC_KEY PUBLIC_KEY2 = {
  512,
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xe5, 0xf2, 0x0d, 0xce, 0x83, 0x32, 0x30, 0xe4,
   0x51, 0xd5, 0x0c, 0x79, 0xa5, 0x34, 0x23, 0xfb, 0x5f, 0xfb, 0xa0, 0xff,
   0x5c, 0x77, 0x96, 0xa9, 0x2c, 0x35, 0xee, 0x53, 0x02, 0xb7, 0x89, 0x2d,
   0xf0, 0x78, 0x49, 0xdd, 0xdc, 0x27, 0x79, 0x8b, 0x69, 0xa2, 0x5e, 0x7a,
   0x40, 0x27, 0x43, 0x82, 0x7a, 0xc4, 0xfa, 0x50, 0x21, 0x1f, 0x15, 0x35,
   0xc3, 0x93, 0x46, 0x62, 0xcd, 0xd4, 0x26, 0x89},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01}
};

static R_RSA_PRIVATE_KEY PRIVATE_KEY2 = {
  512,
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0xe5, 0xf2, 0x0d, 0xce, 0x83, 0x32, 0x30, 0xe4,
   0x51, 0xd5, 0x0c, 0x79, 0xa5, 0x34, 0x23, 0xfb, 0x5f, 0xfb, 0xa0, 0xff,
   0x5c, 0x77, 0x96, 0xa9, 0x2c, 0x35, 0xee, 0x53, 0x02, 0xb7, 0x89, 0x2d,
   0xf0, 0x78, 0x49, 0xdd, 0xdc, 0x27, 0x79, 0x8b, 0x69, 0xa2, 0x5e, 0x7a,
   0x40, 0x27, 0x43, 0x82, 0x7a, 0xc4, 0xfa, 0x50, 0x21, 0x1f, 0x15, 0x35,
   0xc3, 0x93, 0x46, 0x62, 0xcd, 0xd4, 0x26, 0x89},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x8e, 0x6b, 0x48, 0x4f, 0xe3, 0x04, 0x60, 0x31,
   0xd9, 0xd9, 0x59, 0xdb, 0xb2, 0x0d, 0xc4, 0x47, 0x7a, 0x60, 0x70, 0x8c,
   0x19, 0x2a, 0x5c, 0x9f, 0x35, 0x29, 0xc6, 0x0d, 0x95, 0xfe, 0x35, 0x30,
   0x99, 0x54, 0xda, 0x99, 0x90, 0xe3, 0x3e, 0x1d, 0xdb, 0x32, 0x7b, 0x1d,
   0x26, 0xf2, 0x9a, 0xab, 0x03, 0x09, 0x77, 0xba, 0x4f, 0x43, 0xdb, 0xda,
   0xc8, 0x1f, 0x12, 0xd6, 0xf2, 0x57, 0x1a, 0x31},
  {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x6c, 0x5d, 0xb7,
    0x7b, 0xa7, 0x9e, 0x2f, 0x4a, 0x26, 0xec, 0xe0, 0x1b, 0x2a, 0x5f, 0x42,
    0x04, 0x87, 0xb4, 0xc4, 0x68, 0x80, 0xf3, 0x09, 0xe5, 0x48, 0x00, 0x30,
    0x6f, 0x54, 0x04, 0x75},
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xd6, 0x25, 0x08,
    0xe5, 0x54, 0x19, 0xa3, 0x98, 0x9d, 0x77, 0x92, 0x18, 0xba, 0x9c, 0x00,
    0xda, 0x69, 0xee, 0x84, 0xf9, 0x10, 0xe5, 0xda, 0xf0, 0x7d, 0x78, 0x6c,
    0x92, 0xd8, 0xc7, 0x45}},
  {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x03, 0x32, 0x71,
    0x69, 0x3c, 0x85, 0xca, 0x20, 0xca, 0x0b, 0x22, 0xb2, 0xc2, 0x03, 0x00,
    0xce, 0x20, 0x3c, 0xf4, 0xa5, 0x93, 0x4f, 0xe2, 0x1f, 0xf7, 0x07, 0x5c,
    0x64, 0xc8, 0x24, 0x21},
   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf1, 0xde, 0x01,
    0x07, 0xe9, 0x1b, 0xfa, 0x7e, 0x51, 0x6b, 0x62, 0xb2, 0x29, 0x6b, 0xb6,
    0x0f, 0xeb, 0xd5, 0xf8, 0x08, 0xc1, 0x7c, 0x90, 0xd6, 0x3f, 0xa0, 0xa4,
    0x2e, 0x30, 0xef, 0xb5}},
  {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x60, 0x46,
   0x90, 0x85, 0xaf, 0x6f, 0xa2, 0x8d, 0x6a, 0x1d, 0x3e, 0xfd, 0x56, 0xd7,
   0x57, 0x5e, 0x00, 0x30, 0x5b, 0x49, 0x6c, 0xc4, 0x85, 0xf5, 0x1c, 0x39,
   0xef, 0x0b, 0x4b, 0x28}
};

R_RSA_PUBLIC_KEY PUBLIC_KEY3;
R_RSA_PRIVATE_KEY PRIVATE_KEY3;
int KEYPAIR3_READY = 0;

int main (argc, argv)
int argc;
char *argv[];
{
  R_RANDOM_STRUCT randomStruct;
  char command[80];
  int done = 0;

  if (SetOptions (argc, argv))
    return (0);
  
  InitRandomStruct (&randomStruct);
  PrintMessage
    ("NOTE: When saving to a file, a filename of \"-\" will output to the screen.");

  while (!done) {
    PrintMessage ("");
    PrintMessage ("S - Sign a file");
    PrintMessage ("E - sEal a file");
    PrintMessage ("V - Verify a signed file");
    PrintMessage ("O - Open a sealed file");
    PrintMessage ("G - Generate a keypair (at least 2 minutes)");
    PrintMessage ("Q - Quit");
    GetCommand (command, sizeof (command), "  Enter choice: ");
    
    switch (*command) {
    case '\0':
    case '#':
      /* entered a blank line or a comment */
      break;
      
    case 's':
    case 'S':
      DoSignFile ();
      break;
      
    case 'e':
    case 'E':
      DoSealFile (&randomStruct);
      break;
      
    case 'v':
    case 'V':
      DoVerifyFile ();
      break;
      
    case 'o':
    case 'O':
      DoOpenFile ();
      break;
      
    case 'g':
    case 'G':
      DoGenerateKeys (&randomStruct);
      break;
      
    case 'Q':
    case 'q':
      done = 1;
      break;
      
    default:
      PrintError ("ERROR: Unrecognized command.  Try again.", 0);
      break;
    }
  }
  
  R_RandomFinal (&randomStruct);
  memset ((POINTER)&PRIVATE_KEY3, 0, sizeof (PRIVATE_KEY3));
  return (0);
}

/* Set options from command line and return 0 for success, 1 for bad format.
 */
static int SetOptions (argc, argv)
int argc;
char *argv[];
{
  int i, status = 0;
  
  for (i = 1; i < argc; i++) {
    if (argv[i][0] != '-') {
      status = 1;
      break;
    }
    
    if (argv[i][1] == 's')
      SILENT_PROMPT = 1;
    else if (argv[i][1] == '2')
      DIGEST_ALGORITHM = DA_MD2;
    else {
      status = 1;
      break;
    }
  }

  if (status)
    puts ("Usage: rdemo [-s] [-2]\n\
  -s silent prompts\n\
  -2 use MD2 (not MD5)");

  return (status);
}

/* Initialize the random structure with all zero seed bytes for test purposes.
   NOTE that this will cause the output of the "random" process to be
     the same every time.  To produce random bytes, the random struct
     needs random seeds!
 */
static void InitRandomStruct (randomStruct)
R_RANDOM_STRUCT *randomStruct;
{
  static unsigned char seedByte = 0;
  unsigned int bytesNeeded;
  
  R_RandomInit (randomStruct);
  
  /* Initialize with all zero seed bytes, which will not yield an actual
       random number output.
   */
  while (1) {
    R_GetRandomBytesNeeded (&bytesNeeded, randomStruct);
    if (bytesNeeded == 0)
      break;
    
    R_RandomUpdate (randomStruct, &seedByte, 1);
  }
}

static void DoSignFile ()
{
  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): "))
    return;
  
  if (status = R_SignPEMBlock
      (encodedContent, &encodedContentLen, encodedSignature,
       &encodedSignatureLen, content, contentLen, recodeFlag,
       DIGEST_ALGORITHM, privateKey)) {
    PrintError ("signing file", status);
    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;
  }
}

static void DoSealFile (randomStruct)
R_RANDOM_STRUCT *randomStruct;
{
  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;

  /* 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): "))
      break;
    if (ENCRYPTED_CONTENT_LEN (contentLen) > sizeof (encryptedContent)) {
      PrintError ("ERROR: Not enough room to encrypt the content.", 0);
      break;
    }
  
    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): "))
      break;
  
    if (status = R_SealPEMBlock
        (encryptedContent, &encryptedContentLen, encryptedKey,
         &encryptedKeyLen, encryptedSignature, &encryptedSignatureLen, iv,
         content, contentLen, DIGEST_ALGORITHM, publicKey, privateKey,
         randomStruct)) {
      PrintError ("sealing file", status);
      break;
    }
  
    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): "))
      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): "))
      break;
  } while (0);
  
  memset ((POINTER)content, 0, sizeof (content));
}

static void DoVerifyFile ()
{
  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;

    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;
  }

  if (ReadBlock
      (encodedSignature, &encodedSignatureLen, sizeof (encodedSignature),
       "  Enter filename of signature (blank to cancel): "))
    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);
    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): "))
      break;
    if (DECRYPTED_CONTENT_LEN (encryptedContentLen) > sizeof (content)) {
      PrintError ("ERROR: Not enough room to decrypt the content.", 0);
      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): "))
      break;  
    if (ReadBlock
        (iv, &ivLen, 8,
         "  Enter filename of the key's IV (blank to cancel): "))
      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): "))
      break;
    
    if (status = R_OpenPEMBlock
        (content, &contentLen, encryptedContent, encryptedContentLen,
         encryptedKey, encryptedKeyLen, encryptedSignature,
         encryptedSignatureLen, iv, DIGEST_ALGORITHM, privateKey,
         publicKey)) {
      PrintError ("opening enveloped file", status);
      break;
    }
    else
      PrintMessage ("Signature verified.");
  
    if (WriteBlock
        (content, contentLen,
         "  Enter filename to save the decrypted content (blank to cancel): "))
      break;
  } while (0);
  
  memset ((POINTER)content, 0, sizeof (content));
}

static void DoGenerateKeys (randomStruct)
R_RANDOM_STRUCT *randomStruct;
{
  R_RSA_PROTO_KEY protoKey;
  char command[80];
  int status, keySize;

  GetCommand
    (command, sizeof (command),
     "  Enter key size in bits, (508 to 1024) (blank to cancel): ");
  if (! *command)
    return;
  sscanf (command, "%d", &keySize);
  
  protoKey.bits = (unsigned int)keySize;
  protoKey.useFermat4 = 1;
  
  if (status = R_GeneratePEMKeys
      (&PUBLIC_KEY3, &PRIVATE_KEY3, &protoKey, randomStruct)) {
    PrintError ("generating keys", status);
    return;
  }

  PrintMessage ("Public key 3 and private key 3 are now ready to use.");
  KEYPAIR3_READY = 1;
  
  WriteKeypair3 ();
}

static void WriteKeypair3 ()
{
  FILE *file;
  char filename[256];
  
  while (1) {
    GetCommand
      (filename, sizeof (filename),
       "Enter filename to save the keypair (blank to not save): ");
    if (! *filename)
      return;
    
    if (filename[0] == '-' && filename[1] == '\0') {
      /* use stdout */
      file = stdout;
      break;
    }
    if ((file = fopen (filename, "w")) != NULL)
      /* successfully opened */
      break;
    
    PrintError ("ERROR: Cannot open a file with that name.  Try again.", 0);
  }

  fprintf (file, "Public Key, %u bits:\n", PUBLIC_KEY3.bits);
  fprintf (file, "  modulus: ");
  WriteBigInteger (file, PUBLIC_KEY3.modulus, sizeof (PUBLIC_KEY3.modulus));
  fprintf (file, "  exponent: ");
  WriteBigInteger (file, PUBLIC_KEY3.exponent, sizeof (PUBLIC_KEY3.exponent));

  fprintf (file, "\nPrivate Key, %u bits:\n", PRIVATE_KEY3.bits);
  fprintf (file, "  modulus: ");
  WriteBigInteger (file, PRIVATE_KEY3.modulus, sizeof (PRIVATE_KEY3.modulus));
  fprintf (file, "  public exponent: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.publicExponent, sizeof (PRIVATE_KEY3.publicExponent));
  fprintf (file, "  exponent: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.exponent, sizeof (PRIVATE_KEY3.exponent));
  fprintf (file, "  prime 1: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.prime[0], sizeof (PRIVATE_KEY3.prime[0]));
  fprintf (file, "  prime 2: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.prime[1], sizeof (PRIVATE_KEY3.prime[1]));
  fprintf (file, "  prime exponent 1: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.primeExponent[0],
     sizeof (PRIVATE_KEY3.primeExponent[0]));
  fprintf (file, "  prime exponent 2: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.primeExponent[1],
     sizeof (PRIVATE_KEY3.primeExponent[1]));
  fprintf (file, "  coefficient: ");
  WriteBigInteger
    (file, PRIVATE_KEY3.coefficient, sizeof (PRIVATE_KEY3.coefficient));

  if (file != stdout)
    fclose (file);
}

/* Write the byte string 'integer' to 'file', skipping over leading zeros.
 */
static void WriteBigInteger (file, integer, integerLen)
FILE *file;
unsigned char *integer;
unsigned int integerLen;
{
  while (*integer == 0 && integerLen > 0) {
    integer++;
    integerLen--;
  }
  
  if (integerLen == 0) {
    /* Special case, just print a zero. */
    fprintf (file, "00\n");
    return;
  }
  
  for (; integerLen > 0; integerLen--)
    fprintf (file, "%02x ", (unsigned int)(*integer++));

  fprintf (file, "\n");
}

/* Use the prompt to 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)
R_RSA_PUBLIC_KEY **publicKey;
char *prompt;
{
  char command[80];
  
  while (1) {
    GetCommand (command, sizeof (command), prompt);

    switch (*command) {
    case '\0':
      return (1);
      
    case '1':
      *publicKey = &PUBLIC_KEY1;
      return (0);
      
    case '2':
      *publicKey = &PUBLIC_KEY2;
      return (0);
      
    case '3':
      if (!KEYPAIR3_READY) {
        PrintError
          ("ERROR: Public key 3 has not been generated yet.  Try Again.", 0);
        break;
      }
      else {
        *publicKey = &PUBLIC_KEY3;
        return (0);
      }
      
    default:
      if (KEYPAIR3_READY)
        PrintError ("ERROR: Please enter 1, 2 or 3.  Try again.", 0);
      else
        PrintError ("ERROR: Please enter 1 or 2.  Try again.", 0);
      break;
    }
  }
}

/* Use the prompt to 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)
R_RSA_PRIVATE_KEY **privateKey;
char *prompt;
{
  char command[80];
  
  while (1) {
    GetCommand (command, sizeof (command), prompt);

    switch (*command) {
    case '\0':
      return (1);
      
    case '1':
      *privateKey = &PRIVATE_KEY1;
      return (0);
      
    case '2':
      *privateKey = &PRIVATE_KEY2;
      return (0);
      
    case '3':
      if (!KEYPAIR3_READY) {
        PrintError
          ("ERROR: Private key 3 has not been generated yet.  Try Again.", 0);
        break;
      }
      else {
        *privateKey = &PRIVATE_KEY3;
        return (0);
      }
      
    default:
      if (KEYPAIR3_READY)
        PrintError ("ERROR: Please enter 1, 2 or 3.  Try again.", 0);
      else
        PrintError ("ERROR: Please enter 1 or 2.  Try again.", 0);
      break;
    }
  }
}

/* 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.
   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;
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)
      /* successfully opened */
      break;
    
    PrintError ("ERROR: Cannot open a file with that name.  Try again.", 0);
  }
  
  /* fread () returns the number of items read in.  Expect an end of file
       after the read.
   */
  *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);
    status = 1;
  }
  else
    status = 0;
  
  fclose (file);
  return (status);
}

/* 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) 
unsigned char *block;
unsigned int *blockLen;
unsigned int maxBlockLen;
char *prompt;
{
  FILE *file;
  int status;
  char filename[256];
  unsigned int lineLen;
  
  while (1) {
    GetCommand (filename, sizeof (filename), prompt);
    if (! *filename)
      return (1);
    
    if ((file = fopen (filename, "rb")) != NULL)
      /* successfully opened */
      break;
    
    PrintError ("ERROR: Cannot open a file with that name.  Try again.", 0);
  }

  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 (status)
    PrintError ("ERROR: Cannot read file or file is too large.", 0);  
  fclose (file);
  return (status);
}

/* Write block oflength 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.
 */
static int WriteBlock (block, blockLen, prompt) 
unsigned char *block;
unsigned int blockLen;
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 */
      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");
  }

  if (file != stdout)
    fclose (file);
  return (status);
}

static void PrintMessage (message)
char *message;
{
  if (!SILENT_PROMPT) {
    puts (message);
    fflush (stdout);
  }
}

/* If type is zero, simply print the task string, otherwise convert the
     type to a string and print task and type.
 */
static void PrintError (task, type)
char *task;
int type;
{
  char *typeString, buf[80];

  if (type == 0) {
    puts (task);
    return;
  }
  
  /* 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";
    break;
  case RE_KEY_ENCODING:
    typeString = "Encrypted key has RFC 1113 encoding error";
    break;
  case RE_MODULUS_LEN:
    typeString = "Modulus length is invalid";
    break;
  case RE_NEED_RANDOM:
    typeString = "Random structure is not seeded";
    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";
    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";
    break;
    
  default:
    sprintf (buf, "Code 0x%04x", type);
    typeString = buf;
  }

  printf ("ERROR: %s while %s\n", typeString, task);  
  fflush (stdout);
}

static void GetCommand (command, maxCommandSize, prompt)
char *command;
unsigned int maxCommandSize;
char *prompt;
{
  unsigned int i;
  
  if (!SILENT_PROMPT) {
    printf ("%s\n", prompt);  
    fflush (stdout);
  }

  fgets (command, maxCommandSize, stdin);
  
  /* Replace the line terminator with a '\0'.
   */
  for (i = 0; command[i] != '\0'; i++) {
    if (command[i] == '\012' || command[i] == '\015' ||
        i == (maxCommandSize - 1)) {
      command[i] = '\0';
      return;
    }
  }
}

