您的位置:首页 > 其它

SOURCE CODE FOR MD5

2012-10-21 23:45 495 查看
View Code

/*
Source Code for Cryptography (Just a touch)

SOURCE CODE FOR MD5

md5.h (the include file for the above C code)

Karn Encryption: Symmetric Secret with MD5

SHA-1 By Steve Reid

RSA Crypto Toolkit Totality

DES Encryption

Elliptic Curves

SOURCE CODE FOR MD5
*/

#ifdef  CPU386  /* Fast assembler version exists for 386/486 */

#pragma inline

#endif

/*

***********************************************************************

** md5.c -- the source code for MD5 routines                         **

** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **

** Created: 2/17/90 RLR                                              **

** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **

**          1992.2.13 Jouko Holopainen, 80x86 version                **

***********************************************************************

*/

/*

***********************************************************************

** Copyright (C) 1990, RSA Data Security, Inc. 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 "md5.h"

/*

***********************************************************************

**  Message-digest routines:                                         **

**  To form the message digest for a message M                       **

**    (1) Initialize a context buffer mdContext using MD5Init        **

**    (2) Call MD5Update on mdContext and M                          **

**    (3) Call MD5Final on mdContext                                 **

**  The message digest is now in mdContext->digest[0...15]           **

***********************************************************************

*/

static unsigned char PADDING[64] = {

0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00

};

#ifndef CPU386  /* Alternate defs exist for 386 assembler version */

/* 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); \

}

#endif  /* CPU386 */

/* The routine MD5Init initializes the message-digest context

mdContext. All fields are set to zero.

*/

void MD5Init (mdContext)

MD5_CTX *mdContext;

{

mdContext->i[0] = mdContext->i[1] = (UINT4)0;

/* Load magic initialization constants.

*/

mdContext->buf[0] = (UINT4)0x67452301;

mdContext->buf[1] = (UINT4)0xefcdab89;

mdContext->buf[2] = (UINT4)0x98badcfe;

mdContext->buf[3] = (UINT4)0x10325476;

}

/* The routine MD5Update updates the message-digest context to

account for the presence of each of the characters inBuf[0..inLen-1]

in the message whose digest is being computed.

*/

void MD5Update (mdContext, inBuf, inLen)

MD5_CTX *mdContext;

unsigned char *inBuf;

unsigned int inLen;

{

UINT4 in[16];

int mdi;

unsigned int i, ii;

/* compute number of bytes mod 64 */

mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

/* update number of bits */

if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0])

mdContext->i[1]++;

mdContext->i[0] += ((UINT4)inLen << 3);

mdContext->i[1] += ((UINT4)inLen >> 29);

#ifdef  LITTLE_ENDIAN

/* Speedup for little-endian machines suggested in MD5 report --P Karn */

if(mdi == 0 && ((int)inBuf & 3) == 0){

while(inLen >= 64){

MD5Transform(mdContext->buf,(UINT4 *)inBuf);

inLen -= 64;

inBuf += 64;

}

}

#endif  /* LITTLE_ENDIAN */

while (inLen--) {

/* add new character to buffer, increment mdi */

mdContext->in[mdi++] = *inBuf++;

/* transform if necessary */

if (mdi == 0x40) {

for (i = 0, ii = 0; i < 16; i++, ii += 4)

in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |

(((UINT4)mdContext->in[ii+2]) << 16) |

(((UINT4)mdContext->in[ii+1]) << 8) |

((UINT4)mdContext->in[ii]);

MD5Transform (mdContext->buf, in);

mdi = 0;

}

}

}

/* The routine MD5Final terminates the message-digest computation and

ends with the desired message digest in mdContext->digest[0...15].

*/

void MD5Final (mdContext)

MD5_CTX *mdContext;

{

UINT4 in[16];

int mdi;

unsigned int i, ii;

unsigned int padLen;

/* save number of bits */

in[14] = mdContext->i[0];

in[15] = mdContext->i[1];

/* compute number of bytes mod 64 */

mdi = (int)((mdContext->i[0] >> 3) & 0x3F);

/* pad out to 56 mod 64 */

padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);

MD5Update (mdContext, PADDING, padLen);

/* append length in bits and transform */

for (i = 0, ii = 0; i < 14; i++, ii += 4)

in[i] = (((UINT4)mdContext->in[ii+3]) << 24) |

(((UINT4)mdContext->in[ii+2]) << 16) |

(((UINT4)mdContext->in[ii+1]) << 8) |

((UINT4)mdContext->in[ii]);

MD5Transform (mdContext->buf, in);

/* store buffer in digest */

for (i = 0, ii = 0; i < 4; i++, ii += 4) {

mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF);

mdContext->digest[ii+1] =

(unsigned char)((mdContext->buf[i] >> 8) & 0xFF);

mdContext->digest[ii+2] =

(unsigned char)((mdContext->buf[i] >> 16) & 0xFF);

mdContext->digest[ii+3] =

(unsigned char)((mdContext->buf[i] >> 24) & 0xFF);

}

}

#ifndef CPU386  /* Fast assembler version exists for 386/486 */

/* Basic MD5 step. Transforms buf based on in.

*/

void MD5Transform (buf, in)

UINT4 *buf;

UINT4 *in;

{

UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3];

/* Round 1 */

#define S11 7

#define S12 12

#define S13 17

#define S14 22

FF ( a, b, c, d, in[ 0], S11, 3614090360); /* 1 */

FF ( d, a, b, c, in[ 1], S12, 3905402710); /* 2 */

FF ( c, d, a, b, in[ 2], S13,  606105819); /* 3 */

FF ( b, c, d, a, in[ 3], S14, 3250441966); /* 4 */

FF ( a, b, c, d, in[ 4], S11, 4118548399); /* 5 */

FF ( d, a, b, c, in[ 5], S12, 1200080426); /* 6 */

FF ( c, d, a, b, in[ 6], S13, 2821735955); /* 7 */

FF ( b, c, d, a, in[ 7], S14, 4249261313); /* 8 */

FF ( a, b, c, d, in[ 8], S11, 1770035416); /* 9 */

FF ( d, a, b, c, in[ 9], S12, 2336552879); /* 10 */

FF ( c, d, a, b, in[10], S13, 4294925233); /* 11 */

FF ( b, c, d, a, in[11], S14, 2304563134); /* 12 */

FF ( a, b, c, d, in[12], S11, 1804603682); /* 13 */

FF ( d, a, b, c, in[13], S12, 4254626195); /* 14 */

FF ( c, d, a, b, in[14], S13, 2792965006); /* 15 */

FF ( b, c, d, a, in[15], S14, 1236535329); /* 16 */

/* Round 2 */

#define S21 5

#define S22 9

#define S23 14

#define S24 20

GG ( a, b, c, d, in[ 1], S21, 4129170786); /* 17 */

GG ( d, a, b, c, in[ 6], S22, 3225465664); /* 18 */

GG ( c, d, a, b, in[11], S23,  643717713); /* 19 */

GG ( b, c, d, a, in[ 0], S24, 3921069994); /* 20 */

GG ( a, b, c, d, in[ 5], S21, 3593408605); /* 21 */

GG ( d, a, b, c, in[10], S22,   38016083); /* 22 */

GG ( c, d, a, b, in[15], S23, 3634488961); /* 23 */

GG ( b, c, d, a, in[ 4], S24, 3889429448); /* 24 */

GG ( a, b, c, d, in[ 9], S21,  568446438); /* 25 */

GG ( d, a, b, c, in[14], S22, 3275163606); /* 26 */

GG ( c, d, a, b, in[ 3], S23, 4107603335); /* 27 */

GG ( b, c, d, a, in[ 8], S24, 1163531501); /* 28 */

GG ( a, b, c, d, in[13], S21, 2850285829); /* 29 */

GG ( d, a, b, c, in[ 2], S22, 4243563512); /* 30 */

GG ( c, d, a, b, in[ 7], S23, 1735328473); /* 31 */

GG ( b, c, d, a, in[12], S24, 2368359562); /* 32 */

/* Round 3 */

#define S31 4

#define S32 11

#define S33 16

#define S34 23

HH ( a, b, c, d, in[ 5], S31, 4294588738); /* 33 */

HH ( d, a, b, c, in[ 8], S32, 2272392833); /* 34 */

HH ( c, d, a, b, in[11], S33, 1839030562); /* 35 */

HH ( b, c, d, a, in[14], S34, 4259657740); /* 36 */

HH ( a, b, c, d, in[ 1], S31, 2763975236); /* 37 */

HH ( d, a, b, c, in[ 4], S32, 1272893353); /* 38 */

HH ( c, d, a, b, in[ 7], S33, 4139469664); /* 39 */

HH ( b, c, d, a, in[10], S34, 3200236656); /* 40 */

HH ( a, b, c, d, in[13], S31,  681279174); /* 41 */

HH ( d, a, b, c, in[ 0], S32, 3936430074); /* 42 */

HH ( c, d, a, b, in[ 3], S33, 3572445317); /* 43 */

HH ( b, c, d, a, in[ 6], S34,   76029189); /* 44 */

HH ( a, b, c, d, in[ 9], S31, 3654602809); /* 45 */

