]> andersk Git - moira.git/commitdiff
RSAREF (for new reg_svr)
authordanw <danw>
Wed, 22 Jul 1998 14:54:49 +0000 (14:54 +0000)
committerdanw <danw>
Wed, 22 Jul 1998 14:54:49 +0000 (14:54 +0000)
24 files changed:
util/rsaref/Makefile.in [new file with mode: 0644]
util/rsaref/des.h [new file with mode: 0644]
util/rsaref/desc.c [new file with mode: 0644]
util/rsaref/digit.c [new file with mode: 0644]
util/rsaref/digit.h [new file with mode: 0644]
util/rsaref/global.h [new file with mode: 0644]
util/rsaref/md2.h [new file with mode: 0644]
util/rsaref/md2c.c [new file with mode: 0644]
util/rsaref/md5.h [new file with mode: 0644]
util/rsaref/md5c.c [new file with mode: 0644]
util/rsaref/nn.c [new file with mode: 0644]
util/rsaref/nn.h [new file with mode: 0644]
util/rsaref/prime.c [new file with mode: 0644]
util/rsaref/prime.h [new file with mode: 0644]
util/rsaref/r_dh.c [new file with mode: 0644]
util/rsaref/r_encode.c [new file with mode: 0644]
util/rsaref/r_enhanc.c [new file with mode: 0644]
util/rsaref/r_keygen.c [new file with mode: 0644]
util/rsaref/r_random.c [new file with mode: 0644]
util/rsaref/r_random.h [new file with mode: 0644]
util/rsaref/r_stdlib.c [new file with mode: 0644]
util/rsaref/rsa.c [new file with mode: 0644]
util/rsaref/rsa.h [new file with mode: 0644]
util/rsaref/rsaref.h [new file with mode: 0644]

