Source Code for Cryptography (Just a touch)
md5.h (the
include file for the above C code)
Karn
Encryption: Symmetric Secret with 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 -- 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
* 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 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);
}
/* 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
/*
* 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[n]);
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[n] ^
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[n],
nbytes - n);
ibuf[nbytes - 1] = '0'
+ n;
MEMCPY(BUFFER(msgbuf),
BUFFER(ivec), 8);
DES_XFORM(UBUFFER(msgbuf));
for(n = 0; n <
nbytes; n++)
ibuf[n] ^= 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[n] ^
UCHAR(msgbuf, n))
|0200;
for(n = 0; n <
nbytes; n++)
obuf[n] = 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[n],
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[n] ^= 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[n] = ibuf[n] ^ 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[n],
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[n] ^
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[n],
nbytes - n);
ibuf[nbytes - 1] = '0'
+ n;
MEMCPY(BUFFER(msgbuf),
BUFFER(ivec), 8);
DES_XFORM(UBUFFER(msgbuf));
for(n = 0; n <
nbytes; n++)
ibuf[n] ^= 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[n]);
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
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;
}
}