HH ( d, a, b, c, in[12], S32, 3873151461); /* 46 */

HH ( c, d, a, b, in[15], S33,  530742520); /* 47 */

HH ( b, c, d, a, in[ 2], S34, 3299628645); /* 48 */

/* Round 4 */

#define S41 6

#define S42 10

#define S43 15

#define S44 21

II ( a, b, c, d, in[ 0], S41, 4096336452); /* 49 */

II ( d, a, b, c, in[ 7], S42, 1126891415); /* 50 */

II ( c, d, a, b, in[14], S43, 2878612391); /* 51 */

II ( b, c, d, a, in[ 5], S44, 4237533241); /* 52 */

II ( a, b, c, d, in[12], S41, 1700485571); /* 53 */

II ( d, a, b, c, in[ 3], S42, 2399980690); /* 54 */

II ( c, d, a, b, in[10], S43, 4293915773); /* 55 */

II ( b, c, d, a, in[ 1], S44, 2240044497); /* 56 */

II ( a, b, c, d, in[ 8], S41, 1873313359); /* 57 */

II ( d, a, b, c, in[15], S42, 4264355552); /* 58 */

II ( c, d, a, b, in[ 6], S43, 2734768916); /* 59 */

II ( b, c, d, a, in[13], S44, 1309151649); /* 60 */

II ( a, b, c, d, in[ 4], S41, 4149444226); /* 61 */

II ( d, a, b, c, in[11], S42, 3174756917); /* 62 */

II ( c, d, a, b, in[ 2], S43,  718787259); /* 63 */

II ( b, c, d, a, in[ 9], S44, 3951481745); /* 64 */

buf[0] += a;

buf[1] += b;

buf[2] += c;

buf[3] += d;

}

#else   /* CPU386 */

/* Fast 386 Borland C inline assembler version of the MD5Transform() function

* from the RSA Data Security, Inc, MD5 Message Digest Algorithm.

*

* This version uses native 32 bit registers, so it needs a 386 or 486 CPU.

*

* Because this function does *lots* of 32-bit operations, this version is

* MUCH faster than the reference C version compiled with a garden-

* variety 16-bit MS-DOS C compiler.

*

* Written and placed into the public domain on

* 22 February 1992 by Phil Karn, KA9Q

*/

/* I really shouldn't have to do this explicitly... */

#ifdef  __COMPACT__

asm     .MODEL COMPACT

#elif   __HUGE__

asm     .MODEL HUGE

#elif   __LARGE__

asm     .MODEL LARGE

#elif   __MEDIUM__

asm     .MODEL MEDIUM

#elif   __SMALL__

asm     .MODEL SMALL

#elif   __TINY__

asm     .MODEL TINY

#endif

/* Code sequence common to all four rounds.

* evaluates a = b + (a + edi + x + t) <<< s

* Assumes a,b are registers, s,t are immediate constants

* The 'lea' instruction is just a fast way to compute "a = a+t+edi"

*/

#define COM(a,b,x,s,t)\

asm     lea a,t[a+edi];\

asm     add a,x;\

asm     rol a,s;\

asm     add a,b;

/* Round 1 functions */

/* edi = F(x,y,z) = (x & y) | (~x & z) */

#define F(x,y,z)\

asm     mov edi,x;\

asm     and edi,y;\

asm     mov esi,x;\

asm     not esi;\

asm     and esi,z;\

asm     or edi,esi

/* a = b + ((a + F(x,y,z) + x + t) <<< s); */

#define FF(a,b,c,d,x,s,t)\

F(b,c,d);\

COM(a,b,x,s,t)

/* Round 2 functions */

/* edi = G(x,y,z) = F(z,x,y) = (x & z) | (y & ~z) */

#define G(x,y,z) F(z,x,y)

/* a = b + ((a + G(b,c,d) + x + t) <<< s) */

#define GG(a,b,c,d,x,s,t)\

G(b,c,d);\

COM(a,b,x,s,t)

/* Round 3 functions */

/* edi = H(x,y,z) = x ^ y ^ z */

#define H(x,y,z)\

asm     mov edi,x;\

asm     xor edi,y;\

asm     xor edi,z

/* a = b + ((a + H(b,c,d) + x + t) <<< s) */

#define HH(a,b,c,d,x,s,t)\

H(b,c,d);\

COM(a,b,x,s,t)

/* Round 4 functions */

/* edi = I(x,y,z) = y ^ (x | ~z) */

#define I(x,y,z)\

asm     mov edi,z;\

asm     not edi;\

asm     or edi,x;\

asm     xor edi,y

/* a = b + ((a + I(b,c,d) + x + t) <<< s) */

#define II(a,b,c,d,x,s,t)\

I(b,c,d);\

COM(a,b,x,s,t)

#define A       eax

#define B       ebx

#define C       ecx

#define D       edx

void

MD5Transform(buf,input)

UINT4 *buf;

UINT4 *input;

{

asm     .386;   /* Allow use of 32-bit general registers */

/* Save caller's registers */

asm     push si;

asm     push di;

asm     push es;

asm     if @DataSize NE 0

asm             push ds;

asm     endif

/* Get buf argument */

asm     if @DataSize NE 0

asm             lds si,buf;

asm     else

asm             mov si,buf;

asm     endif

asm     mov A,dword ptr si[0*4];        /* A = buf[0] */

asm     mov B,dword ptr si[1*4];        /* B = buf[1] */

asm     mov C,dword ptr si[2*4];        /* C = buf[2] */

asm     mov D,dword ptr si[3*4];        /* D = buf[3] */

/* Warning: This makes our other args inaccessible until bp

* is restored!

*/

asm     push bp;

asm     les bp,input

/* Round 1. The *4 factors in the subscripts to bp account for the

* byte offsets of each long element in the input array.

*/

#define S11 7

#define S12 12

#define S13 17

#define S14 22

FF(A,B,C,D,es:bp[ 0*4],S11,3614090360); /* 1 */

FF(D,A,B,C,es:bp[ 1*4],S12,3905402710); /* 2 */

FF(C,D,A,B,es:bp[ 2*4],S13, 606105819); /* 3 */

FF(B,C,D,A,es:bp[ 3*4],S14,3250441966); /* 4 */

FF(A,B,C,D,es:bp[ 4*4],S11,4118548399); /* 5 */

FF(D,A,B,C,es:bp[ 5*4],S12,1200080426); /* 6 */

FF(C,D,A,B,es:bp[ 6*4],S13,2821735955); /* 7 */

FF(B,C,D,A,es:bp[ 7*4],S14,4249261313); /* 8 */

FF(A,B,C,D,es:bp[ 8*4],S11,1770035416); /* 9 */

FF(D,A,B,C,es:bp[ 9*4],S12,2336552879); /* 10 */

FF(C,D,A,B,es:bp[10*4],S13,4294925233); /* 11 */

FF(B,C,D,A,es:bp[11*4],S14,2304563134); /* 12 */

FF(A,B,C,D,es:bp[12*4],S11,1804603682); /* 13 */

FF(D,A,B,C,es:bp[13*4],S12,4254626195); /* 14 */

FF(C,D,A,B,es:bp[14*4],S13,2792965006); /* 15 */

FF(B,C,D,A,es:bp[15*4],S14,1236535329); /* 16 */

/* Round 2 */

#define S21 5

#define S22 9

#define S23 14

#define S24 20

GG(A,B,C,D,es:bp[ 1*4],S21,4129170786); /* 17 */

GG(D,A,B,C,es:bp[ 6*4],S22,3225465664); /* 18 */

GG(C,D,A,B,es:bp[11*4],S23, 643717713); /* 19 */

GG(B,C,D,A,es:bp[ 0*4],S24,3921069994); /* 20 */

GG(A,B,C,D,es:bp[ 5*4],S21,3593408605); /* 21 */

GG(D,A,B,C,es:bp[10*4],S22,  38016083); /* 22 */

GG(C,D,A,B,es:bp[15*4],S23,3634488961); /* 23 */

GG(B,C,D,A,es:bp[ 4*4],S24,3889429448); /* 24 */

GG(A,B,C,D,es:bp[ 9*4],S21, 568446438); /* 25 */

GG(D,A,B,C,es:bp[14*4],S22,3275163606); /* 26 */

GG(C,D,A,B,es:bp[ 3*4],S23,4107603335); /* 27 */

GG(B,C,D,A,es:bp[ 8*4],S24,1163531501); /* 28 */

GG(A,B,C,D,es:bp[13*4],S21,2850285829); /* 29 */

GG(D,A,B,C,es:bp[ 2*4],S22,4243563512); /* 30 */

GG(C,D,A,B,es:bp[ 7*4],S23,1735328473); /* 31 */

GG(B,C,D,A,es:bp[12*4],S24,2368359562); /* 32 */

/* Round 3 */

#define S31 4

#define S32 11

#define S33 16

#define S34 23

HH(A,B,C,D,es:bp[ 5*4],S31,4294588738); /* 33 */

HH(D,A,B,C,es:bp[ 8*4],S32,2272392833); /* 34 */

HH(C,D,A,B,es:bp[11*4],S33,1839030562); /* 35 */

HH(B,C,D,A,es:bp[14*4],S34,4259657740); /* 36 */

HH(A,B,C,D,es:bp[ 1*4],S31,2763975236); /* 37 */

HH(D,A,B,C,es:bp[ 4*4],S32,1272893353); /* 38 */

HH(C,D,A,B,es:bp[ 7*4],S33,4139469664); /* 39 */

HH(B,C,D,A,es:bp[10*4],S34,3200236656); /* 40 */

HH(A,B,C,D,es:bp[13*4],S31, 681279174); /* 41 */

HH(D,A,B,C,es:bp[ 0*4],S32,3936430074); /* 42 */

HH(C,D,A,B,es:bp[ 3*4],S33,3572445317); /* 43 */

HH(B,C,D,A,es:bp[ 6*4],S34,  76029189); /* 44 */

HH(A,B,C,D,es:bp[ 9*4],S31,3654602809); /* 45 */

HH(D,A,B,C,es:bp[12*4],S32,3873151461); /* 46 */

HH(C,D,A,B,es:bp[15*4],S33, 530742520); /* 47 */

HH(B,C,D,A,es:bp[ 2*4],S34,3299628645); /* 48 */

/* Round 4 */

#define S41 6

#define S42 10

#define S43 15

#define S44 21

II(A,B,C,D,es:bp[ 0*4],S41,4096336452); /* 49 */

II(D,A,B,C,es:bp[ 7*4],S42,1126891415); /* 50 */

II(C,D,A,B,es:bp[14*4],S43,2878612391); /* 51 */

II(B,C,D,A,es:bp[ 5*4],S44,4237533241); /* 52 */

II(A,B,C,D,es:bp[12*4],S41,1700485571); /* 53 */

II(D,A,B,C,es:bp[ 3*4],S42,2399980690); /* 54 */

II(C,D,A,B,es:bp[10*4],S43,4293915773); /* 55 */

II(B,C,D,A,es:bp[ 1*4],S44,2240044497); /* 56 */

II(A,B,C,D,es:bp[ 8*4],S41,1873313359); /* 57 */

II(D,A,B,C,es:bp[15*4],S42,4264355552); /* 58 */

II(C,D,A,B,es:bp[ 6*4],S43,2734768916); /* 59 */

II(B,C,D,A,es:bp[13*4],S44,1309151649); /* 60 */

II(A,B,C,D,es:bp[ 4*4],S41,4149444226); /* 61 */

II(D,A,B,C,es:bp[11*4],S42,3174756917); /* 62 */

II(C,D,A,B,es:bp[ 2*4],S43, 718787259); /* 63 */

II(B,C,D,A,es:bp[ 9*4],S44,3951481745); /* 64 */

asm pop bp;             /* We can address our args again */

asm     if @DataSize NE 0

asm             lds si,buf

asm     else

asm             mov si,buf;

asm     endif

asm add dword ptr si[0*4],A;    /* buf[0] += A */

asm add dword ptr si[1*4],B;    /* buf[1] += B */

asm add dword ptr si[2*4],C;    /* buf[2] += C */

asm add dword ptr si[3*4],D;    /* buf[3] += D */

/* Restore caller's registers */

asm     if @DataSize NE 0

asm             pop ds

asm     endif

asm     pop es;

asm     pop di;

asm     pop si;

}