diff --git a/util/rsaref/Makefile.in b/util/rsaref/Makefile.in
new file mode 100644 (file)
index 0000000..33987f9
--- /dev/null
@@ -0,0 +1,34 @@
+# $Id$
+
+SHELL=/bin/sh
+
+CC=@CC@
+CPPFLAGS=@CPPFLAGS@
+CFLAGS=@CFLAGS@
+DEFS=@DEFS@
+ALL_CFLAGS=$(CPPFLAGS) $(CFLAGS) $(DEFS)
+RANLIB=@RANLIB@
+
+srcdir=@srcdir@
+VPATH=@srcdir@
+SRCTOP=@top_srcdir@
+BUILDTOP=..
+
+OBJS=  desc.o digit.o md2c.o md5c.o nn.o prime.o rsa.o r_encode.o \
+       r_dh.o r_enhanc.o r_keygen.o r_random.o r_stdlib.o
+
+.c.o:
+       $(CC) -c $(ALL_CFLAGS) $<
+
+all: rsaref.a
+
+clean:
+       rm -f $(OBJS) rsaref.a
+
+depend:
+
+install: all
+
+rsaref.a: $(OBJS)
+       ar cru $@ $(OBJS)
+       $(RANLIB) $@
diff --git a/util/rsaref/des.h b/util/rsaref/des.h
new file mode 100644 (file)
index 0000000..a446300
--- /dev/null
@@ -0,0 +1,56 @@
+/* DES.H - header file for DESC.C
+ */
+
+#ifndef _DES_H_
+#define _DES_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  UINT4 subkeys[32];                                             /* subkeys */
+  UINT4 iv[2];                                       /* initializing vector */
+  UINT4 originalIV[2];                        /* for restarting the context */
+  int encrypt;                                               /* encrypt flag */
+} DES_CBC_CTX;
+
+typedef struct {
+  UINT4 subkeys[32];                                             /* subkeys */
+  UINT4 iv[2];                                       /* initializing vector */
+  UINT4 inputWhitener[2];                                 /* input whitener */
+  UINT4 outputWhitener[2];                               /* output whitener */
+  UINT4 originalIV[2];                        /* for restarting the context */
+  int encrypt;                                              /* encrypt flag */
+} DESX_CBC_CTX;
+
+typedef struct {
+  UINT4 subkeys[3][32];                     /* subkeys for three operations */
+  UINT4 iv[2];                                       /* initializing vector */
+  UINT4 originalIV[2];                        /* for restarting the context */
+  int encrypt;                                              /* encrypt flag */
+} DES3_CBC_CTX;
+
+void DES_CBCInit PROTO_LIST 
+  ((DES_CBC_CTX *, unsigned char *, unsigned char *, int));
+int DES_CBCUpdate PROTO_LIST
+  ((DES_CBC_CTX *, unsigned char *, unsigned char *, unsigned int));
+void DES_CBCRestart PROTO_LIST ((DES_CBC_CTX *));
+
+void DESX_CBCInit PROTO_LIST 
+  ((DESX_CBC_CTX *, unsigned char *, unsigned char *, int));
+int DESX_CBCUpdate PROTO_LIST
+  ((DESX_CBC_CTX *, unsigned char *, unsigned char *, unsigned int));
+void DESX_CBCRestart PROTO_LIST ((DESX_CBC_CTX *));
+
+void DES3_CBCInit PROTO_LIST 
+  ((DES3_CBC_CTX *, unsigned char *, unsigned char *, int));
+int DES3_CBCUpdate PROTO_LIST
+  ((DES3_CBC_CTX *, unsigned char *, unsigned char *, unsigned int));
+void DES3_CBCRestart PROTO_LIST ((DES3_CBC_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/util/rsaref/desc.c b/util/rsaref/desc.c
new file mode 100644 (file)
index 0000000..05e47ca
--- /dev/null
@@ -0,0 +1,645 @@
+/* DESC.C - Data Encryption Standard routines for RSAREF
+     Based on "Karn/Hoey/Outerbridge" implementation (KHODES)
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "des.h"
+
+static UINT2 BYTE_BIT[8] = {
+  0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static UINT4 BIG_BYTE[24] = {
+  0x800000L, 0x400000L, 0x200000L, 0x100000L,
+  0x80000L,  0x40000L,  0x20000L,  0x10000L,
+  0x8000L,   0x4000L,   0x2000L,   0x1000L,
+  0x800L,    0x400L,    0x200L,    0x100L,
+  0x80L,     0x40L,     0x20L,     0x10L,
+  0x8L,      0x4L,      0x2L,      0x1L
+};
+
+static unsigned char PC1[56] = {
+  56, 48, 40, 32, 24, 16,  8,      0, 57, 49, 41, 33, 25, 17,
+   9,  1, 58, 50, 42, 34, 26,     18, 10,  2, 59, 51, 43, 35,
+  62, 54, 46, 38, 30, 22, 14,      6, 61, 53, 45, 37, 29, 21,
+  13,  5, 60, 52, 44, 36, 28,     20, 12,  4, 27, 19, 11,  3
+};
+
+static unsigned char TOTAL_ROTATIONS[16] = {
+  1, 2, 4, 6, 8, 10, 12, 14, 15, 17, 19, 21, 23, 25, 27, 28
+};
+
+static unsigned char PC2[48] = {
+  13, 16, 10, 23,  0,  4,  2, 27, 14,  5, 20,  9,
+  22, 18, 11,  3, 25,  7, 15,  6, 26, 19, 12,  1,
+  40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+  43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+};
+
+static UINT4 SP1[64] = {
+  0x01010400L, 0x00000000L, 0x00010000L, 0x01010404L,
+  0x01010004L, 0x00010404L, 0x00000004L, 0x00010000L,
+  0x00000400L, 0x01010400L, 0x01010404L, 0x00000400L,
+  0x01000404L, 0x01010004L, 0x01000000L, 0x00000004L,
+  0x00000404L, 0x01000400L, 0x01000400L, 0x00010400L,
+  0x00010400L, 0x01010000L, 0x01010000L, 0x01000404L,
+  0x00010004L, 0x01000004L, 0x01000004L, 0x00010004L,
+  0x00000000L, 0x00000404L, 0x00010404L, 0x01000000L,
+  0x00010000L, 0x01010404L, 0x00000004L, 0x01010000L,
+  0x01010400L, 0x01000000L, 0x01000000L, 0x00000400L,
+  0x01010004L, 0x00010000L, 0x00010400L, 0x01000004L,
+  0x00000400L, 0x00000004L, 0x01000404L, 0x00010404L,
+  0x01010404L, 0x00010004L, 0x01010000L, 0x01000404L,
+  0x01000004L, 0x00000404L, 0x00010404L, 0x01010400L,
+  0x00000404L, 0x01000400L, 0x01000400L, 0x00000000L,
+  0x00010004L, 0x00010400L, 0x00000000L, 0x01010004L
+};
+
+static UINT4 SP2[64] = {
+  0x80108020L, 0x80008000L, 0x00008000L, 0x00108020L,
+  0x00100000L, 0x00000020L, 0x80100020L, 0x80008020L,
+  0x80000020L, 0x80108020L, 0x80108000L, 0x80000000L,
+  0x80008000L, 0x00100000L, 0x00000020L, 0x80100020L,
+  0x00108000L, 0x00100020L, 0x80008020L, 0x00000000L,
+  0x80000000L, 0x00008000L, 0x00108020L, 0x80100000L,
+  0x00100020L, 0x80000020L, 0x00000000L, 0x00108000L,
+  0x00008020L, 0x80108000L, 0x80100000L, 0x00008020L,
+  0x00000000L, 0x00108020L, 0x80100020L, 0x00100000L,
+  0x80008020L, 0x80100000L, 0x80108000L, 0x00008000L,
+  0x80100000L, 0x80008000L, 0x00000020L, 0x80108020L,
+  0x00108020L, 0x00000020L, 0x00008000L, 0x80000000L,
+  0x00008020L, 0x80108000L, 0x00100000L, 0x80000020L,
+  0x00100020L, 0x80008020L, 0x80000020L, 0x00100020L,
+  0x00108000L, 0x00000000L, 0x80008000L, 0x00008020L,
+  0x80000000L, 0x80100020L, 0x80108020L, 0x00108000L
+};
+
+static UINT4 SP3[64] = {
+  0x00000208L, 0x08020200L, 0x00000000L, 0x08020008L,
+  0x08000200L, 0x00000000L, 0x00020208L, 0x08000200L,
+  0x00020008L, 0x08000008L, 0x08000008L, 0x00020000L,
+  0x08020208L, 0x00020008L, 0x08020000L, 0x00000208L,
+  0x08000000L, 0x00000008L, 0x08020200L, 0x00000200L,
+  0x00020200L, 0x08020000L, 0x08020008L, 0x00020208L,
+  0x08000208L, 0x00020200L, 0x00020000L, 0x08000208L,
+  0x00000008L, 0x08020208L, 0x00000200L, 0x08000000L,
+  0x08020200L, 0x08000000L, 0x00020008L, 0x00000208L,
+  0x00020000L, 0x08020200L, 0x08000200L, 0x00000000L,
+  0x00000200L, 0x00020008L, 0x08020208L, 0x08000200L,
+  0x08000008L, 0x00000200L, 0x00000000L, 0x08020008L,
+  0x08000208L, 0x00020000L, 0x08000000L, 0x08020208L,
+  0x00000008L, 0x00020208L, 0x00020200L, 0x08000008L,
+  0x08020000L, 0x08000208L, 0x00000208L, 0x08020000L,
+  0x00020208L, 0x00000008L, 0x08020008L, 0x00020200L
+};
+
+static UINT4 SP4[64] = {
+  0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+  0x00802080L, 0x00800081L, 0x00800001L, 0x00002001L,
+  0x00000000L, 0x00802000L, 0x00802000L, 0x00802081L,
+  0x00000081L, 0x00000000L, 0x00800080L, 0x00800001L,
+  0x00000001L, 0x00002000L, 0x00800000L, 0x00802001L,
+  0x00000080L, 0x00800000L, 0x00002001L, 0x00002080L,
+  0x00800081L, 0x00000001L, 0x00002080L, 0x00800080L,
+  0x00002000L, 0x00802080L, 0x00802081L, 0x00000081L,
+  0x00800080L, 0x00800001L, 0x00802000L, 0x00802081L,
+  0x00000081L, 0x00000000L, 0x00000000L, 0x00802000L,
+  0x00002080L, 0x00800080L, 0x00800081L, 0x00000001L,
+  0x00802001L, 0x00002081L, 0x00002081L, 0x00000080L,
+  0x00802081L, 0x00000081L, 0x00000001L, 0x00002000L,
+  0x00800001L, 0x00002001L, 0x00802080L, 0x00800081L,
+  0x00002001L, 0x00002080L, 0x00800000L, 0x00802001L,
+  0x00000080L, 0x00800000L, 0x00002000L, 0x00802080L
+};
+
+static UINT4 SP5[64] = {
+  0x00000100L, 0x02080100L, 0x02080000L, 0x42000100L,
+  0x00080000L, 0x00000100L, 0x40000000L, 0x02080000L,
+  0x40080100L, 0x00080000L, 0x02000100L, 0x40080100L,
+  0x42000100L, 0x42080000L, 0x00080100L, 0x40000000L,
+  0x02000000L, 0x40080000L, 0x40080000L, 0x00000000L,
+  0x40000100L, 0x42080100L, 0x42080100L, 0x02000100L,
+  0x42080000L, 0x40000100L, 0x00000000L, 0x42000000L,
+  0x02080100L, 0x02000000L, 0x42000000L, 0x00080100L,
+  0x00080000L, 0x42000100L, 0x00000100L, 0x02000000L,
+  0x40000000L, 0x02080000L, 0x42000100L, 0x40080100L,
+  0x02000100L, 0x40000000L, 0x42080000L, 0x02080100L,
+  0x40080100L, 0x00000100L, 0x02000000L, 0x42080000L,
+  0x42080100L, 0x00080100L, 0x42000000L, 0x42080100L,
+  0x02080000L, 0x00000000L, 0x40080000L, 0x42000000L,
+  0x00080100L, 0x02000100L, 0x40000100L, 0x00080000L,
+  0x00000000L, 0x40080000L, 0x02080100L, 0x40000100L
+};
+
+static UINT4 SP6[64] = {
+  0x20000010L, 0x20400000L, 0x00004000L, 0x20404010L,
+  0x20400000L, 0x00000010L, 0x20404010L, 0x00400000L,
+  0x20004000L, 0x00404010L, 0x00400000L, 0x20000010L,
+  0x00400010L, 0x20004000L, 0x20000000L, 0x00004010L,
+  0x00000000L, 0x00400010L, 0x20004010L, 0x00004000L,
+  0x00404000L, 0x20004010L, 0x00000010L, 0x20400010L,
+  0x20400010L, 0x00000000L, 0x00404010L, 0x20404000L,
+  0x00004010L, 0x00404000L, 0x20404000L, 0x20000000L,
+  0x20004000L, 0x00000010L, 0x20400010L, 0x00404000L,
+  0x20404010L, 0x00400000L, 0x00004010L, 0x20000010L,
+  0x00400000L, 0x20004000L, 0x20000000L, 0x00004010L,
+  0x20000010L, 0x20404010L, 0x00404000L, 0x20400000L,
+  0x00404010L, 0x20404000L, 0x00000000L, 0x20400010L,
+  0x00000010L, 0x00004000L, 0x20400000L, 0x00404010L,
+  0x00004000L, 0x00400010L, 0x20004010L, 0x00000000L,
+  0x20404000L, 0x20000000L, 0x00400010L, 0x20004010L
+};
+
+static UINT4 SP7[64] = {
+  0x00200000L, 0x04200002L, 0x04000802L, 0x00000000L,
+  0x00000800L, 0x04000802L, 0x00200802L, 0x04200800L,
+  0x04200802L, 0x00200000L, 0x00000000L, 0x04000002L,
+  0x00000002L, 0x04000000L, 0x04200002L, 0x00000802L,
+  0x04000800L, 0x00200802L, 0x00200002L, 0x04000800L,
+  0x04000002L, 0x04200000L, 0x04200800L, 0x00200002L,
+  0x04200000L, 0x00000800L, 0x00000802L, 0x04200802L,
+  0x00200800L, 0x00000002L, 0x04000000L, 0x00200800L,
+  0x04000000L, 0x00200800L, 0x00200000L, 0x04000802L,
+  0x04000802L, 0x04200002L, 0x04200002L, 0x00000002L,
+  0x00200002L, 0x04000000L, 0x04000800L, 0x00200000L,
+  0x04200800L, 0x00000802L, 0x00200802L, 0x04200800L,
+  0x00000802L, 0x04000002L, 0x04200802L, 0x04200000L,
+  0x00200800L, 0x00000000L, 0x00000002L, 0x04200802L,
+  0x00000000L, 0x00200802L, 0x04200000L, 0x00000800L,
+  0x04000002L, 0x04000800L, 0x00000800L, 0x00200002L
+};
+
+static UINT4 SP8[64] = {
+  0x10001040L, 0x00001000L, 0x00040000L, 0x10041040L,
+  0x10000000L, 0x10001040L, 0x00000040L, 0x10000000L,
+  0x00040040L, 0x10040000L, 0x10041040L, 0x00041000L,
+  0x10041000L, 0x00041040L, 0x00001000L, 0x00000040L,
+  0x10040000L, 0x10000040L, 0x10001000L, 0x00001040L,
+  0x00041000L, 0x00040040L, 0x10040040L, 0x10041000L,
+  0x00001040L, 0x00000000L, 0x00000000L, 0x10040040L,
+  0x10000040L, 0x10001000L, 0x00041040L, 0x00040000L,
+  0x00041040L, 0x00040000L, 0x10041000L, 0x00001000L,
+  0x00000040L, 0x10040040L, 0x00001000L, 0x00041040L,
+  0x10001000L, 0x00000040L, 0x10000040L, 0x10040000L,
+  0x10040040L, 0x10000000L, 0x00040000L, 0x10001040L,
+  0x00000000L, 0x10041040L, 0x00040040L, 0x10000040L,
+  0x10040000L, 0x10001000L, 0x10001040L, 0x00000000L,
+  0x10041040L, 0x00041000L, 0x00041000L, 0x00001040L,
+  0x00001040L, 0x00040040L, 0x10000000L, 0x10041000L
+};
+
+static void Unpack PROTO_LIST ((unsigned char *, UINT4 *));
+static void Pack PROTO_LIST ((UINT4 *, unsigned char *));
+static void DESKey PROTO_LIST ((UINT4 *, unsigned char *, int));
+static void CookKey PROTO_LIST ((UINT4 *, UINT4 *, int));
+static void DESFunction PROTO_LIST ((UINT4 *, UINT4 *));
+
+/* Initialize context.  Caller must zeroize the context when finished.
+ */
+void DES_CBCInit (context, key, iv, encrypt)
+DES_CBC_CTX *context;                                            /* context */
+unsigned char key[8];                                                /* key */
+unsigned char iv[8];                                 /* initializing vector */
+int encrypt;                     /* encrypt flag (1 = encrypt, 0 = decrypt) */
+{  
+  /* Copy encrypt flag to context.
+   */
+  context->encrypt = encrypt;
+
+  /* Pack initializing vector into context.
+   */
+  Pack (context->iv, iv);
+
+  /* Save the IV for use in Restart */
+  context->originalIV[0] = context->iv[0];
+  context->originalIV[1] = context->iv[1];
+
+  /* Precompute key schedule
+   */
+  DESKey (context->subkeys, key, encrypt);
+}
+
+/* DES-CBC block update operation. Continues a DES-CBC encryption
+   operation, processing eight-byte message blocks, and updating
+   the context.
+ */
+int DES_CBCUpdate (context, output, input, len)
+DES_CBC_CTX *context;                                            /* context */
+unsigned char *output;                                      /* output block */
+unsigned char *input;                                        /* input block */
+unsigned int len;                      /* length of input and output blocks */
+{
+  UINT4 inputBlock[2], work[2];
+  unsigned int i;
+  
+  if (len % 8)
+    return (RE_LEN);
+
+  for (i = 0; i < len/8; i++) {
+    Pack (inputBlock, &input[8*i]);
+        
+    /* Chain if encrypting.
+     */
+    if (context->encrypt) {
+      work[0] = inputBlock[0] ^ context->iv[0];
+      work[1] = inputBlock[1] ^ context->iv[1];
+    }
+    else {
+      work[0] = inputBlock[0];
+      work[1] = inputBlock[1];         
+    }
+
+    DESFunction (work, context->subkeys);
+
+    /* Chain if decrypting, then update IV.
+     */
+    if (context->encrypt) {
+      context->iv[0] = work[0];
+      context->iv[1] = work[1];
+    }
+    else {
+      work[0] ^= context->iv[0];
+      work[1] ^= context->iv[1];
+      context->iv[0] = inputBlock[0];
+      context->iv[1] = inputBlock[1];
+    }
+    Unpack (&output[8*i], work);
+  }
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)inputBlock, 0, sizeof (inputBlock));
+  R_memset ((POINTER)work, 0, sizeof (work));
+  
+  return (0);
+}
+
+void DES_CBCRestart (context)
+DES_CBC_CTX *context;
+{
+  /* Reset to the original IV */
+  context->iv[0] = context->originalIV[0];
+  context->iv[1] = context->originalIV[1];
+}
+
+/* Initialize context.  Caller must zeroize the context when finished.
+   The key has the DES key, input whitener and output whitener concatenated.
+ */
+void DESX_CBCInit (context, key, iv, encrypt)
+DESX_CBC_CTX *context;
+unsigned char key[24];                              /* DES key and whiteners */
+unsigned char iv[8];                              /* DES initializing vector */
+int encrypt;                      /* encrypt flag (1 = encrypt, 0 = decrypt) */
+{  
+  /* Copy encrypt flag to context.
+   */
+  context->encrypt = encrypt;
+
+  /* Pack initializing vector and whiteners into context.
+   */
+  Pack (context->iv, iv);
+  Pack (context->inputWhitener, key + 8);
+  Pack (context->outputWhitener, key + 16);
+
+  /* Save the IV for use in Restart */
+  context->originalIV[0] = context->iv[0];
+  context->originalIV[1] = context->iv[1];
+
+  /* Precompute key schedule.
+   */
+  DESKey (context->subkeys, key, encrypt);
+}
+
+/* DESX-CBC block update operation. Continues a DESX-CBC encryption
+   operation, processing eight-byte message blocks, and updating
+   the context.
+ */
+int DESX_CBCUpdate (context, output, input, len)
+DESX_CBC_CTX *context;                                           /* context */
+unsigned char *output;                                      /* output block */
+unsigned char *input;                                        /* input block */
+unsigned int len;                      /* length of input and output blocks */
+{
+  UINT4 inputBlock[2], work[2];
+  unsigned int i;
+  
+  if (len % 8)
+    return (RE_LEN);
+
+  for (i = 0; i < len/8; i++)  {
+    Pack (inputBlock, &input[8*i]);
+        
+    /* Chain if encrypting, and xor with whitener.
+     */
+    if (context->encrypt) {
+      work[0] =
+        inputBlock[0] ^ context->iv[0] ^ context->inputWhitener[0];
+      work[1] =
+        inputBlock[1] ^ context->iv[1] ^ context->inputWhitener[1];
+    }
+    else {
+      work[0] = inputBlock[0] ^ context->outputWhitener[0];
+      work[1] = inputBlock[1] ^ context->outputWhitener[1];         
+    }
+
+    DESFunction (work, context->subkeys);
+
+    /* Xor with whitener, chain if decrypting, then update IV.
+     */
+    if (context->encrypt) {
+      work[0] ^= context->outputWhitener[0];
+      work[1] ^= context->outputWhitener[1];
+      context->iv[0] = work[0];
+      context->iv[1] = work[1];
+    }
+    else {
+      work[0] ^= context->iv[0] ^ context->inputWhitener[0];
+      work[1] ^= context->iv[1] ^ context->inputWhitener[1];
+      context->iv[0] = inputBlock[0];
+      context->iv[1] = inputBlock[1];
+    }
+    Unpack (&output[8*i], work);
+  }
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)inputBlock, 0, sizeof (inputBlock));
+  R_memset ((POINTER)work, 0, sizeof (work));
+  
+  return (0);
+}
+
+void DESX_CBCRestart (context)
+DESX_CBC_CTX *context;
+{
+  /* Reset to the original IV */
+  context->iv[0] = context->originalIV[0];
+  context->iv[1] = context->originalIV[1];
+}
+
+/* Initialize context.  Caller must zeroize the context when finished.
+ */
+void DES3_CBCInit(context, key, iv, encrypt)
+DES3_CBC_CTX *context;                                           /* context */
+unsigned char key[24];                                               /* key */
+unsigned char iv[8];                                 /* initializing vector */
+int encrypt;                     /* encrypt flag (1 = encrypt, 0 = decrypt) */
+{  
+  /* Copy encrypt flag to context.
+   */
+  context->encrypt = encrypt;
+
+  /* Pack initializing vector into context.
+   */
+  Pack (context->iv, iv);
+
+  /* Save the IV for use in Restart */
+  context->originalIV[0] = context->iv[0];
+  context->originalIV[1] = context->iv[1];
+
+  /* Precompute key schedules.
+   */
+  DESKey (context->subkeys[0], encrypt ? key : &key[16], encrypt);
+  DESKey (context->subkeys[1], &key[8], !encrypt);
+  DESKey (context->subkeys[2], encrypt ? &key[16] : key, encrypt);
+}
+
+int DES3_CBCUpdate (context, output, input, len)
+DES3_CBC_CTX *context;                                           /* context */
+unsigned char *output;                                      /* output block */
+unsigned char *input;                                        /* input block */
+unsigned int len;                      /* length of input and output blocks */
+{
+  UINT4 inputBlock[2], work[2];
+  unsigned int i;
+  
+  if (len % 8)
+    return (RE_LEN);
+
+  for (i = 0; i < len/8; i++) {
+    Pack (inputBlock, &input[8*i]);
+        
+    /* Chain if encrypting.
+     */
+    if (context->encrypt) {
+      work[0] = inputBlock[0] ^ context->iv[0];
+      work[1] = inputBlock[1] ^ context->iv[1];
+    }
+    else {
+      work[0] = inputBlock[0];
+      work[1] = inputBlock[1];         
+    }
+
+    DESFunction (work, context->subkeys[0]);
+    DESFunction (work, context->subkeys[1]);
+    DESFunction (work, context->subkeys[2]);
+
+    /* Chain if decrypting, then update IV.
+     */
+    if (context->encrypt) {
+      context->iv[0] = work[0];
+      context->iv[1] = work[1];
+    }
+    else {
+      work[0] ^= context->iv[0];
+      work[1] ^= context->iv[1];
+      context->iv[0] = inputBlock[0];
+      context->iv[1] = inputBlock[1];
+    }
+    Unpack (&output[8*i], work);
+  }
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)inputBlock, 0, sizeof (inputBlock));
+  R_memset ((POINTER)work, 0, sizeof (work));
+  
+  return (0);
+}
+
+void DES3_CBCRestart (context)
+DES3_CBC_CTX *context;
+{
+  /* Reset to the original IV */
+  context->iv[0] = context->originalIV[0];
+  context->iv[1] = context->originalIV[1];
+}
+
+static void Pack (into, outof)
+UINT4 *into;
+unsigned char *outof;
+{
+  *into    = (*outof++ & 0xffL) << 24;
+  *into   |= (*outof++ & 0xffL) << 16;
+  *into   |= (*outof++ & 0xffL) << 8;
+  *into++ |= (*outof++ & 0xffL);
+  *into    = (*outof++ & 0xffL) << 24;
+  *into   |= (*outof++ & 0xffL) << 16;
+  *into   |= (*outof++ & 0xffL) << 8;
+  *into   |= (*outof   & 0xffL);
+}
+
+static void Unpack (into, outof)
+unsigned char *into;
+UINT4 *outof;
+{
+  *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+  *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+  *into++ = (unsigned char)((*outof >>  8) & 0xffL);
+  *into++ = (unsigned char)( *outof++      & 0xffL);
+  *into++ = (unsigned char)((*outof >> 24) & 0xffL);
+  *into++ = (unsigned char)((*outof >> 16) & 0xffL);
+  *into++ = (unsigned char)((*outof >>  8) & 0xffL);
+  *into   = (unsigned char)( *outof        & 0xffL);
+}
+
+static void DESKey (subkeys, key, encrypt)
+UINT4 subkeys[32];
+unsigned char key[8];
+int encrypt;
+{
+  UINT4 kn[32];
+  int i, j, l, m, n;
+  unsigned char pc1m[56], pcr[56];
+
+  for (j = 0; j < 56; j++) {
+    l = PC1[j];
+    m = l & 07;
+    pc1m[j] = (unsigned char)((key[l >> 3] & BYTE_BIT[m]) ? 1 : 0);
+  }
+  for (i = 0; i < 16; i++) {
+    m = i << 1;
+    n = m + 1;
+    kn[m] = kn[n] = 0L;
+    for (j = 0; j < 28; j++) {
+      l = j + TOTAL_ROTATIONS[i];
+      if (l < 28)
+        pcr[j] = pc1m[l];
+      else
+        pcr[j] = pc1m[l - 28];
+    }
+    for (j = 28; j < 56; j++) {
+      l = j + TOTAL_ROTATIONS[i];
+      if (l < 56)
+        pcr[j] = pc1m[l];
+      else
+        pcr[j] = pc1m[l - 28];
+    }
+    for (j = 0; j < 24; j++) {
+      if (pcr[PC2[j]])
+        kn[m] |= BIG_BYTE[j];
+      if (pcr[PC2[j+24]])
+        kn[n] |= BIG_BYTE[j];
+    }
+  }
+  CookKey (subkeys, kn, encrypt);
+
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)pc1m, 0, sizeof (pc1m));
+  R_memset ((POINTER)pcr, 0, sizeof (pcr));
+  R_memset ((POINTER)kn, 0, sizeof (kn));
+}
+
+static void CookKey (subkeys, kn, encrypt)
+UINT4 *subkeys;
+UINT4 *kn;
+int encrypt;
+{
+  UINT4 *cooked, *raw0, *raw1;
+  int increment;
+  unsigned int i;
+
+  raw1 = kn;
+  cooked = encrypt ? subkeys : &subkeys[30];
+  increment = encrypt ? 1 : -3;
+
+  for (i = 0; i < 16; i++, raw1++) {
+    raw0 = raw1++;
+    *cooked    = (*raw0 & 0x00fc0000L) << 6;
+    *cooked   |= (*raw0 & 0x00000fc0L) << 10;
+    *cooked   |= (*raw1 & 0x00fc0000L) >> 10;
+    *cooked++ |= (*raw1 & 0x00000fc0L) >> 6;
+    *cooked    = (*raw0 & 0x0003f000L) << 12;
+    *cooked   |= (*raw0 & 0x0000003fL) << 16;
+    *cooked   |= (*raw1 & 0x0003f000L) >> 4;
+    *cooked   |= (*raw1 & 0x0000003fL);
+    cooked += increment;
+  }
+}
+
+static void DESFunction (block, subkeys)
+UINT4 *block;
+UINT4 *subkeys;
+{
+  register UINT4 fval, work, right, left;
+  register int round;
+  
+  left = block[0];
+  right = block[1];
+  work = ((left >> 4) ^ right) & 0x0f0f0f0fL;
+  right ^= work;
+  left ^= (work << 4);
+  work = ((left >> 16) ^ right) & 0x0000ffffL;
+  right ^= work;
+  left ^= (work << 16);
+  work = ((right >> 2) ^ left) & 0x33333333L;
+  left ^= work;
+  right ^= (work << 2);
+  work = ((right >> 8) ^ left) & 0x00ff00ffL;
+  left ^= work;
+  right ^= (work << 8);
+  right = ((right << 1) | ((right >> 31) & 1L)) & 0xffffffffL;
+  work = (left ^ right) & 0xaaaaaaaaL;
+  left ^= work;
+  right ^= work;
+  left = ((left << 1) | ((left >> 31) & 1L)) & 0xffffffffL;
+  
+  for (round = 0; round < 8; round++) {
+    work  = (right << 28) | (right >> 4);
+    work ^= *subkeys++;
+    fval  = SP7[ work        & 0x3fL];
+    fval |= SP5[(work >>  8) & 0x3fL];
+    fval |= SP3[(work >> 16) & 0x3fL];
+    fval |= SP1[(work >> 24) & 0x3fL];
+    work  = right ^ *subkeys++;
+    fval |= SP8[ work        & 0x3fL];
+    fval |= SP6[(work >>  8) & 0x3fL];
+    fval |= SP4[(work >> 16) & 0x3fL];
+    fval |= SP2[(work >> 24) & 0x3fL];
+    left ^= fval;
+    work  = (left << 28) | (left >> 4);
+    work ^= *subkeys++;
+    fval  = SP7[ work        & 0x3fL];
+    fval |= SP5[(work >>  8) & 0x3fL];
+    fval |= SP3[(work >> 16) & 0x3fL];
+    fval |= SP1[(work >> 24) & 0x3fL];
+    work  = left ^ *subkeys++;
+    fval |= SP8[ work        & 0x3fL];
+    fval |= SP6[(work >>  8) & 0x3fL];
+    fval |= SP4[(work >> 16) & 0x3fL];
+    fval |= SP2[(work >> 24) & 0x3fL];
+    right ^= fval;
+  }
+  
+  right = (right << 31) | (right >> 1);
+  work = (left ^ right) & 0xaaaaaaaaL;
+  left ^= work;
+  right ^= work;
+  left = (left << 31) | (left >> 1);
+  work = ((left >> 8) ^ right) & 0x00ff00ffL;
+  right ^= work;
+  left ^= (work << 8);
+  work = ((left >> 2) ^ right) & 0x33333333L;
+  right ^= work;
+  left ^= (work << 2);
+  work = ((right >> 16) ^ left) & 0x0000ffffL;
+  left ^= work;
+  right ^= (work << 16);
+  work = ((right >> 4) ^ left) & 0x0f0f0f0fL;
+  left ^= work;
+  right ^= (work << 4);
+  *block++ = right;
+  *block = left;
+}
diff --git a/util/rsaref/digit.c b/util/rsaref/digit.c
new file mode 100644 (file)
index 0000000..19bcaed
--- /dev/null
@@ -0,0 +1,107 @@
+/* DIGIT.C - digit arithmetic routines
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+      Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "nn.h"
+#include "digit.h"
+
+/* Computes a = b * c, where b and c are digits.
+
+   Lengths: a[2].
+ */
+void NN_DigitMult (a, b, c)
+NN_DIGIT a[2], b, c;
+{
+  NN_DIGIT t, u;
+  NN_HALF_DIGIT bHigh, bLow, cHigh, cLow;
+
+  bHigh = (NN_HALF_DIGIT)HIGH_HALF (b);
+  bLow = (NN_HALF_DIGIT)LOW_HALF (b);
+  cHigh = (NN_HALF_DIGIT)HIGH_HALF (c);
+  cLow = (NN_HALF_DIGIT)LOW_HALF (c);
+
+  a[0] = (NN_DIGIT)bLow * (NN_DIGIT)cLow;
+  t = (NN_DIGIT)bLow * (NN_DIGIT)cHigh;
+  u = (NN_DIGIT)bHigh * (NN_DIGIT)cLow;
+  a[1] = (NN_DIGIT)bHigh * (NN_DIGIT)cHigh;
+  
+  if ((t += u) < u)
+    a[1] += TO_HIGH_HALF (1);
+  u = TO_HIGH_HALF (t);
+  
+  if ((a[0] += u) < u)
+    a[1]++;
+  a[1] += HIGH_HALF (t);
+}
+
+/* Sets a = b / c, where a and c are digits.
+
+   Lengths: b[2].
+   Assumes b[1] < c and HIGH_HALF (c) > 0. For efficiency, c should be
+   normalized.
+ */
+void NN_DigitDiv (a, b, c)
+NN_DIGIT *a, b[2], c;
+{
+  NN_DIGIT t[2], u, v;
+  NN_HALF_DIGIT aHigh, aLow, cHigh, cLow;
+
+  cHigh = (NN_HALF_DIGIT)HIGH_HALF (c);
+  cLow = (NN_HALF_DIGIT)LOW_HALF (c);
+
+  t[0] = b[0];
+  t[1] = b[1];
+
+  /* Underestimate high half of quotient and subtract.
+   */
+  if (cHigh == MAX_NN_HALF_DIGIT)
+    aHigh = (NN_HALF_DIGIT)HIGH_HALF (t[1]);
+  else
+    aHigh = (NN_HALF_DIGIT)(t[1] / (cHigh + 1));
+  u = (NN_DIGIT)aHigh * (NN_DIGIT)cLow;
+  v = (NN_DIGIT)aHigh * (NN_DIGIT)cHigh;
+  if ((t[0] -= TO_HIGH_HALF (u)) > (MAX_NN_DIGIT - TO_HIGH_HALF (u)))
+    t[1]--;
+  t[1] -= HIGH_HALF (u);
+  t[1] -= v;
+
+  /* Correct estimate.
+   */
+  while ((t[1] > cHigh) ||
+         ((t[1] == cHigh) && (t[0] >= TO_HIGH_HALF (cLow)))) {
+    if ((t[0] -= TO_HIGH_HALF (cLow)) > MAX_NN_DIGIT - TO_HIGH_HALF (cLow))
+      t[1]--;
+    t[1] -= cHigh;
+    aHigh++;
+  }
+
+  /* Underestimate low half of quotient and subtract.
+   */
+  if (cHigh == MAX_NN_HALF_DIGIT)
+    aLow = (NN_HALF_DIGIT)LOW_HALF (t[1]);
+  else
+    aLow = 
+      (NN_HALF_DIGIT)((TO_HIGH_HALF (t[1]) + HIGH_HALF (t[0])) / (cHigh + 1));
+  u = (NN_DIGIT)aLow * (NN_DIGIT)cLow;
+  v = (NN_DIGIT)aLow * (NN_DIGIT)cHigh;
+  if ((t[0] -= u) > (MAX_NN_DIGIT - u))
+    t[1]--;
+  if ((t[0] -= TO_HIGH_HALF (v)) > (MAX_NN_DIGIT - TO_HIGH_HALF (v)))
+    t[1]--;
+  t[1] -= HIGH_HALF (v);
+
+  /* Correct estimate.
+   */
+  while ((t[1] > 0) || ((t[1] == 0) && t[0] >= c)) {
+    if ((t[0] -= c) > (MAX_NN_DIGIT - c))
+      t[1]--;
+    aLow++;
+  }
+  
+  *a = TO_HIGH_HALF (aHigh) + aLow;
+}
diff --git a/util/rsaref/digit.h b/util/rsaref/digit.h
new file mode 100644 (file)
index 0000000..2fb7c47
--- /dev/null
@@ -0,0 +1,9 @@
+/* DIGIT.H - header file for DIGIT.C
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+void NN_DigitMult PROTO_LIST ((NN_DIGIT [2], NN_DIGIT, NN_DIGIT));
+void NN_DigitDiv PROTO_LIST ((NN_DIGIT *, NN_DIGIT [2], NN_DIGIT));
diff --git a/util/rsaref/global.h b/util/rsaref/global.h
new file mode 100644 (file)
index 0000000..360cc6e
--- /dev/null
@@ -0,0 +1,46 @@
+/* GLOBAL.H - RSAREF types and constants
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#ifndef _GLOBAL_H_
+#define _GLOBAL_H_ 1
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+     function argument prototyping.
+   The following makes PROTOTYPES default to 1 if it has not already been
+     defined as 0 with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef unsigned short int UINT2;
+
+/* UINT4 defines a four byte word */
+typedef unsigned long int UINT4;
+
+#ifndef NULL_PTR
+#define NULL_PTR ((POINTER)0)
+#endif
+
+#ifndef UNUSED_ARG
+#define UNUSED_ARG(x) x = *(&x);
+#endif
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+   If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+     returns an empty list.  
+ */
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+#endif /* end _GLOBAL_H_ */
diff --git a/util/rsaref/md2.h b/util/rsaref/md2.h
new file mode 100644 (file)
index 0000000..f25467c
--- /dev/null
@@ -0,0 +1,45 @@
+/* MD2.H - header file for MD2C.C
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+   rights reserved.
+
+   License to copy and use this software is granted for
+   non-commercial Internet Privacy-Enhanced Mail provided that it is
+   identified as the "RSA Data Security, Inc. MD2 Message Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.  
+ */
+
+#ifndef _MD2_H_
+#define _MD2_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+  unsigned char state[16];                                 /* state */
+  unsigned char checksum[16];                           /* checksum */
+  unsigned int count;                 /* number of bytes, modulo 16 */
+  unsigned char buffer[16];                         /* input buffer */
+} MD2_CTX;
+
+void MD2Init PROTO_LIST ((MD2_CTX *));
+void MD2Update PROTO_LIST
+  ((MD2_CTX *, unsigned char *, unsigned int));
+void MD2Final PROTO_LIST ((unsigned char [16], MD2_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/util/rsaref/md2c.c b/util/rsaref/md2c.c
new file mode 100644 (file)
index 0000000..bef0e84
--- /dev/null
@@ -0,0 +1,218 @@
+/* MD2C.C - RSA Data Security, Inc., MD2 message-digest algorithm
+ */
+
+/* Copyright (C) 1990-2, RSA Data Security, Inc. Created 1990. All
+   rights reserved.
+
+   License to copy and use this software is granted for
+   non-commercial Internet Privacy-Enhanced Mail provided that it is
+   identified as the "RSA Data Security, Inc. MD2 Message Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.
+
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.  
+ */
+
+#include "global.h"
+#include "md2.h"
+
+static void MD2Transform PROTO_LIST
+  ((unsigned char [16], unsigned char [16], unsigned char [16]));
+static void MD2_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD2_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+/* Permutation of 0..255 constructed from the digits of pi. It gives a
+   "random" nonlinear byte substitution operation.
+ */
+static unsigned char PI_SUBST[256] = {
+  41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
+  19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
+  76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
+  138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
+  245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
+  148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
+  39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
+  181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
+  150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
+  112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
+  96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
+  85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
+  234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
+  129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
+  8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
+  203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
+  166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
+  31, 26, 219, 153, 141, 51, 159, 17, 131, 20
+};
+
+static unsigned char *PADDING[] = {
+  (unsigned char *)"",
+  (unsigned char *)"\001",
+  (unsigned char *)"\002\002",
+  (unsigned char *)"\003\003\003",
+  (unsigned char *)"\004\004\004\004",
+  (unsigned char *)"\005\005\005\005\005",
+  (unsigned char *)"\006\006\006\006\006\006", 
+  (unsigned char *)"\007\007\007\007\007\007\007",
+  (unsigned char *)"\010\010\010\010\010\010\010\010",
+  (unsigned char *)"\011\011\011\011\011\011\011\011\011",
+  (unsigned char *)"\012\012\012\012\012\012\012\012\012\012",
+  (unsigned char *)"\013\013\013\013\013\013\013\013\013\013\013",
+  (unsigned char *)"\014\014\014\014\014\014\014\014\014\014\014\014",
+  (unsigned char *)
+    "\015\015\015\015\015\015\015\015\015\015\015\015\015",
+  (unsigned char *)
+    "\016\016\016\016\016\016\016\016\016\016\016\016\016\016",
+  (unsigned char *)
+    "\017\017\017\017\017\017\017\017\017\017\017\017\017\017\017",
+  (unsigned char *)
+    "\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020\020"
+};
+
+/* MD2 initialization. Begins an MD2 operation, writing a new context.
+ */
+void MD2Init (context)
+MD2_CTX *context;                                        /* context */
+{
+  context->count = 0;
+  MD2_memset ((POINTER)context->state, 0, sizeof (context->state));
+  MD2_memset
+    ((POINTER)context->checksum, 0, sizeof (context->checksum));
+}
+
+/* MD2 block update operation. Continues an MD2 message-digest
+     operation, processing another message block, and updating the
+     context.
+ */
+void MD2Update (context, input, inputLen)
+MD2_CTX *context;                                        /* context */
+unsigned char *input;                                /* input block */
+unsigned int inputLen;                     /* length of input block */
+{
+  unsigned int i, index, partLen;
+  
+  /* Update number of bytes mod 16 */
+  index = context->count;
+  context->count = (index + inputLen) & 0xf;
+  
+  partLen = 16 - index;
+  
+  /* Transform as many times as possible.
+    */
+  if (inputLen >= partLen) {
+    MD2_memcpy
+      ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+    MD2Transform (context->state, context->checksum, context->buffer);
+
+    for (i = partLen; i + 15 < inputLen; i += 16)
+      MD2Transform (context->state, context->checksum, &input[i]);
+    
+    index = 0;
+  }
+  else
+    i = 0;
+  
+  /* Buffer remaining input */
+  MD2_memcpy
+    ((POINTER)&context->buffer[index], (POINTER)&input[i],
+     inputLen-i);
+}
+
+/* MD2 finalization. Ends an MD2 message-digest operation, writing the
+     message digest and zeroizing the context.
+ */
+void MD2Final (digest, context)
+unsigned char digest[16];                         /* message digest */
+MD2_CTX *context;                                        /* context */
+{
+  unsigned int index, padLen;
+
+  /* Pad out to multiple of 16.
+   */
+  index = context->count;
+  padLen = 16 - index;
+  MD2Update (context, PADDING[padLen], padLen);
+
+  /* Extend with checksum */
+  MD2Update (context, context->checksum, 16);
+  
+  /* Store state in digest */
+  MD2_memcpy ((POINTER)digest, (POINTER)context->state, 16);
+  
+  /* Zeroize sensitive information.
+   */
+  MD2_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD2 basic transformation. Transforms state and updates checksum
+     based on block.
+ */
+static void MD2Transform (state, checksum, block)
+unsigned char state[16];
+unsigned char checksum[16];
+unsigned char block[16];
+{
+  unsigned int i, j, t;
+  unsigned char x[48];
+  
+  /* Form encryption block from state, block, state ^ block.
+   */
+  MD2_memcpy ((POINTER)x, (POINTER)state, 16);
+  MD2_memcpy ((POINTER)x+16, (POINTER)block, 16);
+  for (i = 0; i < 16; i++)
+    x[i+32] = state[i] ^ block[i];
+  
+  /* Encrypt block (18 rounds).
+   */
+  t = 0;
+  for (i = 0; i < 18; i++) {
+    for (j = 0; j < 48; j++)
+      t = x[j] ^= PI_SUBST[t];
+    t = (t + i) & 0xff;
+  }
+    
+  /* Save new state */
+  MD2_memcpy ((POINTER)state, (POINTER)x, 16);
+    
+  /* Update checksum.
+   */
+  t = checksum[15];
+  for (i = 0; i < 16; i++)
+    t = checksum[i] ^= PI_SUBST[block[i] ^ t];
+
+  /* Zeroize sensitive information.
+   */
+  MD2_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+static void MD2_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+  unsigned int i;
+  
+  for (i = 0; i < len; i++)
+    output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD2_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+  unsigned int i;
+  
+  for (i = 0; i < len; i++)
+    ((char *)output)[i] = (char)value;
+}
diff --git a/util/rsaref/md5.h b/util/rsaref/md5.h
new file mode 100644 (file)
index 0000000..94774ba
--- /dev/null
@@ -0,0 +1,49 @@
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+   rights reserved.
+
+   License to copy and use this software is granted provided that it
+   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   License is also granted to make and use derivative works provided
+   that such works are identified as "derived from the RSA Data
+   Security, Inc. MD5 Message-Digest Algorithm" in all material
+   mentioning or referencing the derived work.  
+                                                                    
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.  
+                                                                    
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.  
+ */
+
+#ifndef _MD5_H_
+#define _MD5_H_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+  ((MD5_CTX *, unsigned char *, unsigned int));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/util/rsaref/md5c.c b/util/rsaref/md5c.c
new file mode 100644 (file)
index 0000000..8b0c856
--- /dev/null
@@ -0,0 +1,334 @@
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+   rights reserved.
+
+   License to copy and use this software is granted provided that it
+   is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+   Algorithm" in all material mentioning or referencing this software
+   or this function.
+
+   License is also granted to make and use derivative works provided
+   that such works are identified as "derived from the RSA Data
+   Security, Inc. MD5 Message-Digest Algorithm" in all material
+   mentioning or referencing the derived work.  
+                                                                    
+   RSA Data Security, Inc. makes no representations concerning either
+   the merchantability of this software or the suitability of this
+   software for any particular purpose. It is provided "as is"
+   without express or implied warranty of any kind.  
+                                                                    
+   These notices must be retained in any copies of any part of this
+   documentation and/or software.  
+ */
+
+#include "global.h"
+#include "md5.h"
+
+/* Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+static void Encode PROTO_LIST
+  ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+  ((UINT4 *, unsigned char *, unsigned int));
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+   Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+    (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+    (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+    (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+    (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+    (a) = ROTATE_LEFT ((a), (s)); \
+    (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context;                                        /* context */
+{
+  context->count[0] = context->count[1] = 0;
+
+  /* Load magic initialization constants.
+   */
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+     operation, processing another message block, and updating the
+     context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context;                                        /* context */
+unsigned char *input;                                /* input block */
+unsigned int inputLen;                     /* length of input block */
+{
+  unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3))
+      < ((UINT4)inputLen << 3))
+    context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+  
+  partLen = 64 - index;
+  
+  /* Transform as many times as possible.
+   */
+  if (inputLen >= partLen) {
+    MD5_memcpy
+      ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+    MD5Transform (context->state, context->buffer);
+  
+    for (i = partLen; i + 63 < inputLen; i += 64)
+      MD5Transform (context->state, &input[i]);
+    
+    index = 0;
+  }
+  else
+    i = 0;
+  
+  /* Buffer remaining input */
+  MD5_memcpy 
+    ((POINTER)&context->buffer[index], (POINTER)&input[i],
+     inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+     the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16];                         /* message digest */
+MD5_CTX *context;                                       /* context */
+{
+  unsigned char bits[8];
+  unsigned int index, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64.
+   */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (index < 56) ? (56 - index) : (120 - index);
+  MD5Update (context, PADDING, padLen);
+  
+  /* Append length (before padding) */
+  MD5Update (context, bits, 8);
+
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+  
+  /* Zeroize sensitive information.
+   */
+  MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+  
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+  /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+  
+  /* Zeroize sensitive information.
+   */
+  MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+     a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+    output[j] = (unsigned char)(input[i] & 0xff);
+    output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+    output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+    output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+     a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+    output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+  unsigned int i;
+  
+  for (i = 0; i < len; i++)
+    output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+  unsigned int i;
+  
+  for (i = 0; i < len; i++)
+    ((char *)output)[i] = (char)value;
+}
diff --git a/util/rsaref/nn.c b/util/rsaref/nn.c
new file mode 100644 (file)
index 0000000..6399e5c
--- /dev/null
@@ -0,0 +1,622 @@
+/* NN.C - natural numbers routines
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "nn.h"
+#include "digit.h"
+
+static NN_DIGIT NN_AddDigitMult PROTO_LIST 
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int));
+static NN_DIGIT NN_SubDigitMult PROTO_LIST 
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT, NN_DIGIT *, unsigned int));
+
+static unsigned int NN_DigitBits PROTO_LIST ((NN_DIGIT));
+
+/* Decodes character string b into a, where character string is ordered
+   from most to least significant.
+
+   Lengths: a[digits], b[len].
+   Assumes b[i] = 0 for i < len - digits * NN_DIGIT_LEN. (Otherwise most
+   significant bytes are truncated.)
+ */
+void NN_Decode (a, digits, b, len)
+NN_DIGIT *a;
+unsigned char *b;
+unsigned int digits, len;
+{
+  NN_DIGIT t;
+  int j;
+  unsigned int i, u;
+  
+  for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
+    t = 0;
+    for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8)
+      t |= ((NN_DIGIT)b[j]) << u;
+    a[i] = t;
+  }
+  
+  for (; i < digits; i++)
+    a[i] = 0;
+}
+
+/* Encodes b into character string a, where character string is ordered
+   from most to least significant.
+
+   Lengths: a[len], b[digits].
+   Assumes NN_Bits (b, digits) <= 8 * len. (Otherwise most significant
+   digits are truncated.)
+ */
+void NN_Encode (a, len, b, digits)
+NN_DIGIT *b;
+unsigned char *a;
+unsigned int digits, len;
+{
+  NN_DIGIT t;
+  int j;
+  unsigned int i, u;
+
+  for (i = 0, j = len - 1; i < digits && j >= 0; i++) {
+    t = b[i];
+    for (u = 0; j >= 0 && u < NN_DIGIT_BITS; j--, u += 8)
+      a[j] = (unsigned char)(t >> u);
+  }
+
+  for (; j >= 0; j--)
+    a[j] = 0;
+}
+
+/* Assigns a = b.
+
+   Lengths: a[digits], b[digits].
+ */
+void NN_Assign (a, b, digits)
+NN_DIGIT *a, *b;
+unsigned int digits;
+{
+  unsigned int i;
+
+  for (i = 0; i < digits; i++)
+    a[i] = b[i];
+}
+
+/* Assigns a = 0.
+
+   Lengths: a[digits].
+ */
+void NN_AssignZero (a, digits)
+NN_DIGIT *a;
+unsigned int digits;
+{
+  unsigned int i;
+
+  for (i = 0; i < digits; i++)
+    a[i] = 0;
+}
+
+/* Assigns a = 2^b.
+
+   Lengths: a[digits].
+   Requires b < digits * NN_DIGIT_BITS.
+ */
+void NN_Assign2Exp (a, b, digits)
+NN_DIGIT *a;
+unsigned int b, digits;
+{
+  NN_AssignZero (a, digits);
+
+  if (b >= digits * NN_DIGIT_BITS)
+    return;
+
+  a[b / NN_DIGIT_BITS] = (NN_DIGIT)1 << (b % NN_DIGIT_BITS);
+}
+
+/* Computes a = b + c. Returns carry.
+
+   Lengths: a[digits], b[digits], c[digits].
+ */
+NN_DIGIT NN_Add (a, b, c, digits)
+NN_DIGIT *a, *b, *c;
+unsigned int digits;
+{
+  NN_DIGIT ai, carry;
+  unsigned int i;
+
+  carry = 0;
+
+  for (i = 0; i < digits; i++) {
+    if ((ai = b[i] + carry) < carry)
+      ai = c[i];
+    else if ((ai += c[i]) < c[i])
+      carry = 1;
+    else
+      carry = 0;
+    a[i] = ai;
+  }
+
+  return (carry);
+}
+
+/* Computes a = b - c. Returns borrow.
+
+   Lengths: a[digits], b[digits], c[digits].
+ */
+NN_DIGIT NN_Sub (a, b, c, digits)
+NN_DIGIT *a, *b, *c;
+unsigned int digits;
+{
+  NN_DIGIT ai, borrow;
+  unsigned int i;
+
+  borrow = 0;
+
+  for (i = 0; i < digits; i++) {
+    if ((ai = b[i] - borrow) > (MAX_NN_DIGIT - borrow))
+      ai = MAX_NN_DIGIT - c[i];
+    else if ((ai -= c[i]) > (MAX_NN_DIGIT - c[i]))
+      borrow = 1;
+    else
+      borrow = 0;
+    a[i] = ai;
+  }
+
+  return (borrow);
+}
+
+/* Computes a = b * c.
+
+   Lengths: a[2*digits], b[digits], c[digits].
+   Assumes digits < MAX_NN_DIGITS.
+ */
+void NN_Mult (a, b, c, digits)
+NN_DIGIT *a, *b, *c;
+unsigned int digits;
+{
+  NN_DIGIT t[2*MAX_NN_DIGITS];
+  unsigned int bDigits, cDigits, i;
+
+  NN_AssignZero (t, 2 * digits);
+  
+  bDigits = NN_Digits (b, digits);
+  cDigits = NN_Digits (c, digits);
+
+  for (i = 0; i < bDigits; i++)
+    t[i+cDigits] += NN_AddDigitMult (&t[i], &t[i], b[i], c, cDigits);
+  
+  NN_Assign (a, t, 2 * digits);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)t, 0, sizeof (t));
+}
+
+/* Computes a = b * 2^c (i.e., shifts left c bits), returning carry.
+
+   Lengths: a[digits], b[digits].
+   Requires c < NN_DIGIT_BITS.
+ */
+NN_DIGIT NN_LShift (a, b, c, digits)
+NN_DIGIT *a, *b;
+unsigned int c, digits;
+{
+  NN_DIGIT bi, carry;
+  unsigned int i, t;
+  
+  if (c >= NN_DIGIT_BITS)
+    return (0);
+  
+  t = NN_DIGIT_BITS - c;
+
+  carry = 0;
+
+  for (i = 0; i < digits; i++) {
+    bi = b[i];
+    a[i] = (bi << c) | carry;
+    carry = c ? (bi >> t) : 0;
+  }
+  
+  return (carry);
+}
+
+/* Computes a = c div 2^c (i.e., shifts right c bits), returning carry.
+
+   Lengths: a[digits], b[digits].
+   Requires: c < NN_DIGIT_BITS.
+ */
+NN_DIGIT NN_RShift (a, b, c, digits)
+NN_DIGIT *a, *b;
+unsigned int c, digits;
+{
+  NN_DIGIT bi, carry;
+  int i;
+  unsigned int t;
+  
+  if (c >= NN_DIGIT_BITS)
+    return (0);
+  
+  t = NN_DIGIT_BITS - c;
+
+  carry = 0;
+
+  for (i = digits - 1; i >= 0; i--) {
+    bi = b[i];
+    a[i] = (bi >> c) | carry;
+    carry = c ? (bi << t) : 0;
+  }
+  
+  return (carry);
+}
+
+/* Computes a = c div d and b = c mod d.
+
+   Lengths: a[cDigits], b[dDigits], c[cDigits], d[dDigits].
+   Assumes d > 0, cDigits < 2 * MAX_NN_DIGITS,
+           dDigits < MAX_NN_DIGITS.
+ */
+void NN_Div (a, b, c, cDigits, d, dDigits)
+NN_DIGIT *a, *b, *c, *d;
+unsigned int cDigits, dDigits;
+{
+  NN_DIGIT ai, cc[2*MAX_NN_DIGITS+1], dd[MAX_NN_DIGITS], t;
+  int i;
+  unsigned int ddDigits, shift;
+  
+  ddDigits = NN_Digits (d, dDigits);
+  if (ddDigits == 0)
+    return;
+  
+  /* Normalize operands.
+   */
+  shift = NN_DIGIT_BITS - NN_DigitBits (d[ddDigits-1]);
+  NN_AssignZero (cc, ddDigits);
+  cc[cDigits] = NN_LShift (cc, c, shift, cDigits);
+  NN_LShift (dd, d, shift, ddDigits);
+  t = dd[ddDigits-1];
+  
+  NN_AssignZero (a, cDigits);
+
+  for (i = cDigits-ddDigits; i >= 0; i--) {
+    /* Underestimate quotient digit and subtract.
+     */
+    if (t == MAX_NN_DIGIT)
+      ai = cc[i+ddDigits];
+    else
+      NN_DigitDiv (&ai, &cc[i+ddDigits-1], t + 1);
+    cc[i+ddDigits] -= NN_SubDigitMult (&cc[i], &cc[i], ai, dd, ddDigits);
+
+    /* Correct estimate.
+     */
+    while (cc[i+ddDigits] || (NN_Cmp (&cc[i], dd, ddDigits) >= 0)) {
+      ai++;
+      cc[i+ddDigits] -= NN_Sub (&cc[i], &cc[i], dd, ddDigits);
+    }
+    
+    a[i] = ai;
+  }
+  
+  /* Restore result.
+   */
+  NN_AssignZero (b, dDigits);
+  NN_RShift (b, cc, shift, ddDigits);
+
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)cc, 0, sizeof (cc));
+  R_memset ((POINTER)dd, 0, sizeof (dd));
+}
+
+/* Computes a = b mod c.
+
+   Lengths: a[cDigits], b[bDigits], c[cDigits].
+   Assumes c > 0, bDigits < 2 * MAX_NN_DIGITS, cDigits < MAX_NN_DIGITS.
+ */
+void NN_Mod (a, b, bDigits, c, cDigits)
+NN_DIGIT *a, *b, *c;
+unsigned int bDigits, cDigits;
+{
+  NN_DIGIT t[2 * MAX_NN_DIGITS];
+  
+  NN_Div (t, a, b, bDigits, c, cDigits);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)t, 0, sizeof (t));
+}
+
+/* Computes a = b * c mod d.
+
+   Lengths: a[digits], b[digits], c[digits], d[digits].
+   Assumes d > 0, digits < MAX_NN_DIGITS.
+ */
+void NN_ModMult (a, b, c, d, digits)
+NN_DIGIT *a, *b, *c, *d;
+unsigned int digits;
+{
+  NN_DIGIT t[2*MAX_NN_DIGITS];
+
+  NN_Mult (t, b, c, digits);
+  NN_Mod (a, t, 2 * digits, d, digits);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)t, 0, sizeof (t));
+}
+
+/* Computes a = b^c mod d.
+
+   Lengths: a[dDigits], b[dDigits], c[cDigits], d[dDigits].
+   Assumes d > 0, cDigits > 0, dDigits < MAX_NN_DIGITS.
+ */
+void NN_ModExp (a, b, c, cDigits, d, dDigits)
+NN_DIGIT *a, *b, *c, *d;
+unsigned int cDigits, dDigits;
+{
+  NN_DIGIT bPower[3][MAX_NN_DIGITS], ci, t[MAX_NN_DIGITS];
+  int i;
+  unsigned int ciBits, j, s;
+
+  /* Store b, b^2 mod d, and b^3 mod d.
+   */
+  NN_Assign (bPower[0], b, dDigits);
+  NN_ModMult (bPower[1], bPower[0], b, d, dDigits);
+  NN_ModMult (bPower[2], bPower[1], b, d, dDigits);
+  
+  NN_ASSIGN_DIGIT (t, 1, dDigits);
+
+  cDigits = NN_Digits (c, cDigits);
+  for (i = cDigits - 1; i >= 0; i--) {
+    ci = c[i];
+    ciBits = NN_DIGIT_BITS;
+    
+    /* Scan past leading zero bits of most significant digit.
+     */
+    if (i == (int)(cDigits - 1)) {
+      while (! DIGIT_2MSB (ci)) {
+        ci <<= 2;
+        ciBits -= 2;
+      }
+    }
+
+    for (j = 0; j < ciBits; j += 2, ci <<= 2) {
+      /* Compute t = t^4 * b^s mod d, where s = two MSB's of ci.
+       */
+      NN_ModMult (t, t, t, d, dDigits);
+      NN_ModMult (t, t, t, d, dDigits);
+      if ((s = DIGIT_2MSB (ci)) != 0)
+        NN_ModMult (t, t, bPower[s-1], d, dDigits);
+    }
+  }
+  
+  NN_Assign (a, t, dDigits);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)bPower, 0, sizeof (bPower));
+  R_memset ((POINTER)t, 0, sizeof (t));
+}
+
+/* Compute a = 1/b mod c, assuming inverse exists.
+   
+   Lengths: a[digits], b[digits], c[digits].
+   Assumes gcd (b, c) = 1, digits < MAX_NN_DIGITS.
+ */
+void NN_ModInv (a, b, c, digits)
+NN_DIGIT *a, *b, *c;
+unsigned int digits;
+{
+  NN_DIGIT q[MAX_NN_DIGITS], t1[MAX_NN_DIGITS], t3[MAX_NN_DIGITS],
+    u1[MAX_NN_DIGITS], u3[MAX_NN_DIGITS], v1[MAX_NN_DIGITS],
+    v3[MAX_NN_DIGITS], w[2*MAX_NN_DIGITS];
+  int u1Sign;
+
+  /* Apply extended Euclidean algorithm, modified to avoid negative
+     numbers.
+   */
+  NN_ASSIGN_DIGIT (u1, 1, digits);
+  NN_AssignZero (v1, digits);
+  NN_Assign (u3, b, digits);
+  NN_Assign (v3, c, digits);
+  u1Sign = 1;
+
+  while (! NN_Zero (v3, digits)) {
+    NN_Div (q, t3, u3, digits, v3, digits);
+    NN_Mult (w, q, v1, digits);
+    NN_Add (t1, u1, w, digits);
+    NN_Assign (u1, v1, digits);
+    NN_Assign (v1, t1, digits);
+    NN_Assign (u3, v3, digits);
+    NN_Assign (v3, t3, digits);
+    u1Sign = -u1Sign;
+  }
+  
+  /* Negate result if sign is negative.
+    */
+  if (u1Sign < 0)
+    NN_Sub (a, c, u1, digits);
+  else
+    NN_Assign (a, u1, digits);
+
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)q, 0, sizeof (q));
+  R_memset ((POINTER)t1, 0, sizeof (t1));
+  R_memset ((POINTER)t3, 0, sizeof (t3));
+  R_memset ((POINTER)u1, 0, sizeof (u1));
+  R_memset ((POINTER)u3, 0, sizeof (u3));
+  R_memset ((POINTER)v1, 0, sizeof (v1));
+  R_memset ((POINTER)v3, 0, sizeof (v3));
+  R_memset ((POINTER)w, 0, sizeof (w));
+}
+
+/* Computes a = gcd(b, c).
+
+   Lengths: a[digits], b[digits], c[digits].
+   Assumes b > c, digits < MAX_NN_DIGITS.
+ */
+void NN_Gcd (a, b, c, digits)
+NN_DIGIT *a, *b, *c;
+unsigned int digits;
+{
+  NN_DIGIT t[MAX_NN_DIGITS], u[MAX_NN_DIGITS], v[MAX_NN_DIGITS];
+
+  NN_Assign (u, b, digits);
+  NN_Assign (v, c, digits);
+
+  while (! NN_Zero (v, digits)) {
+    NN_Mod (t, u, digits, v, digits);
+    NN_Assign (u, v, digits);
+    NN_Assign (v, t, digits);
+  }
+
+  NN_Assign (a, u, digits);
+
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)t, 0, sizeof (t));
+  R_memset ((POINTER)u, 0, sizeof (u));
+  R_memset ((POINTER)v, 0, sizeof (v));
+}
+
+/* Returns sign of a - b.
+
+   Lengths: a[digits], b[digits].
+ */
+int NN_Cmp (a, b, digits)
+NN_DIGIT *a, *b;
+unsigned int digits;
+{
+  int i;
+  
+  for (i = digits - 1; i >= 0; i--) {
+    if (a[i] > b[i])
+      return (1);
+    if (a[i] < b[i])
+      return (-1);
+  }
+
+  return (0);
+}
+
+/* Returns nonzero iff a is zero.
+
+   Lengths: a[digits].
+ */
+int NN_Zero (a, digits)
+NN_DIGIT *a;
+unsigned int digits;
+{
+  unsigned int i;
+  
+  for (i = 0; i < digits; i++)
+    if (a[i])
+      return (0);
+    
+  return (1);
+}
+
+/* Returns the significant length of a in bits.
+
+   Lengths: a[digits].
+ */
+unsigned int NN_Bits (a, digits)
+NN_DIGIT *a;
+unsigned int digits;
+{
+  if ((digits = NN_Digits (a, digits)) == 0)
+    return (0);
+
+  return ((digits - 1) * NN_DIGIT_BITS + NN_DigitBits (a[digits-1]));
+}
+
+/* Returns the significant length of a in digits.
+
+   Lengths: a[digits].
+ */
+unsigned int NN_Digits (a, digits)
+NN_DIGIT *a;
+unsigned int digits;
+{
+  int i;
+  
+  for (i = digits - 1; i >= 0; i--)
+    if (a[i])
+      break;
+
+  return (i + 1);
+}
+
+/* Computes a = b + c*d, where c is a digit. Returns carry.
+
+   Lengths: a[digits], b[digits], d[digits].
+ */
+static NN_DIGIT NN_AddDigitMult (a, b, c, d, digits)
+NN_DIGIT *a, *b, c, *d;
+unsigned int digits;
+{
+  NN_DIGIT carry, t[2];
+  unsigned int i;
+
+  if (c == 0)
+    return (0);
+
+  carry = 0;
+  for (i = 0; i < digits; i++) {
+    NN_DigitMult (t, c, d[i]);
+    if ((a[i] = b[i] + carry) < carry)
+      carry = 1;
+    else
+      carry = 0;
+    if ((a[i] += t[0]) < t[0])
+      carry++;
+    carry += t[1];
+  }
+  
+  return (carry);
+}
+
+/* Computes a = b - c*d, where c is a digit. Returns borrow.
+
+   Lengths: a[digits], b[digits], d[digits].
+ */
+static NN_DIGIT NN_SubDigitMult (a, b, c, d, digits)
+NN_DIGIT *a, *b, c, *d;
+unsigned int digits;
+{
+  NN_DIGIT borrow, t[2];
+  unsigned int i;
+
+  if (c == 0)
+    return (0);
+
+  borrow = 0;
+  for (i = 0; i < digits; i++) {
+    NN_DigitMult (t, c, d[i]);
+    if ((a[i] = b[i] - borrow) > (MAX_NN_DIGIT - borrow))
+      borrow = 1;
+    else
+      borrow = 0;
+    if ((a[i] -= t[0]) > (MAX_NN_DIGIT - t[0]))
+      borrow++;
+    borrow += t[1];
+  }
+  
+  return (borrow);
+}
+
+/* Returns the significant length of a in bits, where a is a digit.
+ */
+static unsigned int NN_DigitBits (a)
+NN_DIGIT a;
+{
+  unsigned int i;
+  
+  for (i = 0; i < NN_DIGIT_BITS; i++, a >>= 1)
+    if (a == 0)
+      break;
+    
+  return (i);
+}
diff --git a/util/rsaref/nn.h b/util/rsaref/nn.h
new file mode 100644 (file)
index 0000000..4071e7b
--- /dev/null
@@ -0,0 +1,114 @@
+/* NN.H - header file for NN.C
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+/* Type definitions.
+ */
+typedef UINT4 NN_DIGIT;
+typedef UINT2 NN_HALF_DIGIT;
+
+/* Constants.
+
+   Note: MAX_NN_DIGITS is long enough to hold any RSA modulus, plus
+   one more digit as required by R_GeneratePEMKeys (for n and phiN,
+   whose lengths must be even). All natural numbers have at most
+   MAX_NN_DIGITS digits, except for double-length intermediate values
+   in NN_Mult (t), NN_ModMult (t), NN_ModInv (w), and NN_Div (c).
+ */
+/* Length of digit in bits */
+#define NN_DIGIT_BITS 32
+#define NN_HALF_DIGIT_BITS 16
+/* Length of digit in bytes */
+#define NN_DIGIT_LEN (NN_DIGIT_BITS / 8)
+/* Maximum length in digits */
+#define MAX_NN_DIGITS \
+  ((MAX_RSA_MODULUS_LEN + NN_DIGIT_LEN - 1) / NN_DIGIT_LEN + 1)
+/* Maximum digits */
+#define MAX_NN_DIGIT 0xffffffff
+#define MAX_NN_HALF_DIGIT 0xffff
+
+/* Macros.
+ */
+#define LOW_HALF(x) ((x) & MAX_NN_HALF_DIGIT)
+#define HIGH_HALF(x) (((x) >> NN_HALF_DIGIT_BITS) & MAX_NN_HALF_DIGIT)
+#define TO_HIGH_HALF(x) (((NN_DIGIT)(x)) << NN_HALF_DIGIT_BITS)
+#define DIGIT_MSB(x) (unsigned int)(((x) >> (NN_DIGIT_BITS - 1)) & 1)
+#define DIGIT_2MSB(x) (unsigned int)(((x) >> (NN_DIGIT_BITS - 2)) & 3)
+
+/* CONVERSIONS
+   NN_Decode (a, digits, b, len)   Decodes character string b into a.
+   NN_Encode (a, len, b, digits)   Encodes a into character string b.
+
+   ASSIGNMENTS
+   NN_Assign (a, b, digits)        Assigns a = b.
+   NN_ASSIGN_DIGIT (a, b, digits)  Assigns a = b, where b is a digit.
+   NN_AssignZero (a, b, digits)    Assigns a = 0.
+   NN_Assign2Exp (a, b, digits)    Assigns a = 2^b.
+     
+   ARITHMETIC OPERATIONS
+   NN_Add (a, b, c, digits)        Computes a = b + c.
+   NN_Sub (a, b, c, digits)        Computes a = b - c.
+   NN_Mult (a, b, c, digits)       Computes a = b * c.
+   NN_LShift (a, b, c, digits)     Computes a = b * 2^c.
+   NN_RShift (a, b, c, digits)     Computes a = b / 2^c.
+   NN_Div (a, b, c, cDigits, d, dDigits)  Computes a = c div d and b = c mod d.
+
+   NUMBER THEORY
+   NN_Mod (a, b, bDigits, c, cDigits)  Computes a = b mod c.
+   NN_ModMult (a, b, c, d, digits) Computes a = b * c mod d.
+   NN_ModExp (a, b, c, cDigits, d, dDigits)  Computes a = b^c mod d.
+   NN_ModInv (a, b, c, digits)     Computes a = 1/b mod c.
+   NN_Gcd (a, b, c, digits)        Computes a = gcd (b, c).
+
+   OTHER OPERATIONS
+   NN_EVEN (a, digits)             Returns 1 iff a is even.
+   NN_Cmp (a, b, digits)           Returns sign of a - b.
+   NN_EQUAL (a, digits)            Returns 1 iff a = b.
+   NN_Zero (a, digits)             Returns 1 iff a = 0.
+   NN_Digits (a, digits)           Returns significant length of a in digits.
+   NN_Bits (a, digits)             Returns significant length of a in bits.
+ */
+void NN_Decode PROTO_LIST
+  ((NN_DIGIT *, unsigned int, unsigned char *, unsigned int));
+void NN_Encode PROTO_LIST
+  ((unsigned char *, unsigned int, NN_DIGIT *, unsigned int));
+
+void NN_Assign PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, unsigned int));
+void NN_AssignZero PROTO_LIST ((NN_DIGIT *, unsigned int));
+void NN_Assign2Exp PROTO_LIST ((NN_DIGIT *, unsigned int, unsigned int));
+
+NN_DIGIT NN_Add PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
+NN_DIGIT NN_Sub PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
+void NN_Mult PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
+void NN_Div PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *,
+    unsigned int));
+NN_DIGIT NN_LShift PROTO_LIST 
+  ((NN_DIGIT *, NN_DIGIT *, unsigned int, unsigned int));
+NN_DIGIT NN_RShift PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, unsigned int, unsigned int));
+
+void NN_Mod PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *, unsigned int));
+void NN_ModMult PROTO_LIST 
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
+void NN_ModExp PROTO_LIST 
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int, NN_DIGIT *,
+    unsigned int));
+void NN_ModInv PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
+void NN_Gcd PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int));
+
+int NN_Cmp PROTO_LIST ((NN_DIGIT *, NN_DIGIT *, unsigned int));
+int NN_Zero PROTO_LIST ((NN_DIGIT *, unsigned int));
+unsigned int NN_Bits PROTO_LIST ((NN_DIGIT *, unsigned int));
+unsigned int NN_Digits PROTO_LIST ((NN_DIGIT *, unsigned int));
+
+#define NN_ASSIGN_DIGIT(a, b, digits) {NN_AssignZero (a, digits); a[0] = b;}
+#define NN_EQUAL(a, b, digits) (! NN_Cmp (a, b, digits))
+#define NN_EVEN(a, digits) (((digits) == 0) || ! (a[0] & 1))
diff --git a/util/rsaref/prime.c b/util/rsaref/prime.c
new file mode 100644 (file)
index 0000000..de65d85
--- /dev/null
@@ -0,0 +1,143 @@
+/* PRIME.C - primality-testing routines
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "r_random.h"
+#include "nn.h"
+#include "prime.h"
+
+static unsigned int SMALL_PRIMES[] = { 3, 5, 7, 11 };
+#define SMALL_PRIME_COUNT 4
+
+static int ProbablePrime PROTO_LIST ((NN_DIGIT *, unsigned int));
+static int SmallFactor PROTO_LIST ((NN_DIGIT *, unsigned int));
+static int FermatTest PROTO_LIST ((NN_DIGIT *, unsigned int));
+
+/* Generates a probable prime a between b and c such that a-1 is
+   divisible by d.
+
+   Lengths: a[digits], b[digits], c[digits], d[digits].
+   Assumes b < c, digits < MAX_NN_DIGITS.
+   
+   Returns RE_NEED_RANDOM if randomStruct not seeded, RE_DATA if
+   unsuccessful.
+ */
+int GeneratePrime (a, b, c, d, digits, randomStruct)
+NN_DIGIT *a, *b, *c, *d;
+unsigned int digits;
+R_RANDOM_STRUCT *randomStruct;
+{
+  int status;
+  unsigned char block[MAX_NN_DIGITS * NN_DIGIT_LEN];
+  NN_DIGIT t[MAX_NN_DIGITS], u[MAX_NN_DIGITS];
+
+  /* Generate random number between b and c.
+   */
+  if (status = R_GenerateBytes (block, digits * NN_DIGIT_LEN, randomStruct))
+    return (status);
+  NN_Decode (a, digits, block, digits * NN_DIGIT_LEN);
+  NN_Sub (t, c, b, digits);
+  NN_ASSIGN_DIGIT (u, 1, digits);
+  NN_Add (t, t, u, digits);
+  NN_Mod (a, a, digits, t, digits);
+  NN_Add (a, a, b, digits);
+
+  /* Adjust so that a-1 is divisible by d.
+   */
+  NN_Mod (t, a, digits, d, digits);
+  NN_Sub (a, a, t, digits);
+  NN_Add (a, a, u, digits);
+  if (NN_Cmp (a, b, digits) < 0)
+    NN_Add (a, a, d, digits);
+  if (NN_Cmp (a, c, digits) > 0)
+    NN_Sub (a, a, d, digits);
+
+  /* Search to c in steps of d.
+   */
+  NN_Assign (t, c, digits);
+  NN_Sub (t, t, d, digits);
+
+  while (! ProbablePrime (a, digits)) {
+    if (NN_Cmp (a, t, digits) > 0)
+      return (RE_DATA);
+    NN_Add (a, a, d, digits);
+  }
+
+  return (0);
+}
+
+/* Returns nonzero iff a is a probable prime.
+
+   Lengths: a[aDigits].
+   Assumes aDigits < MAX_NN_DIGITS.
+ */
+static int ProbablePrime (a, aDigits)
+NN_DIGIT *a;
+unsigned int aDigits;
+{
+  return (! SmallFactor (a, aDigits) && FermatTest (a, aDigits));
+}
+
+/* Returns nonzero iff a has a prime factor in SMALL_PRIMES.
+
+   Lengths: a[aDigits].
+   Assumes aDigits < MAX_NN_DIGITS.
+ */
+static int SmallFactor (a, aDigits)
+NN_DIGIT *a;
+unsigned int aDigits;
+{
+  int status;
+  NN_DIGIT t[1];
+  unsigned int i;
+  
+  status = 0;
+  
+  for (i = 0; i < SMALL_PRIME_COUNT; i++) {
+    NN_ASSIGN_DIGIT (t, SMALL_PRIMES[i], 1);
+    if ((aDigits == 1) && ! NN_Cmp (a, t, 1))
+      break;
+    NN_Mod (t, a, aDigits, t, 1);
+    if (NN_Zero (t, 1)) {
+      status = 1;
+      break;
+    }
+  }
+  
+  /* Zeroize sensitive information.
+   */
+  i = 0;
+  R_memset ((POINTER)t, 0, sizeof (t));
+
+  return (status);
+}
+
+/* Returns nonzero iff a passes Fermat's test for witness 2.
+   (All primes pass the test, and nearly all composites fail.)
+     
+   Lengths: a[aDigits].
+   Assumes aDigits < MAX_NN_DIGITS.
+ */
+static int FermatTest (a, aDigits)
+NN_DIGIT *a;
+unsigned int aDigits;
+{
+  int status;
+  NN_DIGIT t[MAX_NN_DIGITS], u[MAX_NN_DIGITS];
+  
+  NN_ASSIGN_DIGIT (t, 2, aDigits);
+  NN_ModExp (u, t, a, aDigits, a, aDigits);
+  
+  status = NN_EQUAL (t, u, aDigits);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)u, 0, sizeof (u));
+  
+  return (status);
+}
diff --git a/util/rsaref/prime.h b/util/rsaref/prime.h
new file mode 100644 (file)
index 0000000..73adbe0
--- /dev/null
@@ -0,0 +1,10 @@
+/* PRIME.H - header file for PRIME.C
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+int GeneratePrime PROTO_LIST
+  ((NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, NN_DIGIT *, unsigned int,
+    R_RANDOM_STRUCT *));
diff --git a/util/rsaref/r_dh.c b/util/rsaref/r_dh.c
new file mode 100644 (file)
index 0000000..c7b9a51
--- /dev/null
@@ -0,0 +1,145 @@
+/* R_DH.C - Diffie-Hellman routines for RSAREF
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1993. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "r_random.h"
+#include "nn.h"
+#include "prime.h"
+
+/* Generates Diffie-Hellman parameters.
+ */
+int R_GenerateDHParams (params, primeBits, subPrimeBits, randomStruct)
+R_DH_PARAMS *params;                       /* new Diffie-Hellman parameters */
+unsigned int primeBits;                          /* length of prime in bits */
+unsigned int subPrimeBits;                    /* length of subprime in bits */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  int status;
+  NN_DIGIT g[MAX_NN_DIGITS], p[MAX_NN_DIGITS], q[MAX_NN_DIGITS],
+    t[MAX_NN_DIGITS], u[MAX_NN_DIGITS], v[MAX_NN_DIGITS];
+  unsigned int pDigits;
+
+  pDigits = (primeBits + NN_DIGIT_BITS - 1) / NN_DIGIT_BITS;
+  
+  /* Generate subprime q between 2^(subPrimeBits-1) and
+       2^subPrimeBits-1, searching in steps of 2.
+   */
+  NN_Assign2Exp (t, subPrimeBits-1, pDigits);
+  NN_Assign (u, t, pDigits);
+  NN_ASSIGN_DIGIT (v, 1, pDigits);
+  NN_Sub (v, t, v, pDigits);
+  NN_Add (u, u, v, pDigits);
+  NN_ASSIGN_DIGIT (v, 2, pDigits);
+  if (status = GeneratePrime (q, t, u, v, pDigits, randomStruct))
+    return (status);
+  
+  /* Generate prime p between 2^(primeBits-1) and 2^primeBits-1,
+       searching in steps of 2*q.
+   */
+  NN_Assign2Exp (t, primeBits-1, pDigits);
+  NN_Assign (u, t, pDigits);
+  NN_ASSIGN_DIGIT (v, 1, pDigits);
+  NN_Sub (v, t, v, pDigits);
+  NN_Add (u, u, v, pDigits);
+  NN_LShift (v, q, 1, pDigits);
+  if (status = GeneratePrime (p, t, u, v, pDigits, randomStruct))
+    return (status);
+  
+  /* Generate generator g for subgroup as 2^((p-1)/q) mod p.
+   */
+  NN_ASSIGN_DIGIT (g, 2, pDigits);
+  NN_Div (t, u, p, pDigits, q, pDigits);
+  NN_ModExp (g, g, t, pDigits, p, pDigits);
+
+  params->generatorLen = params->primeLen = DH_PRIME_LEN (primeBits);
+  NN_Encode (params->prime, params->primeLen, p, pDigits);
+  NN_Encode (params->generator, params->generatorLen, g, pDigits);
+
+  return (0);
+}
+
+/* Sets up Diffie-Hellman key agreement. Public value has same length
+   as prime.
+ */
+int R_SetupDHAgreement
+  (publicValue, privateValue, privateValueLen, params, randomStruct)
+unsigned char *publicValue;                             /* new public value */
+unsigned char *privateValue;                           /* new private value */
+unsigned int privateValueLen;                    /* length of private value */
+R_DH_PARAMS *params;                           /* Diffie-Hellman parameters */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  int status;
+  NN_DIGIT g[MAX_NN_DIGITS], p[MAX_NN_DIGITS], x[MAX_NN_DIGITS],
+    y[MAX_NN_DIGITS];
+  unsigned int pDigits, xDigits;
+
+  NN_Decode (p, MAX_NN_DIGITS, params->prime, params->primeLen);
+  pDigits = NN_Digits (p, MAX_NN_DIGITS);
+  NN_Decode (g, pDigits, params->generator, params->generatorLen);
+
+  /* Generate private value.
+   */
+  if (status = R_GenerateBytes (privateValue, privateValueLen, randomStruct))
+    return (status);
+  NN_Decode (x, pDigits, privateValue, privateValueLen);
+  xDigits = NN_Digits (x, pDigits);
+  
+  /* Compute y = g^x mod p.
+   */
+  NN_ModExp (y, g, x, xDigits, p, pDigits);
+
+  NN_Encode (publicValue, params->primeLen, y, pDigits);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)x, 0, sizeof (x));
+
+  return (0);
+}
+
+/* Computes agreed key from the other party's public value, a private
+   value, and Diffie-Hellman parameters. Other public value and
+   agreed-upon key have same length as prime.
+
+   Requires otherPublicValue < prime.
+ */
+int R_ComputeDHAgreedKey
+  (agreedKey, otherPublicValue, privateValue, privateValueLen, params)
+unsigned char *agreedKey;                                 /* new agreed key */
+unsigned char *otherPublicValue;                    /* other's public value */
+unsigned char *privateValue;                               /* private value */
+unsigned int privateValueLen;                    /* length of private value */
+R_DH_PARAMS *params;                           /* Diffie-Hellman parameters */
+{
+  NN_DIGIT p[MAX_NN_DIGITS], x[MAX_NN_DIGITS], y[MAX_NN_DIGITS],
+    z[MAX_NN_DIGITS];
+  unsigned int pDigits, xDigits;
+
+  NN_Decode (p, MAX_NN_DIGITS, params->prime, params->primeLen);
+  pDigits = NN_Digits (p, MAX_NN_DIGITS);
+  NN_Decode (x, pDigits, privateValue, privateValueLen);
+  xDigits = NN_Digits (x, pDigits);
+  NN_Decode (y, pDigits, otherPublicValue, params->primeLen);
+
+  if (NN_Cmp (y, p, pDigits) >= 0)
+    return (RE_DATA);
+  
+  /* Compute z = y^x mod p.
+   */
+  NN_ModExp (z, y, x, xDigits, p, pDigits);
+
+  NN_Encode (agreedKey, params->primeLen, z, pDigits);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)x, 0, sizeof (x));
+  R_memset ((POINTER)z, 0, sizeof (z));
+
+  return (0);
+}
diff --git a/util/rsaref/r_encode.c b/util/rsaref/r_encode.c
new file mode 100644 (file)
index 0000000..04ae61a
--- /dev/null
@@ -0,0 +1,262 @@
+/* R_ENCODE.C - RFC 1113 encoding and decoding routines
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+
+/* RFC 1113 encoding:
+
+   Value Encoding  Value Encoding  Value Encoding  Value Encoding
+       0 A            17 R            34 i            51 z
+       1 B            18 S            35 j            52 0
+       2 C            19 T            36 k            53 1
+       3 D            20 U            37 l            54 2
+       4 E            21 V            38 m            55 3
+       5 F            22 W            39 n            56 4
+       6 G            23 X            40 o            57 5
+       7 H            24 Y            41 p            58 6
+       8 I            25 Z            42 q            59 7
+       9 J            26 a            43 r            60 8
+      10 K            27 b            44 s            61 9
+      11 L            28 c            45 t            62 +
+      12 M            29 d            46 u            63 /
+      13 N            30 e            47 v
+      14 O            31 f            48 w         (pad) =
+      15 P            32 g            49 x
+      16 Q            33 h            50 y
+*/
+#define ENCODING(i) \
+  (unsigned char)(((i) < 26) ? ((i) + 0x41) : \
+                  (((i) < 52) ? ((i) - 26 + 0x61) : \
+                   (((i) < 62) ? ((i) - 52 + 0x30) : \
+                    (((i) == 62) ? 0x2b : 0x2f))))
+#define ENCODING_PAD 0x3d
+
+#define IS_ENCODING(c) \
+  ((((c) >= 0x41) && ((c) <= 0x5a)) || \
+   (((c) >= 0x61) && ((c) <= 0x7a)) || \
+   (((c) >= 0x30) && ((c) <= 0x39)) || \
+   ((c) == 0x2b) || \
+   ((c) == 0x2f))
+
+/* assumes IS_ENCODING (c) == 1 */
+#define DECODING(c) \
+  (((c) == 0x2b) ? 62 : \
+   (((c) == 0x2f) ? 63 : \
+    (((c) <= 0x39) ? ((c) - 0x30 + 52) : \
+     (((c) <= 0x5a) ? ((c) - 0x41) : ((c) - 0x61 + 26)))))
+      
+static void EncodeQuantum PROTO_LIST ((unsigned char [4], unsigned char [3]));
+static int DecodeQuantum PROTO_LIST ((unsigned char [3], unsigned char [4]));
+static void EncodeLastQuantum
+  PROTO_LIST ((unsigned char [4], unsigned char *, unsigned int));
+static int DecodeLastQuantum
+  PROTO_LIST ((unsigned char *, unsigned int *, unsigned char [4]));
+
+/* This always returns 0.  It is an int function for future compatibility.
+ */
+int R_EncodePEMBlock (encodedBlock, encodedBlockLen, block, blockLen)
+unsigned char *encodedBlock;                               /* encoded block */
+unsigned int *encodedBlockLen;                   /* length of encoded block */
+unsigned char *block;                                              /* block */
+unsigned int blockLen;                                   /* length of block */
+{
+  unsigned int i, lastLen;
+  
+  if (blockLen < 1) {
+    *encodedBlockLen = 0;
+    return (0);
+  }
+  
+  for (i = 0; i < (blockLen-1)/3; i++)
+    EncodeQuantum (&encodedBlock[4*i], &block[3*i]);
+  
+  lastLen = blockLen - 3*i;
+  EncodeLastQuantum (&encodedBlock[4*i], &block[3*i], lastLen);
+  *encodedBlockLen = 4*i + 4;
+
+  return (0);
+}
+                    
+int R_DecodePEMBlock (block, blockLen, encodedBlock, encodedBlockLen)
+unsigned char *block;                                              /* block */
+unsigned int *blockLen;                                  /* length of block */
+unsigned char *encodedBlock;                               /* encoded block */
+unsigned int encodedBlockLen;                    /* length of encoded block */
+{
+  int status;
+  unsigned int i, lastLen;
+
+  if (encodedBlockLen % 4)
+    return (RE_ENCODING);
+  
+  if (encodedBlockLen < 1) {
+    *blockLen = 0;
+    return (0);
+  }
+  
+  for (i = 0; i < (encodedBlockLen-1)/4; i++)
+    if (status = DecodeQuantum (&block[3*i], &encodedBlock[4*i]))
+      return (status);
+    
+  if (status = DecodeLastQuantum (&block[3*i], &lastLen, &encodedBlock[4*i]))
+    return (status);
+
+  *blockLen = 3*i + lastLen;
+  return (0);
+}
+
+static void EncodeQuantum (encodedQuantum, quantum)
+unsigned char encodedQuantum[4];
+unsigned char quantum[3];
+{
+  UINT4 temp;
+  unsigned int a, b, c, d;
+  
+  temp = ((UINT4)quantum[0]) << 16;
+  temp |= ((UINT4)quantum[1]) << 8;
+  temp |= (UINT4)quantum[2];
+  
+  a = (unsigned int)((temp >> 18) & 0x3f);
+  b = (unsigned int)((temp >> 12) & 0x3f);
+  c = (unsigned int)((temp >> 6) & 0x3f);
+  d = (unsigned int)(temp & 0x3f);
+
+  encodedQuantum[0] = ENCODING (a);
+  encodedQuantum[1] = ENCODING (b);
+  encodedQuantum[2] = ENCODING (c);
+  encodedQuantum[3] = ENCODING (d);
+
+  /* Zeroize potentially sensitive information.
+   */
+  temp = 0;
+  a = b = c = d = 0;
+}
+
+static int DecodeQuantum (quantum, encodedQuantum)
+unsigned char quantum[3];
+unsigned char encodedQuantum[4];
+{
+  UINT4 temp;
+  unsigned int a, b, c, d;
+  
+  if (! IS_ENCODING (encodedQuantum[0]) ||
+      ! IS_ENCODING (encodedQuantum[1]) ||
+      ! IS_ENCODING (encodedQuantum[2]) ||
+      ! IS_ENCODING (encodedQuantum[3]))
+    return (RE_ENCODING);
+  
+  a = DECODING (encodedQuantum[0]);
+  b = DECODING (encodedQuantum[1]);
+  c = DECODING (encodedQuantum[2]);
+  d = DECODING (encodedQuantum[3]);
+  
+  temp = ((UINT4)a) << 18;
+  temp |= ((UINT4)b) << 12;
+  temp |= ((UINT4)c) << 6;
+  temp |= (UINT4)d;
+
+  quantum[0] = (unsigned char)(temp >> 16);
+  quantum[1] = (unsigned char)(temp >> 8);
+  quantum[2] = (unsigned char)temp;
+  
+  /* Zeroize potentially sensitive information.
+   */
+  temp = 0;
+  a = b = c = d = 0;
+
+  return (0);
+}
+
+static void EncodeLastQuantum (encodedQuantum, quantum, quantumLen)
+unsigned char encodedQuantum[4];
+unsigned char *quantum;
+unsigned int quantumLen;                                       /* 1, 2 or 3 */
+{
+  UINT4 temp;
+  unsigned int a, b, c, d;
+
+  temp = ((UINT4)quantum[0]) << 16;
+  if (quantumLen >= 2)
+    temp |= ((UINT4)quantum[1]) << 8;
+  if (quantumLen == 3)
+    temp |= ((UINT4)quantum[2]);
+  
+  a = (unsigned int)((temp >> 18) & 0x3f);
+  b = (unsigned int)((temp >> 12) & 0x3f);
+  if (quantumLen >= 2)
+    c = (unsigned int)((temp >> 6) & 0x3f);
+  if (quantumLen == 3)
+    d = (unsigned int)(temp & 0x3f);
+
+  encodedQuantum[0] = ENCODING (a);
+  encodedQuantum[1] = ENCODING (b);
+  if (quantumLen >= 2)
+    encodedQuantum[2] = ENCODING (c);
+  else
+    encodedQuantum[2] = ENCODING_PAD;
+  if (quantumLen == 3)
+    encodedQuantum[3] = ENCODING (d);
+  else
+    encodedQuantum[3] = ENCODING_PAD;
+
+  /* Zeroize potentially sensitive information.
+   */
+  temp = 0;
+  a = b = c = d = 0;
+}
+
+static int DecodeLastQuantum (quantum, quantumLen, encodedQuantum)
+unsigned char *quantum;
+unsigned int *quantumLen;                                      /* 1, 2 or 3 */
+unsigned char encodedQuantum[4];
+{
+  UINT4 temp;
+  unsigned int a, b, c, d;
+  
+  if (! IS_ENCODING (encodedQuantum[0]) ||
+      ! IS_ENCODING (encodedQuantum[1]) ||
+      (! IS_ENCODING (encodedQuantum[2]) &&
+       (encodedQuantum[2] != ENCODING_PAD)) ||
+      (! IS_ENCODING (encodedQuantum[3]) &&
+       (encodedQuantum[3] != ENCODING_PAD)))
+    return (RE_ENCODING);
+        
+  if (encodedQuantum[2] == ENCODING_PAD)
+    *quantumLen = 1;
+  else if (encodedQuantum[3] == ENCODING_PAD)
+    *quantumLen = 2;
+  else
+    *quantumLen = 3;
+  
+  a = DECODING (encodedQuantum[0]);
+  b = DECODING (encodedQuantum[1]);
+  if (*quantumLen >= 2)
+    c = DECODING (encodedQuantum[2]);
+  if (*quantumLen == 3)
+    d = DECODING (encodedQuantum[3]);
+  
+  temp = ((UINT4)a) << 18;
+  temp |= ((UINT4)b) << 12;
+  if (*quantumLen >= 2)
+    temp |= ((UINT4)c) << 6;
+  if (*quantumLen == 3)
+    temp |= ((UINT4)d);
+
+  quantum[0] = (unsigned char)(temp >> 16);
+  if (*quantumLen >= 2)
+    quantum[1] = (unsigned char)(temp >> 8);
+  if (*quantumLen == 3)
+    quantum[2] = (unsigned char)temp;
+  
+  /* Zeroize potentially sensitive information.
+   */
+  temp = 0;
+  a = b = c = d = 0;
+  
+  return (0);
+}
diff --git a/util/rsaref/r_enhanc.c b/util/rsaref/r_enhanc.c
new file mode 100644 (file)
index 0000000..6347b4b
--- /dev/null
@@ -0,0 +1,965 @@
+/* R_ENHANC.C - cryptographic enhancements for RSAREF
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "r_random.h"
+#include "rsa.h"
+
+/* DigestInfo encoding is DIGEST_INFO_A, then 2 or 5 (for MD2/MD5),
+   then DIGEST_INFO_B, then 16-byte message digest.
+ */
+
+static unsigned char DIGEST_INFO_A[] = {
+  0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+  0x0d, 0x02
+};
+#define DIGEST_INFO_A_LEN sizeof (DIGEST_INFO_A)
+
+static unsigned char DIGEST_INFO_B[] = { 0x05, 0x00, 0x04, 0x10 };
+#define DIGEST_INFO_B_LEN sizeof (DIGEST_INFO_B)
+
+#define DIGEST_INFO_LEN (DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN + 16)
+
+static unsigned char *PADDING[] = {
+  (unsigned char *)"", (unsigned char *)"\001", (unsigned char *)"\002\002",
+  (unsigned char *)"\003\003\003", (unsigned char *)"\004\004\004\004",
+  (unsigned char *)"\005\005\005\005\005",
+  (unsigned char *)"\006\006\006\006\006\006", 
+  (unsigned char *)"\007\007\007\007\007\007\007",
+  (unsigned char *)"\010\010\010\010\010\010\010\010"
+};
+
+#define MAX_ENCRYPTED_KEY_LEN MAX_RSA_MODULUS_LEN
+
+static void R_EncodeDigestInfo PROTO_LIST
+  ((unsigned char *, int, unsigned char *));
+static void EncryptPEMUpdateFinal PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *,
+    unsigned int));
+static int DecryptPEMUpdateFinal PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *,
+    unsigned int));
+static int CipherInit PROTO_LIST
+  ((R_ENVELOPE_CTX *, int, unsigned char *, unsigned char *, int));
+static void CipherUpdate PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned char *, unsigned int));
+static void CipherRestart PROTO_LIST ((R_ENVELOPE_CTX *));
+
+int R_DigestInit (context, digestAlgorithm)
+R_DIGEST_CTX *context;                                       /* new context */
+int digestAlgorithm;                            /* message-digest algorithm */
+{
+  context->digestAlgorithm = digestAlgorithm;
+
+  switch (digestAlgorithm) {
+  case DA_MD2:
+    MD2Init (&context->context.md2);
+    break;
+
+  case DA_MD5:
+    MD5Init (&context->context.md5);
+    break;
+  
+  default:
+    return (RE_DIGEST_ALGORITHM);
+  }
+
+  return (0);
+}
+
+int R_DigestUpdate (context, partIn, partInLen)
+R_DIGEST_CTX *context;                                           /* context */
+unsigned char *partIn;                                    /* next data part */
+unsigned int partInLen;                         /* length of next data part */
+{
+  if (context->digestAlgorithm == DA_MD2)
+    MD2Update (&context->context.md2, partIn, partInLen);
+  else
+    MD5Update (&context->context.md5, partIn, partInLen);
+  return (0);
+}
+
+int R_DigestFinal (context, digest, digestLen)
+R_DIGEST_CTX *context;                                           /* context */
+unsigned char *digest;                                    /* message digest */
+unsigned int *digestLen;                        /* length of message digest */
+{
+  *digestLen = 16;
+  if (context->digestAlgorithm == DA_MD2)
+    MD2Final (digest, &context->context.md2);
+  else
+    MD5Final (digest, &context->context.md5);
+
+  return (0);
+}
+
+int R_SignInit (context, digestAlgorithm)
+R_SIGNATURE_CTX *context;                                    /* new context */
+int digestAlgorithm;                            /* message-digest algorithm */
+{
+  return (R_DigestInit (&context->digestContext, digestAlgorithm));
+}
+
+int R_SignUpdate (context, partIn, partInLen)
+R_SIGNATURE_CTX *context;                                        /* context */
+unsigned char *partIn;                                    /* next data part */
+unsigned int partInLen;                         /* length of next data part */
+{
+  return (R_DigestUpdate (&context->digestContext, partIn, partInLen));
+}
+
+int R_SignFinal (context, signature, signatureLen, privateKey)
+R_SIGNATURE_CTX *context;                                        /* context */
+unsigned char *signature;                                      /* signature */
+unsigned int *signatureLen;                          /* length of signature */
+R_RSA_PRIVATE_KEY *privateKey;                  /* signer's RSA private key */
+{
+  int status;
+  unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN];
+  unsigned int digestLen;
+
+  do {
+    if ((status = R_DigestFinal (&context->digestContext, digest, &digestLen))
+        != 0)
+      break;
+
+    R_EncodeDigestInfo
+      (digestInfo, context->digestContext.digestAlgorithm, digest);
+    
+    if (RSAPrivateEncrypt
+        (signature, signatureLen, digestInfo, DIGEST_INFO_LEN, privateKey)
+        != 0) {
+      status = RE_PRIVATE_KEY;
+      break;
+    }
+
+    /* Reset for another verification. Assume Init won't fail */
+    R_DigestInit
+      (&context->digestContext, context->digestContext.digestAlgorithm);
+  } while (0);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)digest, 0, sizeof (digest));
+  R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo));
+
+  return (status);
+}
+
+int R_VerifyInit (context, digestAlgorithm)
+R_SIGNATURE_CTX *context;                                    /* new context */
+int digestAlgorithm;                            /* message-digest algorithm */
+{
+  return (R_DigestInit (&context->digestContext, digestAlgorithm));
+}
+
+int R_VerifyUpdate (context, partIn, partInLen)
+R_SIGNATURE_CTX *context;                                        /* context */
+unsigned char *partIn;                                    /* next data part */
+unsigned int partInLen;                         /* length of next data part */
+{
+  return (R_DigestUpdate (&context->digestContext, partIn, partInLen));
+}
+
+int R_VerifyFinal (context, signature, signatureLen, publicKey)
+R_SIGNATURE_CTX *context;                                        /* context */
+unsigned char *signature;                                      /* signature */
+unsigned int signatureLen;                           /* length of signature */
+R_RSA_PUBLIC_KEY *publicKey;                     /* signer's RSA public key */
+{
+  int status;
+  unsigned char digest[MAX_DIGEST_LEN], digestInfo[DIGEST_INFO_LEN],
+    originalDigestInfo[MAX_SIGNATURE_LEN];
+  unsigned int originalDigestInfoLen, digestLen;
+  
+  if (signatureLen > MAX_SIGNATURE_LEN)
+    return (RE_LEN);
+
+  status = 0;
+  do {
+    if ((status = R_DigestFinal (&context->digestContext, digest, &digestLen))
+        != 0)
+      break;
+
+    R_EncodeDigestInfo
+      (digestInfo, context->digestContext.digestAlgorithm, digest);
+    
+    if (RSAPublicDecrypt
+        (originalDigestInfo, &originalDigestInfoLen, signature, signatureLen, 
+         publicKey) != 0) {
+      status = RE_PUBLIC_KEY;
+      break;
+    }
+    
+    if ((originalDigestInfoLen != DIGEST_INFO_LEN) ||
+        (R_memcmp 
+         ((POINTER)originalDigestInfo, (POINTER)digestInfo,
+          DIGEST_INFO_LEN))) {
+      status = RE_SIGNATURE;
+      break;
+    }
+
+    /* Reset for another verification. Assume Init won't fail */
+    R_DigestInit
+      (&context->digestContext, context->digestContext.digestAlgorithm);
+  } while (0);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)digest, 0, sizeof (digest));
+  R_memset ((POINTER)digestInfo, 0, sizeof (digestInfo));
+  R_memset ((POINTER)originalDigestInfo, 0, sizeof (originalDigestInfo));
+
+  return (status);
+}
+
+/* Caller must ASCII recode the encrypted keys if desired.
+ */
+int R_SealInit
+  (context, encryptedKeys, encryptedKeyLens, iv, publicKeyCount, publicKeys,
+   encryptionAlgorithm, randomStruct)
+R_ENVELOPE_CTX *context;                                     /* new context */
+unsigned char **encryptedKeys;                            /* encrypted keys */
+unsigned int *encryptedKeyLens;                /* lengths of encrypted keys */
+unsigned char iv[8];                               /* initialization vector */
+unsigned int publicKeyCount;                       /* number of public keys */
+R_RSA_PUBLIC_KEY **publicKeys;                               /* public keys */
+int encryptionAlgorithm;                       /* data encryption algorithm */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  int status;
+  unsigned char key[24];
+  unsigned int keyLen, i;
+  
+  do {
+    context->encryptionAlgorithm = encryptionAlgorithm;
+    
+    keyLen = (encryptionAlgorithm == EA_DES_CBC) ? 8 : 24;
+    if ((status = R_GenerateBytes (key, keyLen, randomStruct)) != 0)
+      break;
+    if ((status = R_GenerateBytes (iv, 8, randomStruct)) != 0)
+      break;
+
+    if (encryptionAlgorithm == EA_DES_EDE2_CBC)
+      /* Make both E keys the same */
+      R_memcpy ((POINTER)(key + 16), (POINTER)key, 8);
+
+    if ((status = CipherInit (context, encryptionAlgorithm, key, iv, 1)) != 0)
+      break;
+
+    for (i = 0; i < publicKeyCount; ++i) {
+      if (RSAPublicEncrypt
+          (encryptedKeys[i], &encryptedKeyLens[i], key, keyLen,
+           publicKeys[i], randomStruct)) {
+        status = RE_PUBLIC_KEY;
+        break;
+      }
+    }
+    if (status != 0)
+      break;
+
+    context->bufferLen = 0;
+  } while (0);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)key, 0, sizeof (key));
+
+  return (status);
+}
+
+/* Assume partOut buffer is at least partInLen + 7, since this may flush
+     buffered input.
+ */
+int R_SealUpdate (context, partOut, partOutLen, partIn, partInLen)
+R_ENVELOPE_CTX *context;                                         /* context */
+unsigned char *partOut;                         /* next encrypted data part */
+unsigned int *partOutLen;             /* length of next encrypted data part */
+unsigned char *partIn;                                    /* next data part */
+unsigned int partInLen;                         /* length of next data part */
+{
+  unsigned int tempLen;
+
+  tempLen = 8 - context->bufferLen;
+  if (partInLen < tempLen) {
+    /* Just accumulate into buffer.
+     */
+    R_memcpy
+      ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn,
+       partInLen);
+    context->bufferLen += partInLen;
+    *partOutLen = 0;
+    return (0);
+  }
+
+  /* Fill the buffer and encrypt.
+   */
+  R_memcpy
+    ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn,
+     tempLen);
+  CipherUpdate (context, partOut, context->buffer, 8);
+  partIn += tempLen;
+  partInLen -= tempLen;
+  partOut += 8;
+  *partOutLen = 8;
+
+  /* Encrypt as many 8-byte blocks as possible.
+   */
+  tempLen = 8 * (partInLen / 8);
+  CipherUpdate (context, partOut, partIn, tempLen);
+  partIn += tempLen;
+  partInLen -= tempLen;
+  *partOutLen += tempLen;
+
+  /* Length is now less than 8, so copy remainder to buffer.
+   */
+  R_memcpy
+    ((POINTER)context->buffer, (POINTER)partIn,
+     context->bufferLen = partInLen);
+
+  return (0);
+}
+
+/* Assume partOut buffer is at least 8 bytes.
+ */
+int R_SealFinal (context, partOut, partOutLen)
+R_ENVELOPE_CTX *context;                                         /* context */
+unsigned char *partOut;                         /* last encrypted data part */
+unsigned int *partOutLen;             /* length of last encrypted data part */
+{
+  unsigned int padLen;
+
+  /* Pad and encrypt final block.
+   */
+  padLen = 8 - context->bufferLen;
+  R_memset
+    ((POINTER)(context->buffer + context->bufferLen), (int)padLen, padLen);
+  CipherUpdate (context, partOut, context->buffer, 8);
+  *partOutLen = 8;
+
+  /* Restart the context.
+   */
+  CipherRestart (context);
+  context->bufferLen = 0;
+
+  return (0);
+}
+
+/* Assume caller has already ASCII decoded the encryptedKey if necessary.
+ */
+int R_OpenInit
+  (context, encryptionAlgorithm, encryptedKey, encryptedKeyLen, iv, privateKey)
+R_ENVELOPE_CTX *context;                                     /* new context */
+int encryptionAlgorithm;                       /* data encryption algorithm */
+unsigned char *encryptedKey;               /* encrypted data encryption key */
+unsigned int encryptedKeyLen;                    /* length of encrypted key */
+unsigned char iv[8];                               /* initialization vector */
+R_RSA_PRIVATE_KEY *privateKey;               /* recipient's RSA private key */
+{
+  int status;
+  unsigned char key[MAX_ENCRYPTED_KEY_LEN];
+  unsigned int keyLen;
+  
+  if (encryptedKeyLen > MAX_ENCRYPTED_KEY_LEN)
+    return (RE_LEN);
+  
+  do {
+    context->encryptionAlgorithm = encryptionAlgorithm;
+
+    if (RSAPrivateDecrypt
+        (key, &keyLen, encryptedKey, encryptedKeyLen, privateKey)) {
+      status = RE_PRIVATE_KEY;
+      break;
+    }
+
+    if (encryptionAlgorithm == EA_DES_CBC) {    
+      if (keyLen != 8) {
+        status = RE_PRIVATE_KEY;
+        break;
+      }
+    }
+    else {
+      if (keyLen != 24) {
+        status = RE_PRIVATE_KEY;
+        break;
+      }
+    }
+    
+    if ((status = CipherInit (context, encryptionAlgorithm, key, iv, 0)) != 0)
+      break;
+
+    context->bufferLen = 0;
+  } while (0);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)key, 0, sizeof (key));
+
+  return (status);
+}
+
+/* Assume partOut buffer is at least partInLen + 7, since this may flush
+     buffered input. Always leaves at least one byte in buffer.
+ */
+int R_OpenUpdate (context, partOut, partOutLen, partIn, partInLen)
+R_ENVELOPE_CTX *context;                                         /* context */
+unsigned char *partOut;                         /* next recovered data part */
+unsigned int *partOutLen;             /* length of next recovered data part */
+unsigned char *partIn;                          /* next encrypted data part */
+unsigned int partInLen;               /* length of next encrypted data part */
+{
+  unsigned int tempLen;
+
+  tempLen = 8 - context->bufferLen;
+  if (partInLen <= tempLen) {
+    /* Just accumulate into buffer.
+     */
+    R_memcpy
+      ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn,
+       partInLen);
+    context->bufferLen += partInLen;
+    *partOutLen = 0;
+    return (0);
+  }
+
+  /* Fill the buffer and decrypt.  We know that there will be more left
+       in partIn after decrypting the buffer.
+   */
+  R_memcpy
+    ((POINTER)(context->buffer + context->bufferLen), (POINTER)partIn,
+     tempLen);
+  CipherUpdate (context, partOut, context->buffer, 8);
+  partIn += tempLen;
+  partInLen -= tempLen;
+  partOut += 8;
+  *partOutLen = 8;
+
+  /* Decrypt as many 8 byte blocks as possible, leaving at least one byte
+       in partIn.
+   */
+  tempLen = 8 * ((partInLen - 1) / 8);
+  CipherUpdate (context, partOut, partIn, tempLen);
+  partIn += tempLen;
+  partInLen -= tempLen;
+  *partOutLen += tempLen;
+
+  /* Length is between 1 and 8, so copy into buffer.
+   */
+  R_memcpy
+    ((POINTER)context->buffer, (POINTER)partIn,
+     context->bufferLen = partInLen);
+
+  return (0);
+}
+
+/* Assume partOut buffer is at least 7 bytes.
+ */
+int R_OpenFinal (context, partOut, partOutLen)
+R_ENVELOPE_CTX *context;                                         /* context */
+unsigned char *partOut;                         /* last recovered data part */
+unsigned int *partOutLen;             /* length of last recovered data part */
+{
+  int status;
+  unsigned char lastPart[8];
+  unsigned int padLen;
+
+  status = 0;
+  do {
+    if (context->bufferLen == 0)
+      /* There was no input data to decrypt */
+      *partOutLen = 0;
+    else {
+      if (context->bufferLen != 8) {
+        status = RE_KEY;
+        break;
+      }
+
+      /* Decrypt and strip padding from final block which is in buffer.
+       */
+      CipherUpdate (context, lastPart, context->buffer, 8);
+    
+      padLen = lastPart[7];
+      if (padLen == 0 || padLen > 8) {
+        status = RE_KEY;
+        break;
+      }
+      if (R_memcmp 
+          ((POINTER)&lastPart[8 - padLen], PADDING[padLen], padLen) != 0) {
+        status = RE_KEY;
+        break;
+      }
+      
+      R_memcpy ((POINTER)partOut, (POINTER)lastPart, *partOutLen = 8 - padLen);
+    }
+
+    /* Restart the context.
+     */
+    CipherRestart (context);
+    context->bufferLen = 0;
+  } while (0);
+
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)lastPart, 0, sizeof (lastPart));
+
+  return (status);
+}
+
+int R_SignPEMBlock 
+  (encodedContent, encodedContentLen, encodedSignature, encodedSignatureLen,
+   content, contentLen, recode, digestAlgorithm, privateKey)
+unsigned char *encodedContent;                           /* encoded content */
+unsigned int *encodedContentLen;               /* length of encoded content */
+unsigned char *encodedSignature;                       /* encoded signature */
+unsigned int *encodedSignatureLen;           /* length of encoded signature */
+unsigned char *content;                                          /* content */
+unsigned int contentLen;                               /* length of content */
+int recode;                                                /* recoding flag */
+int digestAlgorithm;                            /* message-digest algorithm */
+R_RSA_PRIVATE_KEY *privateKey;                  /* signer's RSA private key */
+{
+  int status;
+  unsigned char signature[MAX_SIGNATURE_LEN];
+  unsigned int signatureLen;
+  
+  if ((status = R_SignBlock
+       (signature, &signatureLen, content, contentLen, digestAlgorithm,
+        privateKey)) != 0)
+    return (status);
+
+  R_EncodePEMBlock 
+    (encodedSignature, encodedSignatureLen, signature, signatureLen);
+
+  if (recode)
+    R_EncodePEMBlock
+    (encodedContent, encodedContentLen, content, contentLen);
+
+  return (0);
+}
+
+int R_SignBlock
+  (signature, signatureLen, block, blockLen, digestAlgorithm, privateKey)
+unsigned char *signature;                                      /* signature */
+unsigned int *signatureLen;                          /* length of signature */
+unsigned char *block;                                              /* block */
+unsigned int blockLen;                                   /* length of block */
+int digestAlgorithm;                            /* message-digest algorithm */
+R_RSA_PRIVATE_KEY *privateKey;                  /* signer's RSA private key */
+{
+  R_SIGNATURE_CTX context;
+  int status;
+
+  do {
+    if ((status = R_SignInit (&context, digestAlgorithm)) != 0)
+      break;
+    if ((status = R_SignUpdate (&context, block, blockLen)) != 0)
+      break;
+    if ((status = R_SignFinal (&context, signature, signatureLen, privateKey))
+        != 0)
+      break;
+  } while (0);
+
+  /* Zeroize sensitive information. */
+  R_memset ((POINTER)&context, 0, sizeof (context));
+
+  return (status);
+}
+
+int R_VerifyPEMSignature 
+  (content, contentLen, encodedContent, encodedContentLen, encodedSignature,
+   encodedSignatureLen, recode, digestAlgorithm, publicKey)
+unsigned char *content;                                          /* content */
+unsigned int *contentLen;                              /* length of content */
+unsigned char *encodedContent;                /* (possibly) encoded content */
+unsigned int encodedContentLen;                /* length of encoded content */
+unsigned char *encodedSignature;                       /* encoded signature */
+unsigned int encodedSignatureLen;            /* length of encoded signature */
+int recode;                                                /* recoding flag */
+int digestAlgorithm;                            /* message-digest algorithm */
+R_RSA_PUBLIC_KEY *publicKey;                     /* signer's RSA public key */
+{
+  unsigned char signature[MAX_SIGNATURE_LEN];
+  unsigned int signatureLen;
+  
+  if (encodedSignatureLen > MAX_PEM_SIGNATURE_LEN)
+    return (RE_SIGNATURE_ENCODING);
+  
+  if (recode) {
+    if (R_DecodePEMBlock
+        (content, contentLen, encodedContent, encodedContentLen))
+      return (RE_CONTENT_ENCODING);
+  }
+  else {
+    content = encodedContent;
+    *contentLen = encodedContentLen;
+  }
+    
+  if (R_DecodePEMBlock
+      (signature, &signatureLen, encodedSignature, encodedSignatureLen))
+    return (RE_SIGNATURE_ENCODING);
+  
+  return (R_VerifyBlockSignature 
+          (content, *contentLen, signature, signatureLen, digestAlgorithm,
+           publicKey));
+}
+
+int R_VerifyBlockSignature 
+  (block, blockLen, signature, signatureLen, digestAlgorithm, publicKey)
+unsigned char *block;                                              /* block */
+unsigned int blockLen;                                   /* length of block */
+unsigned char *signature;                                      /* signature */
+unsigned int signatureLen;                           /* length of signature */
+int digestAlgorithm;                            /* message-digest algorithm */
+R_RSA_PUBLIC_KEY *publicKey;                     /* signer's RSA public key */
+{
+  R_SIGNATURE_CTX context;
+  int status;
+
+  do {
+    if ((status = R_VerifyInit (&context, digestAlgorithm)) != 0)
+      break;
+    if ((status = R_VerifyUpdate (&context, block, blockLen)) != 0)
+      break;
+    if ((status = R_VerifyFinal (&context, signature, signatureLen, publicKey))
+        != 0)
+      break;
+  } while (0);
+
+  /* Zeroize sensitive information. */
+  R_memset ((POINTER)&context, 0, sizeof (context));
+
+  return (status);
+}
+
+int R_SealPEMBlock 
+  (encryptedContent, encryptedContentLen, encryptedKey, encryptedKeyLen,
+   encryptedSignature, encryptedSignatureLen, iv, content, contentLen,
+   digestAlgorithm, publicKey, privateKey, randomStruct)
+unsigned char *encryptedContent;              /* encoded, encrypted content */
+unsigned int *encryptedContentLen;                                /* length */
+unsigned char *encryptedKey;                      /* encoded, encrypted key */
+unsigned int *encryptedKeyLen;                                    /* length */
+unsigned char *encryptedSignature;          /* encoded, encrypted signature */
+unsigned int *encryptedSignatureLen;                              /* length */
+unsigned char iv[8];                           /* DES initialization vector */
+unsigned char *content;                                          /* content */
+unsigned int contentLen;                               /* length of content */
+int digestAlgorithm;                           /* message-digest algorithms */
+R_RSA_PUBLIC_KEY *publicKey;                  /* recipient's RSA public key */
+R_RSA_PRIVATE_KEY *privateKey;                  /* signer's RSA private key */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  R_ENVELOPE_CTX context;
+  R_RSA_PUBLIC_KEY *publicKeys[1];
+  int status;
+  unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN],
+    signature[MAX_SIGNATURE_LEN], *encryptedKeys[1];
+  unsigned int signatureLen, encryptedKeyBlockLen;
+  
+  do {
+    if ((status = R_SignBlock
+         (signature, &signatureLen, content, contentLen, digestAlgorithm,
+          privateKey)) != 0)
+      break;
+
+    publicKeys[0] = publicKey;
+    encryptedKeys[0] = encryptedKeyBlock;
+    if ((status = R_SealInit
+         (&context, encryptedKeys, &encryptedKeyBlockLen, iv, 1, publicKeys,
+          EA_DES_CBC, randomStruct)) != 0)
+      break;
+
+    R_EncodePEMBlock 
+      (encryptedKey, encryptedKeyLen, encryptedKeyBlock,
+       encryptedKeyBlockLen);
+
+    EncryptPEMUpdateFinal
+      (&context, encryptedContent, encryptedContentLen, content,
+       contentLen);
+    
+    EncryptPEMUpdateFinal
+      (&context, encryptedSignature, encryptedSignatureLen, signature,
+       signatureLen);
+  } while (0);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)&context, 0, sizeof (context));
+  R_memset ((POINTER)signature, 0, sizeof (signature));
+
+  return (status);
+}
+
+int R_OpenPEMBlock
+  (content, contentLen, encryptedContent, encryptedContentLen, encryptedKey,
+   encryptedKeyLen, encryptedSignature, encryptedSignatureLen,
+   iv, digestAlgorithm, privateKey, publicKey)
+unsigned char *content;                                          /* content */
+unsigned int *contentLen;                              /* length of content */
+unsigned char *encryptedContent;              /* encoded, encrypted content */
+unsigned int encryptedContentLen;                                 /* length */
+unsigned char *encryptedKey;                      /* encoded, encrypted key */
+unsigned int encryptedKeyLen;                                     /* length */
+unsigned char *encryptedSignature;          /* encoded, encrypted signature */
+unsigned int encryptedSignatureLen;                               /* length */
+unsigned char iv[8];                           /* DES initialization vector */
+int digestAlgorithm;                           /* message-digest algorithms */
+R_RSA_PRIVATE_KEY *privateKey;               /* recipient's RSA private key */
+R_RSA_PUBLIC_KEY *publicKey;                     /* signer's RSA public key */
+{
+  R_ENVELOPE_CTX context;
+  int status;
+  unsigned char encryptedKeyBlock[MAX_ENCRYPTED_KEY_LEN],
+    signature[MAX_SIGNATURE_LEN];
+  unsigned int encryptedKeyBlockLen, signatureLen;
+  
+  if (encryptedKeyLen > MAX_PEM_ENCRYPTED_KEY_LEN)
+    return (RE_KEY_ENCODING);
+  
+  if (encryptedSignatureLen > MAX_PEM_ENCRYPTED_SIGNATURE_LEN)
+    return (RE_SIGNATURE_ENCODING);
+  
+  do {
+    if (R_DecodePEMBlock 
+        (encryptedKeyBlock, &encryptedKeyBlockLen, encryptedKey,
+         encryptedKeyLen) != 0) {
+      status = RE_KEY_ENCODING;
+      break;
+    }
+
+    if ((status = R_OpenInit
+         (&context, EA_DES_CBC, encryptedKeyBlock, encryptedKeyBlockLen,
+          iv, privateKey)) != 0)
+      break;
+
+    if ((status = DecryptPEMUpdateFinal
+         (&context, content, contentLen, encryptedContent,
+          encryptedContentLen)) != 0) {
+      if ((status == RE_LEN || status == RE_ENCODING))
+        status = RE_CONTENT_ENCODING;
+      else
+        status = RE_KEY;
+      break;
+    }
+    
+    if (status = DecryptPEMUpdateFinal
+        (&context, signature, &signatureLen, encryptedSignature,
+         encryptedSignatureLen)) {
+      if ((status == RE_LEN || status == RE_ENCODING))
+        status = RE_SIGNATURE_ENCODING;
+      else
+        status = RE_KEY;
+      break;
+    }
+
+    if ((status = R_VerifyBlockSignature
+         (content, *contentLen, signature, signatureLen, digestAlgorithm,
+          publicKey)) != 0)
+      break;
+  } while (0);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)&context, 0, sizeof (context));
+  R_memset ((POINTER)signature, 0, sizeof (signature));
+
+  return (status);
+}
+
+int R_DigestBlock (digest, digestLen, block, blockLen, digestAlgorithm)
+unsigned char *digest;                                    /* message digest */
+unsigned int *digestLen;                        /* length of message digest */
+unsigned char *block;                                              /* block */
+unsigned int blockLen;                                   /* length of block */
+int digestAlgorithm;                            /* message-digest algorithm */
+{
+  R_DIGEST_CTX context;
+  int status;
+
+  do {
+    if ((status = R_DigestInit (&context, digestAlgorithm)) != 0)
+      break;
+    if ((status = R_DigestUpdate (&context, block, blockLen)) != 0)
+      break;
+    if ((status = R_DigestFinal (&context, digest, digestLen)) != 0)
+      break;
+  } while (0);
+
+  /* Zeroize sensitive information. */
+  R_memset ((POINTER)&context, 0, sizeof (context));
+
+  return (status);
+}
+
+/* Assumes digestAlgorithm is DA_MD2 or DA_MD5 and digest length is 16.
+ */
+static void R_EncodeDigestInfo (digestInfo, digestAlgorithm, digest)
+unsigned char *digestInfo;                           /* DigestInfo encoding */
+int digestAlgorithm;                            /* message-digest algorithm */
+unsigned char *digest;                                    /* message digest */
+{
+  R_memcpy 
+    ((POINTER)digestInfo, (POINTER)DIGEST_INFO_A, DIGEST_INFO_A_LEN);
+  
+  digestInfo[DIGEST_INFO_A_LEN] =
+    (digestAlgorithm == DA_MD2) ? (unsigned char)2 : (unsigned char)5;
+
+  R_memcpy 
+    ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1], (POINTER)DIGEST_INFO_B,
+     DIGEST_INFO_B_LEN);
+  
+  R_memcpy 
+    ((POINTER)&digestInfo[DIGEST_INFO_A_LEN + 1 + DIGEST_INFO_B_LEN],
+     (POINTER)digest, 16);
+}
+
+/* Call SealUpdate and SealFinal on the input and ASCII recode.
+ */
+static void EncryptPEMUpdateFinal
+  (context, output, outputLen, input, inputLen)
+R_ENVELOPE_CTX *context;
+unsigned char *output;                          /* encrypted, encoded block */
+unsigned int *outputLen;                                /* length of output */
+unsigned char *input;                                   /* block to encrypt */
+unsigned int inputLen;                                            /* length */
+{
+  unsigned char encryptedPart[24];
+  unsigned int i, lastPartLen, tempLen, len;
+
+  /* Choose a buffer size of 24 bytes to hold the temporary encrypted output
+       which will be encoded.
+     Encrypt and encode as many 24-byte blocks as possible.
+   */
+  for (i = 0; i < inputLen / 24; ++i) {
+    /* Assume part out length will equal part in length since it is
+         a multiple of 8.  Also assume no error output. */
+    R_SealUpdate (context, encryptedPart, &tempLen, &input[24*i], 24);
+
+    /* len is always 32 */
+    R_EncodePEMBlock (&output[32*i], &tempLen, encryptedPart, 24);
+  }
+  
+  /* Encrypt the last part into encryptedPart.
+   */  
+  R_SealUpdate
+    (context, encryptedPart, &lastPartLen, &input[24*i], inputLen - 24*i);
+  R_SealFinal (context, encryptedPart + lastPartLen, &len);
+  lastPartLen += len;
+
+  R_EncodePEMBlock (&output[32*i], &len, encryptedPart, lastPartLen);
+  *outputLen = 32*i + len;
+
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart));
+}
+
+static int DecryptPEMUpdateFinal (context, output, outputLen, input, inputLen)
+R_ENVELOPE_CTX *context;
+unsigned char *output;                          /* decoded, decrypted block */
+unsigned int *outputLen;                                /* length of output */
+unsigned char *input;                           /* encrypted, encoded block */
+unsigned int inputLen;                                            /* length */
+{
+  int status;
+  unsigned char encryptedPart[24];
+  unsigned int i, len;
+  
+  do {
+    /* Choose a buffer size of 24 bytes to hold the temporary decoded output
+         which will be decrypted.
+       Decode and decrypt as many 32-byte input blocks as possible.
+     */
+    *outputLen = 0;
+    for (i = 0; i < inputLen/32; i++) {
+      /* len is always 24 */
+      if ((status = R_DecodePEMBlock
+           (encryptedPart, &len, &input[32*i], 32)) != 0)
+        break;
+
+      /* Excpect no error return */
+      R_OpenUpdate (context, output, &len, encryptedPart, 24);
+      output += len;
+      *outputLen += len;
+    }
+    if (status)
+      break;
+
+    /* Decode the last part */  
+    if ((status = R_DecodePEMBlock
+         (encryptedPart, &len, &input[32*i], inputLen - 32*i)) != 0)
+      break;
+
+    /* Decrypt the last part.
+     */
+    R_OpenUpdate (context, output, &len, encryptedPart, len);
+    output += len;
+    *outputLen += len;
+    if ((status = R_OpenFinal (context, output, &len)) != 0)
+      break;
+    *outputLen += len;
+  } while (0);
+
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)&context, 0, sizeof (context));
+  R_memset ((POINTER)encryptedPart, 0, sizeof (encryptedPart));
+
+  return (status);
+}
+
+static int CipherInit (context, encryptionAlgorithm, key, iv, encrypt)
+R_ENVELOPE_CTX *context;
+int encryptionAlgorithm;
+unsigned char *key;                                              /* DES key */
+unsigned char *iv;                             /* DES initialization vector */
+int encrypt;                     /* encrypt flag (1 = encrypt, 0 = decrypt) */
+{
+  switch (encryptionAlgorithm) {
+  case EA_DES_CBC:
+    DES_CBCInit (&context->cipherContext.des, key, iv, encrypt);
+    return (0);
+  case EA_DESX_CBC:
+    DESX_CBCInit (&context->cipherContext.desx, key, iv, encrypt);
+    return (0);
+  case EA_DES_EDE2_CBC:
+  case EA_DES_EDE3_CBC:
+    DES3_CBCInit (&context->cipherContext.des3, key, iv, encrypt);
+    return (0);
+
+  default:
+    return (RE_ENCRYPTION_ALGORITHM);
+  }
+}
+
+/* Assume len is a multiple of 8.
+ */
+static void CipherUpdate (context, output, input, len)
+R_ENVELOPE_CTX *context;
+unsigned char *output;                                      /* output block */
+unsigned char *input;                                        /* input block */
+unsigned int len;                      /* length of input and output blocks */
+{
+  if (context->encryptionAlgorithm == EA_DES_CBC)
+    DES_CBCUpdate (&context->cipherContext.des, output, input, len);
+  else if (context->encryptionAlgorithm == EA_DESX_CBC)
+    DESX_CBCUpdate (&context->cipherContext.desx, output, input, len);
+  else
+    DES3_CBCUpdate (&context->cipherContext.des3, output, input, len);
+}
+
+static void CipherRestart (context)
+R_ENVELOPE_CTX *context;
+{
+  if (context->encryptionAlgorithm == EA_DES_CBC)
+    DES_CBCRestart (&context->cipherContext.des);
+  else if (context->encryptionAlgorithm == EA_DESX_CBC)
+    DESX_CBCRestart (&context->cipherContext.desx);
+  else
+    DES3_CBCRestart (&context->cipherContext.des3);
+}
diff --git a/util/rsaref/r_keygen.c b/util/rsaref/r_keygen.c
new file mode 100644 (file)
index 0000000..30a6099
--- /dev/null
@@ -0,0 +1,182 @@
+/* R_KEYGEN.C - key-pair generation for RSAREF
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "r_random.h"
+#include "nn.h"
+#include "prime.h"
+
+static int RSAFilter PROTO_LIST
+  ((NN_DIGIT *, unsigned int, NN_DIGIT *, unsigned int));
+static int RelativelyPrime PROTO_LIST
+  ((NN_DIGIT *, unsigned int, NN_DIGIT *, unsigned int));
+
+/* Generates an RSA key pair with a given length and public exponent.
+ */
+int R_GeneratePEMKeys (publicKey, privateKey, protoKey, randomStruct)
+R_RSA_PUBLIC_KEY *publicKey;                          /* new RSA public key */
+R_RSA_PRIVATE_KEY *privateKey;                       /* new RSA private key */
+R_RSA_PROTO_KEY *protoKey;                             /* RSA prototype key */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  NN_DIGIT d[MAX_NN_DIGITS], dP[MAX_NN_DIGITS], dQ[MAX_NN_DIGITS],
+    e[MAX_NN_DIGITS], n[MAX_NN_DIGITS], p[MAX_NN_DIGITS], phiN[MAX_NN_DIGITS],
+    pMinus1[MAX_NN_DIGITS], q[MAX_NN_DIGITS], qInv[MAX_NN_DIGITS],
+    qMinus1[MAX_NN_DIGITS], t[MAX_NN_DIGITS], u[MAX_NN_DIGITS],
+    v[MAX_NN_DIGITS];
+  int status;
+  unsigned int nDigits, pBits, pDigits, qBits;
+  
+  if ((protoKey->bits < MIN_RSA_MODULUS_BITS) || 
+      (protoKey->bits > MAX_RSA_MODULUS_BITS))
+    return (RE_MODULUS_LEN);
+  nDigits = (protoKey->bits + NN_DIGIT_BITS - 1) / NN_DIGIT_BITS;
+  pDigits = (nDigits + 1) / 2;
+  pBits = (protoKey->bits + 1) / 2;
+  qBits = protoKey->bits - pBits;
+
+  /* NOTE: for 65537, this assumes NN_DIGIT is at least 17 bits. */
+  NN_ASSIGN_DIGIT
+    (e, protoKey->useFermat4 ? (NN_DIGIT)65537 : (NN_DIGIT)3, nDigits);
+
+  /* Generate prime p between 3*2^(pBits-2) and 2^pBits-1, searching
+       in steps of 2, until one satisfies gcd (p-1, e) = 1.
+   */
+  NN_Assign2Exp (t, pBits-1, pDigits);
+  NN_Assign2Exp (u, pBits-2, pDigits);
+  NN_Add (t, t, u, pDigits);
+  NN_ASSIGN_DIGIT (v, 1, pDigits);
+  NN_Sub (v, t, v, pDigits);
+  NN_Add (u, u, v, pDigits);
+  NN_ASSIGN_DIGIT (v, 2, pDigits);
+  do {
+    if (status = GeneratePrime (p, t, u, v, pDigits, randomStruct))
+      return (status);
+  }
+  while (! RSAFilter (p, pDigits, e, 1));
+  
+  /* Generate prime q between 3*2^(qBits-2) and 2^qBits-1, searching
+       in steps of 2, until one satisfies gcd (q-1, e) = 1.
+   */
+  NN_Assign2Exp (t, qBits-1, pDigits);
+  NN_Assign2Exp (u, qBits-2, pDigits);
+  NN_Add (t, t, u, pDigits);
+  NN_ASSIGN_DIGIT (v, 1, pDigits);
+  NN_Sub (v, t, v, pDigits);
+  NN_Add (u, u, v, pDigits);
+  NN_ASSIGN_DIGIT (v, 2, pDigits);
+  do {
+    if (status = GeneratePrime (q, t, u, v, pDigits, randomStruct))
+      return (status);
+  }
+  while (! RSAFilter (q, pDigits, e, 1));
+  
+  /* Sort so that p > q. (p = q case is extremely unlikely.)
+   */
+  if (NN_Cmp (p, q, pDigits) < 0) {
+    NN_Assign (t, p, pDigits);
+    NN_Assign (p, q, pDigits);
+    NN_Assign (q, t, pDigits);
+  }
+
+  /* Compute n = pq, qInv = q^{-1} mod p, d = e^{-1} mod (p-1)(q-1),
+     dP = d mod p-1, dQ = d mod q-1.
+   */
+  NN_Mult (n, p, q, pDigits);
+  NN_ModInv (qInv, q, p, pDigits);
+  
+  NN_ASSIGN_DIGIT (t, 1, pDigits);
+  NN_Sub (pMinus1, p, t, pDigits);
+  NN_Sub (qMinus1, q, t, pDigits);
+  NN_Mult (phiN, pMinus1, qMinus1, pDigits);
+
+  NN_ModInv (d, e, phiN, nDigits);
+  NN_Mod (dP, d, nDigits, pMinus1, pDigits);
+  NN_Mod (dQ, d, nDigits, qMinus1, pDigits);
+  
+  publicKey->bits = privateKey->bits = protoKey->bits;
+  NN_Encode (publicKey->modulus, MAX_RSA_MODULUS_LEN, n, nDigits);
+  NN_Encode (publicKey->exponent, MAX_RSA_MODULUS_LEN, e, 1);
+  R_memcpy 
+    ((POINTER)privateKey->modulus, (POINTER)publicKey->modulus,
+     MAX_RSA_MODULUS_LEN);
+  R_memcpy
+    ((POINTER)privateKey->publicExponent, (POINTER)publicKey->exponent,
+     MAX_RSA_MODULUS_LEN);
+  NN_Encode (privateKey->exponent, MAX_RSA_MODULUS_LEN, d, nDigits);
+  NN_Encode (privateKey->prime[0], MAX_RSA_PRIME_LEN, p, pDigits);
+  NN_Encode (privateKey->prime[1], MAX_RSA_PRIME_LEN, q, pDigits);
+  NN_Encode (privateKey->primeExponent[0], MAX_RSA_PRIME_LEN, dP, pDigits);
+  NN_Encode (privateKey->primeExponent[1], MAX_RSA_PRIME_LEN, dQ, pDigits);
+  NN_Encode (privateKey->coefficient, MAX_RSA_PRIME_LEN, qInv, pDigits);
+   
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)d, 0, sizeof (d));
+  R_memset ((POINTER)dP, 0, sizeof (dP));
+  R_memset ((POINTER)dQ, 0, sizeof (dQ));
+  R_memset ((POINTER)p, 0, sizeof (p));
+  R_memset ((POINTER)phiN, 0, sizeof (phiN));
+  R_memset ((POINTER)pMinus1, 0, sizeof (pMinus1));
+  R_memset ((POINTER)q, 0, sizeof (q));
+  R_memset ((POINTER)qInv, 0, sizeof (qInv));
+  R_memset ((POINTER)qMinus1, 0, sizeof (qMinus1));
+  R_memset ((POINTER)t, 0, sizeof (t));
+  
+  return (0);
+}
+
+/* Returns nonzero iff GCD (a-1, b) = 1.
+
+   Lengths: a[aDigits], b[bDigits].
+   Assumes aDigits < MAX_NN_DIGITS, bDigits < MAX_NN_DIGITS.
+ */
+static int RSAFilter (a, aDigits, b, bDigits)
+NN_DIGIT *a, *b;
+unsigned int aDigits, bDigits;
+{
+  int status;
+  NN_DIGIT aMinus1[MAX_NN_DIGITS], t[MAX_NN_DIGITS];
+  
+  NN_ASSIGN_DIGIT (t, 1, aDigits);
+  NN_Sub (aMinus1, a, t, aDigits);
+  
+  status = RelativelyPrime (aMinus1, aDigits, b, bDigits);
+
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)aMinus1, 0, sizeof (aMinus1));
+  
+  return (status);
+}
+
+/* Returns nonzero iff a and b are relatively prime.
+
+   Lengths: a[aDigits], b[bDigits].
+   Assumes aDigits >= bDigits, aDigits < MAX_NN_DIGITS.
+ */
+static int RelativelyPrime (a, aDigits, b, bDigits)
+NN_DIGIT *a, *b;
+unsigned int aDigits, bDigits;
+{
+  int status;
+  NN_DIGIT t[MAX_NN_DIGITS], u[MAX_NN_DIGITS];
+  
+  NN_AssignZero (t, aDigits);
+  NN_Assign (t, b, bDigits);
+  NN_Gcd (t, a, t, aDigits);
+  NN_ASSIGN_DIGIT (u, 1, aDigits);
+
+  status = NN_EQUAL (t, u, aDigits);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)t, 0, sizeof (t));
+  
+  return (status);
+}
diff --git a/util/rsaref/r_random.c b/util/rsaref/r_random.c
new file mode 100644 (file)
index 0000000..11ecf10
--- /dev/null
@@ -0,0 +1,111 @@
+/* R_RANDOM.C - random objects for RSAREF
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "r_random.h"
+#include "md5.h"
+
+#define RANDOM_BYTES_NEEDED 256
+
+int R_RandomInit (randomStruct)
+R_RANDOM_STRUCT *randomStruct;                      /* new random structure */
+{
+  randomStruct->bytesNeeded = RANDOM_BYTES_NEEDED;
+  R_memset ((POINTER)randomStruct->state, 0, sizeof (randomStruct->state));
+  randomStruct->outputAvailable = 0;
+  
+  return (0);
+}
+
+int R_RandomUpdate (randomStruct, block, blockLen)
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+unsigned char *block;                          /* block of values to mix in */
+unsigned int blockLen;                                   /* length of block */
+{
+  MD5_CTX context;
+  unsigned char digest[16];
+  unsigned int i, x;
+  
+  MD5Init (&context);
+  MD5Update (&context, block, blockLen);
+  MD5Final (digest, &context);
+
+  /* add digest to state */
+  x = 0;
+  for (i = 0; i < 16; i++) {
+    x += randomStruct->state[15-i] + digest[15-i];
+    randomStruct->state[15-i] = (unsigned char)x;
+    x >>= 8;
+  }
+  
+  if (randomStruct->bytesNeeded < blockLen)
+    randomStruct->bytesNeeded = 0;
+  else
+    randomStruct->bytesNeeded -= blockLen;
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)digest, 0, sizeof (digest));
+  x = 0;
+  
+  return (0);
+}
+
+int R_GetRandomBytesNeeded (bytesNeeded, randomStruct)
+unsigned int *bytesNeeded;                 /* number of mix-in bytes needed */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  *bytesNeeded = randomStruct->bytesNeeded;
+  
+  return (0);
+}
+
+int R_GenerateBytes (block, blockLen, randomStruct)
+unsigned char *block;                                              /* block */
+unsigned int blockLen;                                   /* length of block */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  MD5_CTX context;
+  unsigned int available, i;
+  
+  if (randomStruct->bytesNeeded)
+    return (RE_NEED_RANDOM);
+  
+  available = randomStruct->outputAvailable;
+  
+  while (blockLen > available) {
+    R_memcpy
+      ((POINTER)block, (POINTER)&randomStruct->output[16-available],
+       available);
+    block += available;
+    blockLen -= available;
+
+    /* generate new output */
+    MD5Init (&context);
+    MD5Update (&context, randomStruct->state, 16);
+    MD5Final (randomStruct->output, &context);
+    available = 16;
+
+    /* increment state */
+    for (i = 0; i < 16; i++)
+      if (randomStruct->state[15-i]++)
+        break;
+  }
+
+  R_memcpy 
+    ((POINTER)block, (POINTER)&randomStruct->output[16-available], blockLen);
+  randomStruct->outputAvailable = available - blockLen;
+
+  return (0);
+}
+
+void R_RandomFinal (randomStruct)
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  R_memset ((POINTER)randomStruct, 0, sizeof (*randomStruct));
+}
diff --git a/util/rsaref/r_random.h b/util/rsaref/r_random.h
new file mode 100644 (file)
index 0000000..94845dd
--- /dev/null
@@ -0,0 +1,9 @@
+/* R_RANDOM.H - header file for R_RANDOM.C
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+int R_GenerateBytes PROTO_LIST
+  ((unsigned char *, unsigned int, R_RANDOM_STRUCT *));
diff --git a/util/rsaref/r_stdlib.c b/util/rsaref/r_stdlib.c
new file mode 100644 (file)
index 0000000..5977f23
--- /dev/null
@@ -0,0 +1,39 @@
+/* R_STDLIB.C - platform-specific C library routines for RSAREF
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include <string.h>
+#include "global.h"
+#include "rsaref.h"
+
+void R_memset (output, value, len)
+POINTER output;                                             /* output block */
+int value;                                                         /* value */
+unsigned int len;                                        /* length of block */
+{
+  if (len)
+    memset (output, value, len);
+}
+
+void R_memcpy (output, input, len)
+POINTER output;                                             /* output block */
+POINTER input;                                               /* input block */
+unsigned int len;                                       /* length of blocks */
+{
+  if (len)
+    memcpy (output, input, len);
+}
+
+int R_memcmp (firstBlock, secondBlock, len)
+POINTER firstBlock;                                          /* first block */
+POINTER secondBlock;                                        /* second block */
+unsigned int len;                                       /* length of blocks */
+{
+  if (len)
+    return (memcmp (firstBlock, secondBlock, len));
+  else
+    return (0);
+}
diff --git a/util/rsaref/rsa.c b/util/rsaref/rsa.c
new file mode 100644 (file)
index 0000000..0e57e17
--- /dev/null
@@ -0,0 +1,324 @@
+/* RSA.C - RSA routines for RSAREF
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#include "global.h"
+#include "rsaref.h"
+#include "r_random.h"
+#include "rsa.h"
+#include "nn.h"
+
+static int RSAPublicBlock PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    R_RSA_PUBLIC_KEY *));
+static int RSAPrivateBlock PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    R_RSA_PRIVATE_KEY *));
+
+/* RSA public-key encryption, according to PKCS #1.
+ */
+int RSAPublicEncrypt
+  (output, outputLen, input, inputLen, publicKey, randomStruct)
+unsigned char *output;                                      /* output block */
+unsigned int *outputLen;                          /* length of output block */
+unsigned char *input;                                        /* input block */
+unsigned int inputLen;                             /* length of input block */
+R_RSA_PUBLIC_KEY *publicKey;                              /* RSA public key */
+R_RANDOM_STRUCT *randomStruct;                          /* random structure */
+{
+  int status;
+  unsigned char byte, pkcsBlock[MAX_RSA_MODULUS_LEN];
+  unsigned int i, modulusLen;
+  
+  modulusLen = (publicKey->bits + 7) / 8;
+  if (inputLen + 11 > modulusLen)
+    return (RE_LEN);
+  
+  pkcsBlock[0] = 0;
+  /* block type 2 */
+  pkcsBlock[1] = 2;
+
+  for (i = 2; i < modulusLen - inputLen - 1; i++) {
+    /* Find nonzero random byte.
+     */
+    do {
+      R_GenerateBytes (&byte, 1, randomStruct);
+    } while (byte == 0);
+    pkcsBlock[i] = byte;
+  }
+  /* separator */
+  pkcsBlock[i++] = 0;
+  
+  R_memcpy ((POINTER)&pkcsBlock[i], (POINTER)input, inputLen);
+  
+  status = RSAPublicBlock
+    (output, outputLen, pkcsBlock, modulusLen, publicKey);
+  
+  /* Zeroize sensitive information.
+   */
+  byte = 0;
+  R_memset ((POINTER)pkcsBlock, 0, sizeof (pkcsBlock));
+  
+  return (status);
+}
+
+/* RSA public-key decryption, according to PKCS #1.
+ */
+int RSAPublicDecrypt (output, outputLen, input, inputLen, publicKey)
+unsigned char *output;                                      /* output block */
+unsigned int *outputLen;                          /* length of output block */
+unsigned char *input;                                        /* input block */
+unsigned int inputLen;                             /* length of input block */
+R_RSA_PUBLIC_KEY *publicKey;                              /* RSA public key */
+{
+  int status;
+  unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
+  unsigned int i, modulusLen, pkcsBlockLen;
+  
+  modulusLen = (publicKey->bits + 7) / 8;
+  if (inputLen > modulusLen)
+    return (RE_LEN);
+  
+  if (status = RSAPublicBlock
+      (pkcsBlock, &pkcsBlockLen, input, inputLen, publicKey))
+    return (status);
+  
+  if (pkcsBlockLen != modulusLen)
+    return (RE_LEN);
+  
+  /* Require block type 1.
+   */
+  if ((pkcsBlock[0] != 0) || (pkcsBlock[1] != 1))
+   return (RE_DATA);
+
+  for (i = 2; i < modulusLen-1; i++)
+    if (pkcsBlock[i] != 0xff)
+      break;
+    
+  /* separator */
+  if (pkcsBlock[i++] != 0)
+    return (RE_DATA);
+  
+  *outputLen = modulusLen - i;
+  
+  if (*outputLen + 11 > modulusLen)
+    return (RE_DATA);
+
+  R_memcpy ((POINTER)output, (POINTER)&pkcsBlock[i], *outputLen);
+  
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)pkcsBlock, 0, sizeof (pkcsBlock));
+  
+  return (0);
+}
+
+/* RSA private-key encryption, according to PKCS #1.
+ */
+int RSAPrivateEncrypt (output, outputLen, input, inputLen, privateKey)
+unsigned char *output;                                      /* output block */
+unsigned int *outputLen;                          /* length of output block */
+unsigned char *input;                                        /* input block */
+unsigned int inputLen;                             /* length of input block */
+R_RSA_PRIVATE_KEY *privateKey;                           /* RSA private key */
+{
+  int status;
+  unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
+  unsigned int i, modulusLen;
+  
+  modulusLen = (privateKey->bits + 7) / 8;
+  if (inputLen + 11 > modulusLen)
+    return (RE_LEN);
+  
+  pkcsBlock[0] = 0;
+  /* block type 1 */
+  pkcsBlock[1] = 1;
+
+  for (i = 2; i < modulusLen - inputLen - 1; i++)
+    pkcsBlock[i] = 0xff;
+
+  /* separator */
+  pkcsBlock[i++] = 0;
+  
+  R_memcpy ((POINTER)&pkcsBlock[i], (POINTER)input, inputLen);
+  
+  status = RSAPrivateBlock
+    (output, outputLen, pkcsBlock, modulusLen, privateKey);
+
+  /* Zeroize potentially sensitive information.
+   */
+  R_memset ((POINTER)pkcsBlock, 0, sizeof (pkcsBlock));
+
+  return (status);
+}
+
+/* RSA private-key decryption, according to PKCS #1.
+ */
+int RSAPrivateDecrypt (output, outputLen, input, inputLen, privateKey)
+unsigned char *output;                                      /* output block */
+unsigned int *outputLen;                          /* length of output block */
+unsigned char *input;                                        /* input block */
+unsigned int inputLen;                             /* length of input block */
+R_RSA_PRIVATE_KEY *privateKey;                           /* RSA private key */
+{
+  int status;
+  unsigned char pkcsBlock[MAX_RSA_MODULUS_LEN];
+  unsigned int i, modulusLen, pkcsBlockLen;
+  
+  modulusLen = (privateKey->bits + 7) / 8;
+  if (inputLen > modulusLen)
+    return (RE_LEN);
+  
+  if (status = RSAPrivateBlock
+      (pkcsBlock, &pkcsBlockLen, input, inputLen, privateKey))
+    return (status);
+  
+  if (pkcsBlockLen != modulusLen)
+    return (RE_LEN);
+  
+  /* Require block type 2.
+   */
+  if ((pkcsBlock[0] != 0) || (pkcsBlock[1] != 2))
+   return (RE_DATA);
+
+  for (i = 2; i < modulusLen-1; i++)
+    /* separator */
+    if (pkcsBlock[i] == 0)
+      break;
+    
+  i++;
+  if (i >= modulusLen)
+    return (RE_DATA);
+    
+  *outputLen = modulusLen - i;
+  
+  if (*outputLen + 11 > modulusLen)
+    return (RE_DATA);
+
+  R_memcpy ((POINTER)output, (POINTER)&pkcsBlock[i], *outputLen);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)pkcsBlock, 0, sizeof (pkcsBlock));
+  
+  return (0);
+}
+
+/* Raw RSA public-key operation. Output has same length as modulus.
+
+   Assumes inputLen < length of modulus.
+   Requires input < modulus.
+ */
+static int RSAPublicBlock (output, outputLen, input, inputLen, publicKey)
+unsigned char *output;                                      /* output block */
+unsigned int *outputLen;                          /* length of output block */
+unsigned char *input;                                        /* input block */
+unsigned int inputLen;                             /* length of input block */
+R_RSA_PUBLIC_KEY *publicKey;                              /* RSA public key */
+{
+  NN_DIGIT c[MAX_NN_DIGITS], e[MAX_NN_DIGITS], m[MAX_NN_DIGITS],
+    n[MAX_NN_DIGITS];
+  unsigned int eDigits, nDigits;
+
+  NN_Decode (m, MAX_NN_DIGITS, input, inputLen);
+  NN_Decode (n, MAX_NN_DIGITS, publicKey->modulus, MAX_RSA_MODULUS_LEN);
+  NN_Decode (e, MAX_NN_DIGITS, publicKey->exponent, MAX_RSA_MODULUS_LEN);
+  nDigits = NN_Digits (n, MAX_NN_DIGITS);
+  eDigits = NN_Digits (e, MAX_NN_DIGITS);
+  
+  if (NN_Cmp (m, n, nDigits) >= 0)
+    return (RE_DATA);
+  
+  /* Compute c = m^e mod n.
+   */
+  NN_ModExp (c, m, e, eDigits, n, nDigits);
+
+  *outputLen = (publicKey->bits + 7) / 8;
+  NN_Encode (output, *outputLen, c, nDigits);
+  
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)c, 0, sizeof (c));
+  R_memset ((POINTER)m, 0, sizeof (m));
+
+  return (0);
+}
+
+/* Raw RSA private-key operation. Output has same length as modulus.
+
+   Assumes inputLen < length of modulus.
+   Requires input < modulus.
+ */
+static int RSAPrivateBlock (output, outputLen, input, inputLen, privateKey)
+unsigned char *output;                                      /* output block */
+unsigned int *outputLen;                          /* length of output block */
+unsigned char *input;                                        /* input block */
+unsigned int inputLen;                             /* length of input block */
+R_RSA_PRIVATE_KEY *privateKey;                           /* RSA private key */
+{
+  NN_DIGIT c[MAX_NN_DIGITS], cP[MAX_NN_DIGITS], cQ[MAX_NN_DIGITS],
+    dP[MAX_NN_DIGITS], dQ[MAX_NN_DIGITS], mP[MAX_NN_DIGITS],
+    mQ[MAX_NN_DIGITS], n[MAX_NN_DIGITS], p[MAX_NN_DIGITS], q[MAX_NN_DIGITS],
+    qInv[MAX_NN_DIGITS], t[MAX_NN_DIGITS];
+  unsigned int cDigits, nDigits, pDigits;
+  
+  NN_Decode (c, MAX_NN_DIGITS, input, inputLen);
+  NN_Decode (n, MAX_NN_DIGITS, privateKey->modulus, MAX_RSA_MODULUS_LEN);
+  NN_Decode (p, MAX_NN_DIGITS, privateKey->prime[0], MAX_RSA_PRIME_LEN);
+  NN_Decode (q, MAX_NN_DIGITS, privateKey->prime[1], MAX_RSA_PRIME_LEN);
+  NN_Decode 
+    (dP, MAX_NN_DIGITS, privateKey->primeExponent[0], MAX_RSA_PRIME_LEN);
+  NN_Decode 
+    (dQ, MAX_NN_DIGITS, privateKey->primeExponent[1], MAX_RSA_PRIME_LEN);
+  NN_Decode (qInv, MAX_NN_DIGITS, privateKey->coefficient, MAX_RSA_PRIME_LEN);
+  cDigits = NN_Digits (c, MAX_NN_DIGITS);
+  nDigits = NN_Digits (n, MAX_NN_DIGITS);
+  pDigits = NN_Digits (p, MAX_NN_DIGITS);
+
+  if (NN_Cmp (c, n, nDigits) >= 0)
+    return (RE_DATA);
+  
+  /* Compute mP = cP^dP mod p  and  mQ = cQ^dQ mod q. (Assumes q has
+     length at most pDigits, i.e., p > q.)
+   */
+  NN_Mod (cP, c, cDigits, p, pDigits);
+  NN_Mod (cQ, c, cDigits, q, pDigits);
+  NN_ModExp (mP, cP, dP, pDigits, p, pDigits);
+  NN_AssignZero (mQ, nDigits);
+  NN_ModExp (mQ, cQ, dQ, pDigits, q, pDigits);
+  
+  /* Chinese Remainder Theorem:
+       m = ((((mP - mQ) mod p) * qInv) mod p) * q + mQ.
+   */
+  if (NN_Cmp (mP, mQ, pDigits) >= 0)
+    NN_Sub (t, mP, mQ, pDigits);
+  else {
+    NN_Sub (t, mQ, mP, pDigits);
+    NN_Sub (t, p, t, pDigits);
+  }
+  NN_ModMult (t, t, qInv, p, pDigits);
+  NN_Mult (t, t, q, pDigits);
+  NN_Add (t, t, mQ, nDigits);
+
+  *outputLen = (privateKey->bits + 7) / 8;
+  NN_Encode (output, *outputLen, t, nDigits);
+
+  /* Zeroize sensitive information.
+   */
+  R_memset ((POINTER)c, 0, sizeof (c));
+  R_memset ((POINTER)cP, 0, sizeof (cP));
+  R_memset ((POINTER)cQ, 0, sizeof (cQ));
+  R_memset ((POINTER)dP, 0, sizeof (dP));
+  R_memset ((POINTER)dQ, 0, sizeof (dQ));
+  R_memset ((POINTER)mP, 0, sizeof (mP));
+  R_memset ((POINTER)mQ, 0, sizeof (mQ));
+  R_memset ((POINTER)p, 0, sizeof (p));
+  R_memset ((POINTER)q, 0, sizeof (q));
+  R_memset ((POINTER)qInv, 0, sizeof (qInv));
+  R_memset ((POINTER)t, 0, sizeof (t));
+
+  return (0);
+}
diff --git a/util/rsaref/rsa.h b/util/rsaref/rsa.h
new file mode 100644 (file)
index 0000000..a290541
--- /dev/null
@@ -0,0 +1,19 @@
+/* RSA.H - header file for RSA.C
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+int RSAPublicEncrypt PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    R_RSA_PUBLIC_KEY *, R_RANDOM_STRUCT *));
+int RSAPrivateEncrypt PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    R_RSA_PRIVATE_KEY *));
+int RSAPublicDecrypt PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    R_RSA_PUBLIC_KEY *));
+int RSAPrivateDecrypt PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    R_RSA_PRIVATE_KEY *));
diff --git a/util/rsaref/rsaref.h b/util/rsaref/rsaref.h
new file mode 100644 (file)
index 0000000..cc03f7d
--- /dev/null
@@ -0,0 +1,252 @@
+/* RSAREF.H - header file for RSAREF cryptographic toolkit
+ */
+
+/* Copyright (C) RSA Laboratories, a division of RSA Data Security,
+     Inc., created 1991. All rights reserved.
+ */
+
+#ifndef _RSAREF_H_
+#define _RSAREF_H_ 1
+
+#include "md2.h"
+#include "md5.h"
+#include "des.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Message-digest algorithms.
+ */
+#define DA_MD2 3
+#define DA_MD5 5
+
+/* Encryption algorithms to be ored with digest algorithm in Seal and Open.
+ */
+#define EA_DES_CBC 1
+#define EA_DES_EDE2_CBC 2
+#define EA_DES_EDE3_CBC 3
+#define EA_DESX_CBC 4
+
+/* RSA key lengths.
+ */
+#define MIN_RSA_MODULUS_BITS 508
+#define MAX_RSA_MODULUS_BITS 1024
+#define MAX_RSA_MODULUS_LEN ((MAX_RSA_MODULUS_BITS + 7) / 8)
+#define MAX_RSA_PRIME_BITS ((MAX_RSA_MODULUS_BITS + 1) / 2)
+#define MAX_RSA_PRIME_LEN ((MAX_RSA_PRIME_BITS + 7) / 8)
+
+/* Maximum lengths of encoded and encrypted content, as a function of
+   content length len. Also, inverse functions.
+ */
+#define ENCODED_CONTENT_LEN(len) (4*(len)/3 + 3)
+#define ENCRYPTED_CONTENT_LEN(len) ENCODED_CONTENT_LEN ((len)+8)
+#define DECODED_CONTENT_LEN(len) (3*(len)/4 + 1)
+#define DECRYPTED_CONTENT_LEN(len) (DECODED_CONTENT_LEN (len) - 1)
+
+/* Maximum lengths of signatures, encrypted keys, encrypted
+   signatures, and message digests.
+ */
+#define MAX_SIGNATURE_LEN MAX_RSA_MODULUS_LEN
+#define MAX_PEM_SIGNATURE_LEN ENCODED_CONTENT_LEN (MAX_SIGNATURE_LEN)
+#define MAX_ENCRYPTED_KEY_LEN MAX_RSA_MODULUS_LEN
+#define MAX_PEM_ENCRYPTED_KEY_LEN ENCODED_CONTENT_LEN (MAX_ENCRYPTED_KEY_LEN)
+#define MAX_PEM_ENCRYPTED_SIGNATURE_LEN \
+  ENCRYPTED_CONTENT_LEN (MAX_SIGNATURE_LEN)
+#define MAX_DIGEST_LEN 16
+
+/* Maximum length of Diffie-Hellman parameters.
+ */
+#define DH_PRIME_LEN(bits) (((bits) + 7) / 8)
+
+/* Error codes.
+ */
+#define RE_CONTENT_ENCODING 0x0400
+#define RE_DATA 0x0401
+#define RE_DIGEST_ALGORITHM 0x0402
+#define RE_ENCODING 0x0403
+#define RE_KEY 0x0404
+#define RE_KEY_ENCODING 0x0405
+#define RE_LEN 0x0406
+#define RE_MODULUS_LEN 0x0407
+#define RE_NEED_RANDOM 0x0408
+#define RE_PRIVATE_KEY 0x0409
+#define RE_PUBLIC_KEY 0x040a
+#define RE_SIGNATURE 0x040b
+#define RE_SIGNATURE_ENCODING 0x040c
+#define RE_ENCRYPTION_ALGORITHM 0x040d
+
+/* Random structure.
+ */
+typedef struct {
+  unsigned int bytesNeeded;
+  unsigned char state[16];
+  unsigned int outputAvailable;
+  unsigned char output[16];
+} R_RANDOM_STRUCT;
+
+/* RSA public and private key.
+ */
+typedef struct {
+  unsigned int bits;                           /* length in bits of modulus */
+  unsigned char modulus[MAX_RSA_MODULUS_LEN];                    /* modulus */
+  unsigned char exponent[MAX_RSA_MODULUS_LEN];           /* public exponent */
+} R_RSA_PUBLIC_KEY;
+
+typedef struct {
+  unsigned int bits;                           /* length in bits of modulus */
+  unsigned char modulus[MAX_RSA_MODULUS_LEN];                    /* modulus */
+  unsigned char publicExponent[MAX_RSA_MODULUS_LEN];     /* public exponent */
+  unsigned char exponent[MAX_RSA_MODULUS_LEN];          /* private exponent */
+  unsigned char prime[2][MAX_RSA_PRIME_LEN];               /* prime factors */
+  unsigned char primeExponent[2][MAX_RSA_PRIME_LEN];   /* exponents for CRT */
+  unsigned char coefficient[MAX_RSA_PRIME_LEN];          /* CRT coefficient */
+} R_RSA_PRIVATE_KEY;
+
+/* RSA prototype key.
+ */
+typedef struct {
+  unsigned int bits;                           /* length in bits of modulus */
+  int useFermat4;                        /* public exponent (1 = F4, 0 = 3) */
+} R_RSA_PROTO_KEY;
+
+/* Diffie-Hellman parameters.
+ */
+typedef struct {
+  unsigned char *prime;                                            /* prime */
+  unsigned int primeLen;                                 /* length of prime */
+  unsigned char *generator;                                    /* generator */
+  unsigned int generatorLen;                         /* length of generator */
+} R_DH_PARAMS;
+
+typedef struct {
+  int digestAlgorithm;
+  union {
+    MD2_CTX md2;
+    MD5_CTX md5;
+  } context;
+} R_DIGEST_CTX;
+
+typedef struct {
+  R_DIGEST_CTX digestContext;
+} R_SIGNATURE_CTX;
+
+typedef struct {
+  int encryptionAlgorithm;
+  union {
+    DES_CBC_CTX des;
+    DES3_CBC_CTX des3;
+    DESX_CBC_CTX desx;
+  } cipherContext;
+  
+  unsigned char buffer[8];
+  unsigned int bufferLen;
+} R_ENVELOPE_CTX;
+
+/* Random structures.
+ */
+int R_RandomInit PROTO_LIST ((R_RANDOM_STRUCT *));
+int R_RandomUpdate PROTO_LIST
+  ((R_RANDOM_STRUCT *, unsigned char *, unsigned int));
+int R_GetRandomBytesNeeded PROTO_LIST ((unsigned int *, R_RANDOM_STRUCT *));
+void R_RandomFinal PROTO_LIST ((R_RANDOM_STRUCT *));
+
+/* Cryptographic procedures "by parts"
+ */
+int R_DigestInit PROTO_LIST ((R_DIGEST_CTX *, int));
+int R_DigestUpdate PROTO_LIST
+  ((R_DIGEST_CTX *, unsigned char *, unsigned int));
+int R_DigestFinal PROTO_LIST
+  ((R_DIGEST_CTX *, unsigned char *, unsigned int *));
+
+int R_SignInit PROTO_LIST ((R_SIGNATURE_CTX *, int));
+int R_SignUpdate PROTO_LIST
+  ((R_SIGNATURE_CTX *, unsigned char *, unsigned int));
+int R_SignFinal PROTO_LIST
+  ((R_SIGNATURE_CTX *, unsigned char *, unsigned int *, R_RSA_PRIVATE_KEY *));
+
+int R_VerifyInit PROTO_LIST ((R_SIGNATURE_CTX *, int));
+int R_VerifyUpdate PROTO_LIST
+  ((R_SIGNATURE_CTX *, unsigned char *, unsigned int));
+int R_VerifyFinal PROTO_LIST
+  ((R_SIGNATURE_CTX *, unsigned char *, unsigned int, R_RSA_PUBLIC_KEY *));
+
+int R_SealInit PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char **, unsigned int *, unsigned char [8],
+    unsigned int, R_RSA_PUBLIC_KEY **, int, R_RANDOM_STRUCT *));
+int R_SealUpdate PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *,
+    unsigned int));
+int R_SealFinal PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *));
+
+int R_OpenInit PROTO_LIST
+  ((R_ENVELOPE_CTX *, int, unsigned char *, unsigned int, unsigned char [8],
+    R_RSA_PRIVATE_KEY *));
+int R_OpenUpdate PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *, unsigned char *,
+    unsigned int));
+int R_OpenFinal PROTO_LIST
+  ((R_ENVELOPE_CTX *, unsigned char *, unsigned int *));
+
+/* Cryptographic enhancements by block.
+ */
+int R_SignPEMBlock PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int *,
+    unsigned char *, unsigned int, int, int, R_RSA_PRIVATE_KEY *));
+int R_SignBlock PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int, int,
+    R_RSA_PRIVATE_KEY *));
+int R_VerifyPEMSignature PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    unsigned char *, unsigned int, int, int, R_RSA_PUBLIC_KEY *));
+int R_VerifyBlockSignature PROTO_LIST
+  ((unsigned char *, unsigned int, unsigned char *, unsigned int, int,
+    R_RSA_PUBLIC_KEY *));
+int R_SealPEMBlock PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int *,
+    unsigned char *, unsigned int *, unsigned char [8], unsigned char *,
+    unsigned int, int, R_RSA_PUBLIC_KEY *, R_RSA_PRIVATE_KEY *,
+    R_RANDOM_STRUCT *));
+int R_OpenPEMBlock PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int,
+    unsigned char *, unsigned int, unsigned char *, unsigned int,
+    unsigned char [8], int, R_RSA_PRIVATE_KEY *, R_RSA_PUBLIC_KEY *));
+int R_DigestBlock PROTO_LIST 
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int, int));
+
+/* Printable ASCII encoding and decoding.
+ */
+int R_EncodePEMBlock PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int));
+int R_DecodePEMBlock PROTO_LIST
+  ((unsigned char *, unsigned int *, unsigned char *, unsigned int));
+  
+/* Key-pair generation.
+ */
+int R_GeneratePEMKeys PROTO_LIST
+  ((R_RSA_PUBLIC_KEY *, R_RSA_PRIVATE_KEY *, R_RSA_PROTO_KEY *,
+    R_RANDOM_STRUCT *));
+
+/* Diffie-Hellman key agreement.
+ */
+int R_GenerateDHParams PROTO_LIST
+  ((R_DH_PARAMS *, unsigned int, unsigned int, R_RANDOM_STRUCT *));
+int R_SetupDHAgreement PROTO_LIST
+  ((unsigned char *, unsigned char *, unsigned int, R_DH_PARAMS *,
+    R_RANDOM_STRUCT *));
+int R_ComputeDHAgreedKey PROTO_LIST
+  ((unsigned char *, unsigned char *, unsigned char *, unsigned int,
+    R_DH_PARAMS *));
+
+/* Routines supplied by the implementor.
+ */
+void R_memset PROTO_LIST ((POINTER, int, unsigned int));
+void R_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+int R_memcmp PROTO_LIST ((POINTER, POINTER, unsigned int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
This page took 0.192187 seconds and 5 git commands to generate.