--- /dev/null
+# $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) $@
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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));
--- /dev/null
+/* 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_ */
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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))
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 *));
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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));
+}
--- /dev/null
+/* 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 *));
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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 *));
--- /dev/null
+/* 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