#endif  /* CPU386 */

/*

***********************************************************************

** End of md5.c                                                      **

******************************** (cut) ********************************

*/

md5.h (the include file for the above C code)

/*

***********************************************************************

** md5.h -- header file for implementation of MD5                    **

** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **

** Created: 2/17/90 RLR                                              **

** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **

** Revised (for MD5): RLR 4/27/91                                    **

**   -- G modified to have y&~z instead of y&z                       **

**   -- FF, GG, HH modified to add in last register done             **

**   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **

**   -- distinct additive constant for each step                     **

**   -- round 4 added, working mod 7                                 **

***********************************************************************

*/

/*

***********************************************************************

** Copyright (C) 1990, RSA Data Security, Inc. 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.                                    **

***********************************************************************

*/

/* typedef a 32-bit type */

typedef unsigned long int UINT4;

/* Data structure for MD5 (Message-Digest) computation */

typedef struct {

UINT4 i[2];                   /* number of _bits_ handled mod 2^64 */

UINT4 buf[4];                                    /* scratch buffer */

unsigned char in[64];                              /* input buffer */

unsigned char digest[16];     /* actual digest after MD5Final call */

} MD5_CTX;

void MD5Init (MD5_CTX *);

void MD5Update (MD5_CTX *,unsigned char *,unsigned int);

void MD5Final (MD5_CTX *);

void MD5Transform(UINT4 *,UINT4 *);

/*

***********************************************************************

** End of md5.h                                                      **

******************************** (cut) ********************************

*/

Karn Encryption: Symmetric Secret with MD5

/*

*   Karn encryption

*   Based on Phil Karn, sci.crypt, 13 Feb 1992

*   See also his comments from sci.crypt, 23 Mar 1992.

*   The method is a variant of that described in

*   Zheng, Matsumoto and Imai, Crypto 89.

*   See also, "A New Class of Cryptosystems Based on

*     Interconnection Networks" by

*     michaelp@terpsichore.informatic.rwth-aachen.de

*

*   A method for turning a hash function, here MD5, into a fast

*   secret-key encryption.

*

*   This does triple hashing with nondistinct keys.

*/

typedef unsigned long UINT4;

/* Initial values for MD5 Transform hash function */

static UINT4 ihash[4] = {

0x67452301L, 0xefcdab89L, 0x98badcfeL, 0x10325476L };

/* MD5 hash function */

extern void Transform ();

/* Basic transform for Karn encryption.  Take two 16-byte

half-buffers, two 48-byte keys (which must be distinct), and use

the MD5 Transform algorithm to produce two 16-byte output

half-buffers.

This is reversible: If we get out1 and out2 from in1, in2, key1, key2,

then we can get in2 and in1 from out2, out1, key1, key2.

in1, in2, out1, and out2 should point to 16-byte buffers.

By convention, in1 and in2 are two halves of a 32-byte input

buffer, and out1 and out2 are two halves of a 32-byte output

buffer.

key1 and key2 should point to 48-byte buffers with different contents.

*/

void

karn (out1, out2, in1, in2, key1, key2)

UINT4 *out1, *out2, *in1, *in2, *key1, *key2;

{

int  i;

UINT4     buf[16];

UINT4     hash[4];

UINT4     temp[4];

bcopy (ihash, hash, sizeof(hash));

bcopy (in1, buf, 16);

bcopy (key1, buf+4, 48);

Transform (hash, buf);

for (i=0; i<4; ++i)

temp[i] = buf[i] = in2[i] ^ hash[i];

bcopy (ihash, hash, sizeof(hash));

bcopy (key2, buf+4, 48);

Transform (hash, buf);

for (i=0; i<4; ++i)

out2[i] = buf[i] = in1[i] ^ hash[i];

bcopy (ihash, hash, sizeof(hash));

bcopy (key1, buf+4, 48);

Transform (hash, buf);

for (i=0; i<4; ++i)

out1[i] = temp[i] ^ hash[i];

}

SHA-1 By Steve Reid

/*

SHA-1 in C

By Steve Reid <steve@edmweb.com>

100% Public Domain

Test Vectors (from FIPS PUB 180-1)

"abc"

A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D

"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"

84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1

A million repetitions of "a"

34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F

*/

/* #define LITTLE_ENDIAN * This should be #define'd if true. */

/* #define SHA1HANDSOFF * Copies data before messing with it. */

#include <stdio.h>

#include <string.h>

typedef struct {

unsigned long state[5];

unsigned long count[2];

unsigned char buffer[64];

} SHA1_CTX;

void SHA1Transform(unsigned long state[5], unsigned char buffer[64]);

void SHA1Init(SHA1_CTX* context);

void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len);

void SHA1Final(unsigned char digest[20], SHA1_CTX* context);

#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))

/* blk0() and blk() perform the initial expand. */

/* I got the idea of expanding during the round function from SSLeay */

#ifdef LITTLE_ENDIAN

#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \

|(rol(block->l[i],8)&0x00FF00FF))

#else

#define blk0(i) block->l[i]

#endif

#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \

^block->l[(i+2)&15]^block->l[i&15],1))

/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */

#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);

#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);

#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);

#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);

#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);

/* Hash a single 512-bit block. This is the core of the algorithm. */

void SHA1Transform(unsigned long state[5], unsigned char buffer[64])

{

unsigned long a, b, c, d, e;

typedef union {

unsigned char c[64];

unsigned long l[16];

} CHAR64LONG16;

CHAR64LONG16* block;

#ifdef SHA1HANDSOFF

static unsigned char workspace[64];

block = (CHAR64LONG16*)workspace;

memcpy(block, buffer, 64);

#else

block = (CHAR64LONG16*)buffer;

#endif

/* Copy context->state[] to working vars */

a = state[0];

b = state[1];

c = state[2];

d = state[3];

e = state[4];

/* 4 rounds of 20 operations each. Loop unrolled. */

R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);

R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);

R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);

R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);

R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);

R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);

R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);

R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);

R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);

R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);

R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);

R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);

R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);

R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);

R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);

R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);

R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);

R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);

R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);

R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);

/* Add the working vars back into context.state[] */

state[0] += a;

state[1] += b;

state[2] += c;

state[3] += d;

state[4] += e;

/* Wipe variables */

a = b = c = d = e = 0;

}

/* SHA1Init - Initialize new context */

void SHA1Init(SHA1_CTX* context)

{

/* SHA1 initialization constants */

context->state[0] = 0x67452301;

context->state[1] = 0xEFCDAB89;

context->state[2] = 0x98BADCFE;

context->state[3] = 0x10325476;

context->state[4] = 0xC3D2E1F0;

context->count[0] = context->count[1] = 0;

}

/* Run your data through this. */

void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int len)

{

unsigned int i, j;

j = (context->count[0] >> 3) & 63;

if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;

context->count[1] += (len >> 29);

if ((j + len) > 63) {

memcpy(&context->buffer[j], data, (i = 64-j));

SHA1Transform(context->state, context->buffer);

for ( ; i + 63 < len; i += 64) {

SHA1Transform(context->state, &data[i]);

}

j = 0;

}

else i = 0;

memcpy(&context->buffer[j], &data[i], len - i);

}

/* Add padding and return the message digest. */

void SHA1Final(unsigned char digest[20], SHA1_CTX* context)

{

unsigned long i, j;

unsigned char finalcount[8];

for (i = 0; i < 8; i++) {

finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)]

>> ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */

}

SHA1Update(context, (unsigned char *)"\200", 1);

while ((context->count[0] & 504) != 448) {

SHA1Update(context, (unsigned char *)"\0", 1);

}

SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */

for (i = 0; i < 20; i++) {

digest[i] = (unsigned char)

((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);

}

/* Wipe variables */

i = j = 0;

memset(context->buffer, 0, 64);

memset(context->state, 0, 20);

memset(context->count, 0, 8);

memset(finalcount, 0, 8);

#ifdef SHA1HANDSOFF  /* make SHA1Transform overwrite it's own static vars */

SHA1Transform(context->state, context->buffer);

#endif

}

/*************************************************************/

int main(int argc, char** argv)

{

int i, j;

SHA1_CTX context;

unsigned char digest[20], buffer[16384];

FILE* file;

if (argc > 2) {

puts("Public domain SHA-1 implementation - by Steve Reid <steve@edmweb.com>");

puts("Produces the SHA-1 hash of a file, or stdin if no file is specified.");

exit(0);

}

if (argc < 2) {

file = stdin;

}

else {

if (!(file = fopen(argv[1], "rb"))) {

fputs("Unable to open file.", stderr);

exit(-1);

}

}

SHA1Init(&context);

while (!feof(file)) {  /* note: what if ferror(file) */

i = fread(buffer, 1, 16384, file);

SHA1Update(&context, buffer, i);

}

SHA1Final(digest, &context);

fclose(file);

for (i = 0; i < 5; i++) {

for (j = 0; j < 4; j++) {

printf("%02X", digest[i*4+j]);

}

putchar(' ');

}

putchar('\n');

exit(0);

}

RSA Crypto Toolkit Totality

/* 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

DES Encryption

/*

* CDES -- DES encryption package

* options:

*   -a   key is in ASCII

*   -b   use key in old style (ie, don't reset parity bit)

*            -- default unless key is in ASCII

*   -c   use CBC (cipher block chaining) mode

*   -e   use ECB (electronic code book) mode

*   -f b use b-bit CFB (cipher feedback) mode

*   -F b use b-bit CFB (cipher feedback) alternative mode

*   -i   invert (decrypt) input

*   -m b     generate a MAC of length b

*   -o b use b-bit OFB (output feedback) mode

*   -v v use v as the initialization vector (ignored for ECB)

* note: the last character of the last block is the ASCII digit indicating

* how many characters of that block are to be output.

*/

#include <ctype.h>

#include <stdio.h>

#define C_NULL     ((char *) NULL)

/*

* BSD and System V systems offer special library calls that do

* block moves and fills, so if possible we take advantage of them

*/

#ifdef BSD4

#    define     MEMCPY(dest,src,len)     bcopy((src),(dest),(len))

#    define     MEMZERO(dest,len)     bzero((dest),(len))

#else

#ifdef SYSV

#    include <memory.h>

#    define     MEMCPY(dest,src,len)     (void) memcpy((dest),(src),(len))

#    define     MEMZERO(dest,len)   (void) memset((dest),'\0',(len))

#else

#    define     MEMCPY(dest,src,len)                  \

{                        \

register int i1;       \

for(i1 = 0; i1 < (len); i1++)     \

(dest)[i1] = (src)[i1];  \

}

#    define     MEMZERO(dest,len)                 \

{                        \

register int i1;       \

for(i1 = 0; i1 < (len); i1++)     \

(dest)[i1] = '\0';   \

}

#endif

#endif

/*

* these "hide" the calls to the primitive encryption routines

*/

#define     DES_KEY(buf)   {                            \

char bits1[64];     /* bits of key */    \

expand(buf, bits1);          \

setkey(bits1);               \

}

#define DES_XFORM(buf) {                            \

char bits1[64];     /* bits of message */    \

expand(buf, bits1);          \

encrypt(bits1, inverse);      \

compress(bits1, buf);             \

}

/*

* this does an error-checking write

*/

#define     READ(buf, n)   fread(buf, sizeof(char), n, stdin)

#define WRITE(buf,n)                          \

if (fwrite(buf, sizeof(char), n, stdout) != n)   \

err(1, bn, C_NULL);

/*

* some things to make references easier

*/

typedef char Desbuf[8];

#define     CHAR(x,i)     (x[i])

#define     UCHAR(x,i)     (x[i])

#define     BUFFER(x)     (x)

#define     UBUFFER(x)     (x)

/*

* global variables and related macros

*/

#define KEY_DEFAULT        0    /* interpret radix of key from key */

#define KEY_ASCII     1     /* key is in ASCII characters */

int keybase = KEY_DEFAULT;     /* how to interpret the key */

#define MODE_ENCRYPT       0x01 /* encrypt */

#define MODE_DECRYPT       0x02 /* decrypt */

#define MODE_AUTHENTICATE   0x04 /* authenticate */

#define GET_DIRECTION      ((mode)&0xf)

#define ISSET_MODE_DIRECTION     (GET_DIRECTION != 0)

#define MODE_ECB       0x10 /* ECB mode */

#define MODE_CBC       0x20 /* CBC mode */

#define     MODE_CFB       0x30 /* cipher feedback mode */

#define MODE_OFB       0x40 /* output feedback mode */

#define     MODE_CFBA      0x50 /* alternative cipher feedback mode */

#define GET_ALGORITHM      ((mode)&0xf0)

#define ISSET_MODE_ALGORITHM     (GET_ALGORITHM != 0)

int mode = 0;           /* how to run */

char *keyrep = "*********";     /* replaces command-line key */

Desbuf ivec;            /* initialization vector */

char bits[] = { '\200', '\100',     /* used to extract bits from a char */

'\040', '\020', '\010', '\004', '\002', '\001' };

int inverse = 0;        /* 0 ti encrypt, 1 to decrypt */

char *progname = "des program"; /* program name */

int parity = 1;               /* 0 to reset key parity bits */

int macbits = -1;        /* number of bits in authentication */

int fbbits = -1;        /* number of feedback bits */

char *dummyargs[] = { "*****", NULL };   /* argument list to be printed */

/*

* library hooks

*/

/* see getopt(3) */

extern int optind;        /* option (argument) number */

extern char *optarg;       /* argument to option if any */

/*

* library functions

*/

char *sprintf();        /* in core formatted print */

char *getpass();        /* get a password from a terminal */

main(argc, argv)

int argc;

char **argv;

{

register int i;         /* counter in a for loop */

register char *p;  /* used to obtain the key */

int n;              /* number of command-line errors */

Desbuf msgbuf;        /* I/O buffer */

int nargs;          /* internal number of arguments */

char **arglist;         /* internal argument list */

/*

* hide the arguments

*/

nargs = argc;

argc = 1;

arglist = argv;

argv = dummyargs;

/*

* initialize the initialization vctor

*/

for(i = 0; i < 8; i++)

UCHAR(ivec, i) = 0x00;

/*

* process the argument list

*/

progname = arglist[0];

n = 0;

while ((i = getopt(nargs, arglist, "abceF:f:im:o:v:")) != EOF)

switch(i){

case 'a':      /* key is ASCII */

keybase = KEY_ASCII;

break;

case 'b':      /* don't reset parity bit */

parity = 0;

break;

case 'c':      /* use CBC mode */

if (ISSET_MODE_ALGORITHM)

err(1, -1, "two modes of operation specified");

mode |= MODE_CBC;

break;

case 'e':      /* use ECB mode */

if (ISSET_MODE_ALGORITHM)

err(1, -1, "two modes of operation specified");

mode |= MODE_ECB;

break;

case 'F':      /* use alternative CFB mode */

if (ISSET_MODE_ALGORITHM)

err(1, -1, "two modes of operation specified");

mode |= MODE_CFBA;

if ((fbbits = setbits(optarg, 7)) > 56 || fbbits == 0)

err(1, -1, "-F: number must be 1-56 inclusive");

else if (fbbits == -1)

err(1, -1, "-F: number must be a multiple of 7");

break;

case 'f':      /* use CFB mode */

if (ISSET_MODE_ALGORITHM)

err(1, -1, "two modes of operation specified");

mode |= MODE_CFB;

if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0)

err(1, -1, "-f: number must be 1-64 inclusive");

else if (fbbits == -1)

err(1, -1, "-f: number must be a multiple of 8");

break;

case 'i':      /* decrypt */

if (ISSET_MODE_DIRECTION)

err(1, -1, "only one of -i and -m allowed");

mode |= MODE_DECRYPT;

break;

case 'm':      /* number of bits for MACing */

if (ISSET_MODE_DIRECTION)

err(1, -1, "only one of -i and -m allowed");

mode |= MODE_AUTHENTICATE;

if ((macbits = setbits(optarg, 1)) > 64)

err(1, -1, "-m: number must be 0-64 inclusive");

break;

case 'o':      /* use OFB mode */

if (ISSET_MODE_ALGORITHM)

err(1, -1, "two modes of operation specified");

mode |= MODE_OFB;

if ((fbbits = setbits(optarg, 8)) > 64 || fbbits == 0)

err(1, -1, "-o: number must be 1-64 inclusive");

else if (fbbits == -1)

err(1, -1, "-o: number must be a multiple of 8");

break;

case 'v':      /* set initialization vector */

cvtkey(BUFFER(ivec), optarg);

break;

default:       /* error */

n++;

break;

}

/*

* on error, quit

*/

if (n > 0)

exit(1);

/*

* if no direction set, default to encryption

*/

if (!ISSET_MODE_DIRECTION)

mode |= MODE_ENCRYPT;

if (!ISSET_MODE_ALGORITHM)

mode |= MODE_ECB;

/*

* pick up the key

* -- if there are no more arguments, prompt for it

* -- if there is 1 more argument, use it as the key

* -- if there are 2 or more arguments, error

*/

if (optind == nargs){

/*

* if the key's not ASCII, can't do this since

* only the first 8 chars are significant

*/

if (keybase != KEY_ASCII)

err(1, -1,

"you must enter non-ASCII keys on the command line");

/*

* get the key

*/

if ((p = getpass("Enter key: ")) == NULL)

err(1, -1, "no key given");

/*

* copy it, nul-padded, into the key area

*/

strncpy(BUFFER(msgbuf), p, 8);

}

else if (optind + 1 == nargs){

/*

* obtain the bit form of the key

* and hide it from a "ps"

*/

cvtkey(BUFFER(msgbuf), arglist[optind]);

arglist[optind] = keyrep;

}

else{

/*

* extra arguments -- bomb

*/

err(1, -1, "extraneous arguments");

}

/*

* main loop

*/

switch(mode){

case MODE_ECB|MODE_ENCRYPT:        /* encrypt using ECB mode */

inverse = 0;

makekey(msgbuf);

ecbenc();

break;

case MODE_ECB|MODE_DECRYPT:        /* decrypt using ECB mode */

inverse = 1;

makekey(msgbuf);

ecbdec();

break;

case MODE_ECB|MODE_AUTHENTICATE:     /* authenticate using ECB */

err(1, -1, "can't authenticate with ECB mode");

break;

case MODE_CBC|MODE_ENCRYPT:        /* encrypt using CBC mode */

inverse = 0;

makekey(msgbuf);

cbcenc();

break;

case MODE_CBC|MODE_DECRYPT:        /* decrypt using CBC mode */

inverse = 1;

makekey(msgbuf);

cbcdec();

break;

case MODE_CBC|MODE_AUTHENTICATE:     /* authenticate using CBC */

inverse = 0;

makekey(msgbuf);

cbcauth();

break;

case MODE_CFB|MODE_ENCRYPT:        /* encrypt using CFB mode */

inverse = 0;

makekey(msgbuf);

cfbenc();

break;

case MODE_CFB|MODE_DECRYPT:        /* decrypt using CFB mode */

inverse = 0;

makekey(msgbuf);

cfbdec();

break;

case MODE_CFB|MODE_AUTHENTICATE:     /* authenticate using CFB */

inverse = 0;

makekey(msgbuf);

cfbauth();

break;

case MODE_CFBA|MODE_ENCRYPT:       /* alternative CFB mode */

inverse = 0;

makekey(msgbuf);

cfbaenc();

break;

case MODE_CFBA|MODE_DECRYPT:       /* alternative CFB mode */

inverse = 0;

makekey(msgbuf);

cfbadec();

break;

case MODE_OFB|MODE_ENCRYPT:        /* encrypt using OFB mode */

inverse = 0;

makekey(msgbuf);

ofbenc();

break;

case MODE_OFB|MODE_DECRYPT:        /* decrypt using OFB mode */

inverse = 0;

makekey(msgbuf);

ofbdec();

break;

default:            /* unimplemented */

err(1, -1, "can't handle that yet");

break;

}

exit(0);

}

/*

* print a warning message and, possibly, terminate

*/

err(f, n, s)

int f;             /* >0 if fatal (status code), 0 if not */

int n;             /* offending block number */

char *s;       /* the message */

{

char tbuf[BUFSIZ];

if (n > 0)

(void) sprintf(tbuf, "%s (block %d)", progname, n);

else

(void) sprintf(tbuf, "%s", progname);

if (s == C_NULL)

perror(tbuf);

else

fprintf(stderr, "%s: %s\n", tbuf, s);

if (f > 0)

exit(f);

}

/*

* map a hex character to an integer

*/

int tohex(c)

char c;

{

switch(c){

case '0':      return(0x0);

case '1':      return(0x1);

case '2':      return(0x2);

case '3':      return(0x3);

case '4':      return(0x4);

case '5':      return(0x5);

case '6':      return(0x6);

case '7':      return(0x7);

case '8':      return(0x8);

case '9':      return(0x9);

case 'A': case 'a':     return(0xa);

case 'B': case 'b':     return(0xb);

case 'C': case 'c':     return(0xc);

case 'D': case 'd':     return(0xd);

case 'E': case 'e':     return(0xe);

case 'F': case 'f':     return(0xf);

}

/*

* invalid character

*/

return(-1);

}

/*

* convert the key to a bit pattern

*/

cvtkey(obuf, ibuf)

char *obuf;

char *ibuf;

{

register int i;             /* counter in a for loop */

int nbuf[16];          /* used for hes/key translation */

/*

* just switch on the key base

*/

switch(keybase){

case KEY_ASCII:              /* ascii to integer */

(void) strncpy(obuf, ibuf, 8);

return;

case KEY_DEFAULT:       /* tell from context */

/*

* leading '0x' or '0X' == hex key

*/

if (ibuf[0] == '0' && (ibuf[1] == 'x' || ibuf[1] == 'x')){

ibuf = &ibuf[2];

/*

* now translate it,m bombing on any illegal hex digit

*/

for(i = 0; ibuf[i] && i < 16; i++)

if ((nbuf[i] = tohex(ibuf[i])) == -1)

err(1, -1, "bad hex digit in key");

while(i < 16)

nbuf[i++] = 0;

for(i = 0; i < 8; i++)

obuf[i] = ((nbuf[2*i]&0xf)<<4)|

(nbuf[2*i+1]&0xf);

parity = 0;

return;

}

/*

* no special leader -- ASCII

*/

(void) strncpy(obuf, ibuf, 8);

}

}

/*

* convert an ASCII string into a decimal number:

* 1. must be between 0 and 64 inclusive

* 2. must be a valid decimal number

* 3. must be a multiple of mult

*/

setbits(s, mult)

char *s;

{

register char *p;

register int n = 0;

/*

* skip white space

*/

while (isspace(*s))

s++;

/*

* get the integer

*/

for(p = s; *p; p++){

if (isdigit(*p))

n = n * 10 + *p - '0';

else{

err(1, -1, "bad decimal digit in MAC length");

}

}

/*

* be sure it's a multiple of mult

*/

return((n % mult != 0) ? -1 : n);

}

/*****************

* DES FUNCTIONS *

*****************/

/*

* This sets the DES key and (if you're using the deszip version)

* the direction of the transformation.  Note there are two ways

* to map the 64-bit key onto the 56 bits that the key schedule

* generation routines use: the old way, which just uses the user-

* supplied 64 bits as is, and the new way, which resets the parity

* bit to be the same as the low-order bit in each character.  The

* new way generates a greater variety of key schedules, since many

* systems set the parity (high) bit of each character to 0, and the

* DES ignores the low order bit of each character.

*/

makekey(buf)

Desbuf buf;             /* key block */

{

register int i;             /* counter in a for loop */

/*

* if using new key arrangement, reset the parity bit

* to be the same as the low-order bit

*/

if (parity){

for(i = 0; i < 8; i++)

UCHAR(buf, i) = (UCHAR(buf, i)&0177)|

((UCHAR(buf, i)&01)<<7);

}

/*

* Make the key schedule

*/

DES_KEY(UBUFFER(buf));

}

/*

* This encrypts using the Electronic Code Book mode of DES

*/

ecbenc()

{

register int n;         /* number of bytes actually read */

register int bn;   /* block number */

Desbuf msgbuf;        /* I/O buffer */

for(bn = 0; (n = READ(BUFFER(msgbuf),  8)) == 8; bn++){

/*

* do the transformation

*/

DES_XFORM(UBUFFER(msgbuf));

WRITE(BUFFER(msgbuf), 8);

}

/*

* at EOF or last block -- in either ase, the last byte contains

* the character representation of the number of bytes in it

*/

bn++;

MEMZERO(&CHAR(msgbuf, n), 8 - n);

CHAR(msgbuf, 7) = '0' + n;

DES_XFORM(UBUFFER(msgbuf));

WRITE(BUFFER(msgbuf), 8);

}

/*

* This decrypts using the Electronic Code Book mode of DES

*/

ecbdec()

{

register int n;         /* number of bytes actually read */

register int c;         /* used to test for EOF */

register int bn;   /* block number */

Desbuf msgbuf;        /* I/O buffer */

for(bn = 1; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++){

/*

* do the transformation

*/

DES_XFORM(UBUFFER(msgbuf));

/*

* if the last one, handle it specially

*/

if ((c = getchar()) == EOF){

if ((n = (CHAR(msgbuf, 7) - '0')) < 0 || n > 7)

err(1, bn,

"decryption failed (block corrupted)");

}

else

(void) ungetc(c, stdin);

WRITE(BUFFER(msgbuf), n);

}

if (n > 0)

err(1, bn, "decryption failed (incomplete block)");

}

/*

* This encrypts using the Cipher Block Chaining mode of DES

*/

cbcenc()

{

register int n;         /* number of bytes actually read */

register int bn;   /* block number */

Desbuf msgbuf;        /* I/O buffer */

/*

* do the transformation

*/

for(bn = 1; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++){

for(n = 0; n < 8; n++)

CHAR(msgbuf, n) ^= CHAR(ivec, n);

DES_XFORM(UBUFFER(msgbuf));

MEMCPY(BUFFER(ivec), BUFFER(msgbuf), 8);

WRITE(BUFFER(msgbuf), 8);

}

/*

* at EOF or last block -- in either case, the last byte contains

* the character representation of the number of bytes in it

*/

bn++;

MEMZERO(&CHAR(msgbuf, n), 8 - n);

CHAR(msgbuf, 7) = '0' + n;

for(n = 0; n < 8; n++)

CHAR(msgbuf, n) ^= CHAR(ivec, n);

DES_XFORM(UBUFFER(msgbuf));

WRITE(BUFFER(msgbuf), 8);

}

/*

* This decrypts using the Cipher Block Chaining mode of DES

*/

cbcdec()

{

register int n;         /* number of bytes actually read */

Desbuf msgbuf;        /* I/O buffer */

Desbuf ibuf;          /* temp buffer for initialization vector */

register int c;         /* used to test for EOF */

register int bn;   /* block number */

for(bn = 0; (n = READ(BUFFER(msgbuf), 8)) == 8; bn++){

/*

* do the transformation

*/

MEMCPY(BUFFER(ibuf), BUFFER(msgbuf), 8);

DES_XFORM(UBUFFER(msgbuf));

for(c = 0; c < 8; c++)

UCHAR(msgbuf, c) ^= UCHAR(ivec, c);

MEMCPY(BUFFER(ivec), BUFFER(ibuf), 8);

/*

* if the last one, handle it specially

*/

if ((c = getchar()) == EOF){

if ((n = (CHAR(msgbuf, 7) - '0')) < 0 || n > 7)

err(1, bn,

"decryption failed (block corrupted)");

}

else

(void) ungetc(c, stdin);

WRITE(BUFFER(msgbuf), n);

}

if (n > 0)

err(1, bn, "decryption failed (incomplete block)");

}

/*

* This authenticates using the Cipher Block Chaining mode of DES

*/

cbcauth()

{

register int n;         /* number of bytes actually read */

Desbuf msgbuf;        /* I/O buffer */

Desbuf encbuf;        /* encryption buffer */

/*

* do the transformation

* note we DISCARD the encrypted block;

* we only care about the last one

*/

while ((n = READ(BUFFER(msgbuf), 8)) == 8){

for(n = 0; n < 8; n++)

CHAR(encbuf, n) = CHAR(msgbuf, n) ^ CHAR(ivec, n);

DES_XFORM(UBUFFER(encbuf));

MEMCPY(BUFFER(ivec), BUFFER(encbuf), 8);

}

/*

* now compute the last one, right padding with '\0' if need be

*/

if (n > 0){

MEMZERO(&CHAR(msgbuf, n), 8 - n);

for(n = 0; n < 8; n++)

CHAR(encbuf, n) = CHAR(msgbuf, n) ^ CHAR(ivec, n);

DES_XFORM(UBUFFER(encbuf));

}

/*

* drop the bits

* we write chars until fewer than 7 bits,

* and then pad the last one with 0 bits

*/

for(n = 0; macbits > 7; n++, macbits -= 8)

putchar(CHAR(encbuf, n));

if (macbits > 0){

CHAR(msgbuf, 0) = 0x00;

for(n = 0; n < macbits; n++)

CHAR(msgbuf, 0) |= (CHAR(encbuf, n)&bits
);

putchar(CHAR(msgbuf, 0));

}

}

/*

* This encrypts using the Cipher FeedBack mode of DES

*/

cfbenc()

{

register int n;         /* number of bytes actually read */

register int nbytes;     /* number of bytes to read */

register int bn;   /* block number */

char ibuf[8];       /* input buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 8;

/*

* do the transformation

*/

for(bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < 8 - nbytes; n++)

UCHAR(ivec, n) = UCHAR(ivec, n+nbytes);

for(n = 0; n < nbytes; n++)

UCHAR(ivec, 8-nbytes+n) = ibuf
^ UCHAR(msgbuf, n);

WRITE(&CHAR(ivec, 8-nbytes), nbytes);

}

/*

* at EOF or last block -- in either case, the last byte contains

* the character representation of the number of bytes in it

*/

bn++;

MEMZERO(&ibuf
, nbytes - n);

ibuf[nbytes - 1] = '0' + n;

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < nbytes; n++)

ibuf
^= UCHAR(msgbuf, n);

WRITE(ibuf, nbytes);

}

/*

* This decrypts using the Cipher Block Chaining mode of DES

*/

cfbdec()

{

register int n;         /* number of bytes actually read */

register int c;         /* used to test for EOF */

register int nbytes;     /* number of bytes to read */

register int bn;   /* block number */

char ibuf[8];       /* input buffer */

char obuf[8];       /* output buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 8;

/*

* do the transformation

*/

for(bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(c = 0; c < 8 - nbytes; c++)

CHAR(ivec, c) = CHAR(ivec, c+nbytes);

for(c = 0; c < nbytes; c++){

CHAR(ivec, 8-nbytes+c) = ibuf[c];

obuf[c] = ibuf[c] ^ UCHAR(msgbuf, c);

}

/*

* if the last one, handle it specially

*/

if ((c = getchar()) == EOF){

if ((n = (obuf[nbytes-1] - '0')) < 0

|| n > nbytes-1)

err(1, bn,

"decryption failed (block corrupted)");

}

else

(void) ungetc(c, stdin);

WRITE(obuf, n);

}

if (n > 0)

err(1, bn, "decryption failed (incomplete block)");

}

/*

* This encrypts using the alternative Cipher FeedBack mode of DES

*/

cfbaenc()

{

register int n;         /* number of bytes actually read */

register int nbytes;     /* number of bytes to read */

register int bn;   /* block number */

char ibuf[8];       /* input buffer */

char obuf[8];       /* output buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 7;

/*

* do the transformation

*/

for(bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < 8 - nbytes; n++)

UCHAR(ivec, n) = UCHAR(ivec, n+nbytes);

for(n = 0; n < nbytes; n++)

UCHAR(ivec, 8-nbytes+n) = (ibuf
^ UCHAR(msgbuf, n))

|0200;

for(n = 0; n < nbytes; n++)

obuf
= CHAR(ivec, 8-nbytes+n)&0177;

WRITE(obuf, nbytes);

}

/*

* at EOF or last block -- in either case, the last byte contains

* the character representation of the number of bytes in it

*/

bn++;

MEMZERO(&ibuf
, nbytes - n);

ibuf[nbytes - 1] = ('0' + n)|0200;

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < nbytes; n++)

ibuf
^= UCHAR(msgbuf, n);

WRITE(ibuf, nbytes);

}

/*

* This decrypts using the alternative Cipher Block Chaining mode of DES

*/

cfbadec()

{

register int n;         /* number of bytes actually read */

register int c;         /* used to test for EOF */

register int nbytes;     /* number of bytes to read */

register int bn;   /* block number */

char ibuf[8];       /* input buffer */

char obuf[8];       /* output buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 7;

/*

* do the transformation

*/

for(bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(c = 0; c < 8 - nbytes; c++)

CHAR(ivec, c) = CHAR(ivec, c+nbytes);

for(c = 0; c < nbytes; c++){

CHAR(ivec, 8-nbytes+c) = ibuf[c]|0200;

obuf[c] = (ibuf[c] ^ UCHAR(msgbuf, c))&0177;

}

/*

* if the last one, handle it specially

*/

if ((c = getchar()) == EOF){

if ((n = (obuf[nbytes-1] - '0')) < 0

|| n > nbytes-1)

err(1, bn,

"decryption failed (block corrupted)");

}

else

(void) ungetc(c, stdin);

WRITE(obuf, n);

}

if (n > 0)

err(1, bn, "decryption failed (incomplete block)");

}

/*

* This encrypts using the Output FeedBack mode of DES

*/

ofbenc()

{

register int n;         /* number of bytes actually read */

register int c;         /* used to test for EOF */

register int nbytes;     /* number of bytes to read */

register int bn;   /* block number */

char ibuf[8];       /* input buffer */

char obuf[8];       /* output buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 8;

/*

* do the transformation

*/

for(bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < 8 - nbytes; n++)

UCHAR(ivec, n) = UCHAR(ivec, n+nbytes);

for(n = 0; n < nbytes; n++){

UCHAR(ivec, 8-nbytes+n) = UCHAR(msgbuf, n);

obuf
= ibuf
^ UCHAR(msgbuf, n);

}

WRITE(obuf, nbytes);

}

/*

* at EOF or last block -- in either case, the last byte contains

* the character representation of the number of bytes in it

*/

bn++;

MEMZERO(&ibuf
, nbytes - n);

ibuf[nbytes - 1] = '0' + n;

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(c = 0; c < nbytes; c++)

ibuf[c] ^= UCHAR(msgbuf, c);

WRITE(ibuf, nbytes);

}

/*

* This decrypts using the Output Block Chaining mode of DES

*/

ofbdec()

{

register int n;         /* number of bytes actually read */

register int c;         /* used to test for EOF */

register int nbytes;     /* number of bytes to read */

register int bn;   /* block number */

char ibuf[8];       /* input buffer */

char obuf[8];       /* output buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 8;

/*

* do the transformation

*/

for(bn = 1; (n = READ(ibuf, nbytes)) == nbytes; bn++){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(c = 0; c < 8 - nbytes; c++)

CHAR(ivec, c) = CHAR(ivec, c+nbytes);

for(c = 0; c < nbytes; c++){

CHAR(ivec, 8-nbytes+c) = UCHAR(msgbuf, c);

obuf[c] = ibuf[c] ^ UCHAR(msgbuf, c);

}

/*

* if the last one, handle it specially

*/

if ((c = getchar()) == EOF){

if ((n = (obuf[nbytes-1] - '0')) < 0

|| n > nbytes-1)

err(1, bn,

"decryption failed (block corrupted)");

}

else

(void) ungetc(c, stdin);

/*

* dump it

*/

WRITE(obuf, n);

}

if (n > 0)

err(1, bn, "decryption failed (incomplete block)");

}

/*

* This authenticates using the Cipher FeedBack mode of DES

*/

cfbauth()

{

register int n;         /* number of bytes actually read */

register int nbytes;     /* number of bytes to read */

char ibuf[8];       /* input buffer */

Desbuf msgbuf;        /* encryption buffer */

/*

* do things in bytes, not bits

*/

nbytes = fbbits / 8;

/*

* do the transformation

*/

while((n = READ(ibuf, nbytes)) == nbytes){

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < 8 - nbytes; n++)

UCHAR(ivec, n) = UCHAR(ivec, n+nbytes);

for(n = 0; n < nbytes; n++)

UCHAR(ivec, 8-nbytes+n) = ibuf
^ UCHAR(msgbuf, n);

}

/*

* at EOF or last block -- in either case, the last byte contains

* the character representation of the number of bytes in it

*/

MEMZERO(&ibuf
, nbytes - n);

ibuf[nbytes - 1] = '0' + n;

MEMCPY(BUFFER(msgbuf), BUFFER(ivec), 8);

DES_XFORM(UBUFFER(msgbuf));

for(n = 0; n < nbytes; n++)

ibuf
^= UCHAR(msgbuf, n);

/*

* drop the bits

* we write chars until fewer than 7 bits,

* and then pad the last one with 0 bits

*/

for(n = 0; macbits > 7; n++, macbits -= 8)

putchar(CHAR(msgbuf, n));

if (macbits > 0){

CHAR(msgbuf, 0) = 0x00;

for(n = 0; n < macbits; n++)

CHAR(msgbuf, 0) |= (CHAR(msgbuf, n)&bits
);

putchar(CHAR(msgbuf, 0));

}

}

#ifdef ALONE

/*

* change from 8 bits/Uchar to 1 bit/Uchar

*/

expand(from, to)

Desbuf from;            /* 8bit/unsigned char string */

char to[64];            /* 1bit/char string */

{

register int i, j;      /* counters in for loop */

for(i = 0; i < 8; i++)

for(j = 0; j < 8; j++)

to[i*8+j] = (CHAR(from, i)>>(7-j))&01;

}

/*

* change from 1 bit/char to 8 bits/Uchar

*/

compress(from, to)

char from[64];           /* 1bit/char string */

Desbuf to;              /* 8bit/unsigned char string */

{

register int i, j;      /* counters in for loop */

for(i = 0; i < 8; i++){

CHAR(to, i) = 0;

for(j = 0; j < 8; j++)

CHAR(to, i) = (from[i*8+j]<<(7-j))|CHAR(to, i);

}

}

#endif

Elliptic Curves

/************************************************************************

*                                                                       *

*       Elliptic curves over Galois Fields.  These routines find points *

*  on a curve, add and double points for type 1 optimal normal bases.   *

*                                                                       *

*    For succint explanaition, see Menezes, page 92                  *

*                                                                       *

************************************************************************/

#include <stdio.h>

#include "bigint.h"

#include "eliptic.h"

/************************************************************************

*  Note that the following is obvious to mathematicians.  I thought it  *

*  was pretty cool when I discovered it myself, <sigh>.              *

*                                                                       *

*       Routine to solve quadradic equation.  Enter with coeficients    *

*  a and b and it returns solutions y[2]: y^2 + ay + b = 0.             *

*  If Tr(b/a^2) != 0, returns y=0 and error code 1.                     *

*  If Tr(b/a^2) == 0, returns y[2] and error code 0.                    *

*  If solution fails, returns y=0 and error code 2.                     *

*                                                                       *

*      Algorithm used based on normal basis GF math.  Since (a+b)^2 =   *

*  a^2 + b^2 it follows that (a+b)^.5 = a^.5 + b^.5.  Note that squaring*

*  is a left shift and rooting is a right shift in a normal basis.      *

*  Transforming the source equation with y = ax and dividing by a^2     *

*  gives:                                                               *

*               x^2 + x + b/a^2 = 0                                     *

*                                                                       *

*       or      x = x^.5 + (b/a^2)^.5                                   *

*                                                                       *

*  Let k_i = the ith significant bit of (b/a^2)^.5 and                  *

*      x_i = the ith significant bit of x.                              *

*  The above equation is equivelent to a bitwise representation as      *

*                                                                       *

*               x_i = x_(i+1) + k_i                                     *

*       or                                                              *

*               x(i+1) = x_i + k_i.                                     *

*                                                                       *

*  Since both x and x+1 are solutions, and 1 is represented by all      *

*  bits set in a normal basis, we can start with x_0 = 0 or 1 at our    *

*  pleasure and use the recursion relation to discover every bit of x.  *

*  The answer is then ax and ax+a returned in y[0] and y[1] respectively*

*  If the sum of x_(n-1) + k_(n-1) != x_0, returns error code 2 and     *

*  y = 0.                                                               *

*                                                                       *

*       error code                      returns                         *

*          0                    y[0] and y[1] values                    *

*          1                    y[0] = y[1] = 0                         *

*          2                    mathematicly impossible !!!!            *

*                                                                       *

************************************************************************/

extern  ELEMENT  mask_table[WORDSIZE];

extern  void opt_inv(), rot_left(), rot_right(), null(), opt_mul();

extern  void big_print(), copy();

int gf_quadradic(a, b, y)

BIGINT *a, *b, *y;

{

INDEX   i, l, bits;

BIGINT  x, k, a2;

ELEMENT  r, t, mask;

/*  test for b=0.  Won't work if it is.  */

l = 1;

for (i=STRTPOS; i<MAXLONG; i++) {

if (b->b[i] == 0) continue;

else {

l = 0;

break;

}

}

if (l) {

null(&y[0]);

null(&y[1]);

return(1);

}

/*  find a^-2  */

opt_inv( a, &a2);

rot_left(&a2);

/*  find k=(b/a^2)^.5 */

opt_mul( b, &a2, &k);

rot_right(&k);

r = 0;

/*  check that Tr(k) is zero.  Combine all words first. */

for (i=STRTPOS; i<MAXLONG; i++)

r ^= k.b[i];

/*  take trace of word, combining half of all the bits each time */

for (bits = WORDSIZE/2; bits > 0; bits /= 2)

r = ((r & mask_table[bits]) ^ (r >> bits));

/*  if not zero, return error code 1.  */

if (r) {

null(&y[0]);

null(&y[1]);

return(1);

}

/*  point is valid, proceed with solution.  mask points to bit i,

which is known, in x bits previously found and k (=b/a^2).  */

null(&x);

mask = 1;

for (bits=0; bits < NUMBITS ; bits++) {

/* source long word could be different than destination  */

i = LONGPOS - bits/WORDSIZE;

l = LONGPOS - (bits + 1)/WORDSIZE;

/*  use present bits to compute next one */

r = k.b[i] & mask;

t = x.b[i] & mask;

r ^= t;

/*  same word, so just shift result up */

if ( l == i ) {

r <<= 1;

x.b[l] |= r;

mask <<= 1;

} else {

/*  different word, reset mask and use a 1 */

mask = 1;

if (r) x.b[l] = 1;

}

}

/*  test that last bit generates a zero */

r = k.b[STRTPOS] & UPRBIT;

t = x.b[STRTPOS] & UPRBIT;

if ( r^t ) {

null(&y[0]);

null(&y[1]);

return(2);

}

/*  convert solution back via y = ax */

opt_mul(a, &x, &y[0]);

/*  and create complementary soultion y = ax + a */

null (&y[1]);

for (i = STRTPOS; i < MAXLONG;  i++)

y[1].b[i] = y[0].b[i] ^ a->b[i];

/*  no errors, bye!  */

return(0);

}

/*  compute R.H.S. f(x) = x^3 + a2*x^2 + a6

curv.form = 0 implies a2 = 0, so no extra multiply.

curv.form = 1 is the "twist" curve.

*/

void fofx(x, curv, f)

BIGINT * x, * f;

CURVE * curv;

{

BIGINT x2,x3;

INDEX i;

copy(x, &x2);

rot_left(&x2);

opt_mul(x, &x2, &x3);

if (curv->form) opt_mul(&x2, &curv->a2, f);

else null(f);

for (i = STRTPOS; i < MAXLONG; i++)

f->b[i] ^= (x3.b[i] ^ curv->a6.b[i]);

}

/****************************************************************************

*                                                                           *

*   Implement elliptic curve point addition for optimal normal basis form.  *

*  This follows R. Schroeppel, H. Orman, S. O'Mally, "Fast Key Exchange with*

*  Elliptic Curve Systems", CRYPTO '95, TR-95-03, Univ. of Arizona, Comp.   *

*  Science Dept.                                                            *

*                                                                           *

*   This version is faster for inversion processes requiring fewer          *

*  multiplies than projective math version.  For NUMBITS = 148 or 226 this  *

*  is the case because only 10 multiplies are required for inversion but    *

*  15 multiplies for projective math.  I leave it as a paper to be written  *

*  [HINT!!] to propagate TR-95-03 to normal basis inversion.  In that case  *

*  inversion will require order 2 multiplies and this method would be far   *

*  superior to projective coordinates.                                      *

****************************************************************************/

void esum (p1, p2, p3, curv)

POINT   *p1, *p2, *p3;

CURVE   *curv;

{

register INDEX   i;

BIGINT  x1, y1, lmda, onex, lmda2;

/*  compute lambda = (y_1 + y_2)/(x_1 + x_2)  */

null(&x1);

null(&y1);

SUMLOOP(i) {

x1.b[i] = p1->x.b[i] ^ p2->x.b[i];

y1.b[i] = p1->y.b[i] ^ p2->y.b[i];

}

opt_inv( &x1, &onex);

opt_mul( &onex, &y1, &lmda);

copy( &lmda, &lmda2);

rot_left(&lmda2);

/*  with lambda and lamda^2, compute x_3  */

if (curv->form)

SUMLOOP (i)

p3->x.b[i] = lmda.b[i] ^ lmda2.b[i] ^ p1->x.b[i] ^ p2->x.b[i]

^ curv->a2.b[i];

else

SUMLOOP (i)

p3->x.b[i] = lmda.b[i] ^ lmda2.b[i] ^ p1->x.b[i] ^ p2->x.b[i];

/*  next find y_3  */

SUMLOOP (i) x1.b[i] = p1->x.b[i] ^ p3->x.b[i];

opt_mul( &x1, &lmda, &lmda2);

SUMLOOP (i) p3->y.b[i] = lmda2.b[i] ^ p3->x.b[i] ^ p1->y.b[i];

}

/*  elliptic curve doubling routine for Schroeppel's algorithm over normal

basis.  Enter with p1, p3 as source and destination as well as curv

to operate on.  Returns p3 = 2*p1.

*/

void edbl (p1, p3, curv)

POINT *p1, *p3;

CURVE *curv;

{

BIGINT  x1, y1, lmda, lmda2, t1;

register INDEX   i;

/*  first compute lambda = x + y/x  */

opt_inv( &p1->x, &x1);

opt_mul( &x1, &p1->y, &y1);

SUMLOOP (i) lmda.b[i] = p1->x.b[i] ^ y1.b[i];

/*  next compute x_3  */

copy( &lmda, &lmda2);

rot_left(&lmda2);

if(curv->form)

SUMLOOP (i) p3->x.b[i] = lmda.b[i] ^ lmda2.b[i] ^ curv->a2.b[i];

else

SUMLOOP (i) p3->x.b[i] = lmda.b[i] ^ lmda2.b[i];

/*  and lastly y_3  */

one( &y1);

SUMLOOP (i) y1.b[i] ^= lmda.b[i];

opt_mul( &y1, &p3->x, &t1);

copy( &p1->x, &x1);

rot_left( &x1);

SUMLOOP (i) p3->y.b[i] = x1.b[i] ^ t1.b[i];

}

/*  subtract two points on a curve.  just negates p2 and does a sum.

Returns p3 = p1 - p2 over curv.

*/

void esub (p1, p2, p3, curv)

POINT   *p1, *p2, *p3;

CURVE   *curv;

{

POINT   negp;

INDEX   i;

copy ( &p2->x, &negp.x);

null (&negp.y);

SUMLOOP(i) negp.y.b[i] = p2->x.b[i] ^ p2->y.b[i];

esum (p1, &negp, p3, curv);

}

/*  need to move points around, not just values.  Optimize later.  */

void copy_point (p1, p2)

POINT *p1, *p2;

{

copy (&p1->x, &p2->x);

copy (&p1->y, &p2->y);

}

/*  Routine to compute kP where k is an integer (base 2, not normal basis)

and P is a point on an elliptic curve.  This routine assumes that K

is representable in the same bit field as x, y or z values of P.

This is for simplicity, larger or smaller fields can be independently

implemented.

Enter with: integer k, source point P, curve to compute over (curv) and

Returns with: result point R.

Reference: Koblitz, "CM-Curves with good Cryptografic Properties",

Springer-Verlag LNCS #576, p279 (pg 284 really), 1992

*/

ELEMENT     bit_table[32] = {1, 2, 4, 8, 16, 32, 64, 128, 256,

0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000,

0x10000, 0x20000, 0x40000, 0x80000,

0x100000, 0x200000, 0x400000, 0x800000,

0x1000000, 0x2000000, 0x4000000, 0x8000000,

0x10000000, 0x20000000, 0x40000000, 0x80000000 };

void  elptic_mul(k, p, r, curv)

BIGINT    *k;

POINT     *p, *r;

CURVE     *curv;

{

char      blncd[NUMBITS+1];

ELEMENT        wordptr, mskindx, sequnce;

long      bit_count;

POINT          temp;

/*  scan across k from right to left to expand bits to chars  */

for (bit_count = 0; bit_count < NUMBITS; bit_count++) {

wordptr = LONGPOS - bit_count/WORDSIZE;

mskindx = bit_count % WORDSIZE;

if (k->b[wordptr] & bit_table[mskindx]) blncd[bit_count] = 1;

else blncd[bit_count] = 0;

}

blncd[NUMBITS] = 0;

/*  Next convert balanced array to ballanced representation  */

/*  sequence flag used for multiple 1's being switched to 0's.  */

sequnce = 0;

bit_count = 0;

while (bit_count <= NUMBITS) {

if ( blncd[bit_count]) {

if (sequnce)      /*  in middle of 1's sequence */

blncd[bit_count] = 0;

else if (blncd[bit_count+1]) {

sequnce = 1;        /*  next bit also set, begin sequnce */

blncd[bit_count] = -1;

}

bit_count++;

} else {

if (sequnce) {        /* last bit of sequence */

blncd[bit_count] = 1;

sequnce = 0;

} else

bit_count++;

}

}

/*  now follow ballanced representation and compute kP  */

bit_count = NUMBITS;

while (!blncd[bit_count] && bit_count >= 0) bit_count--; /* find first bit */

if (bit_count < 0) {

null (&r->x);

null (&r->y);

return;

}

copy_point(p,r);         /* first bit always set */

while (bit_count > 0) {

edbl(r, &temp, curv);

bit_count--;

switch (blncd[bit_count]) {

case 1: esum (p, &temp, r, curv);

break;

case -1: esub (&temp, p, r, curv);

break;

case 0: copy_point (&temp, r);

}

}

}

/*  One is not what it appears to be.  In any normal basis, "1" is the sum of

all powers of the generator.  So this routine puts ones to fill the number size

being used in the address of the BIGINT supplied.  */

void one (place)

BIGINT *place;

{

INDEX i;

SUMLOOP(i) place->b[i] = -1L;

place->b[STRTPOS] &= UPRMASK;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: