Reconstruction of des.exe/undes.exe
This commit is contained in:
+410
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
* idea.c - C source code for IDEA block cipher.
|
||||
* IDEA (International Data Encryption Algorithm), formerly known as
|
||||
* IPES (Improved Proposed Encryption Standard).
|
||||
* Algorithm developed by Xuejia Lai and James L. Massey, of ETH Zurich.
|
||||
* This implementation modified and derived from original C code
|
||||
* developed by Xuejia Lai.
|
||||
* Zero-based indexing added, names changed from IPES to IDEA.
|
||||
* CFB functions added. Random number routines added.
|
||||
*
|
||||
* Extensively optimized and restructured by Colin Plumb.
|
||||
*
|
||||
* There are two adjustments that can be made to this code to
|
||||
* speed it up. Defaults may be used for PCs. Only the -DIDEA32
|
||||
* pays off significantly if selectively set or not set.
|
||||
* Experiment to see what works best for your machine.
|
||||
*
|
||||
* Multiplication: default is inline, -DAVOID_JUMPS uses a
|
||||
* different version that does not do any conditional
|
||||
* jumps (a few percent worse on a SPARC), while
|
||||
* -DSMALL_CACHE takes it out of line to stay
|
||||
* within a small on-chip code cache.
|
||||
* Variables: normally, 16-bit variables are used, but some
|
||||
* machines (notably RISCs) do not have 16-bit registers,
|
||||
* so they do a great deal of masking. -DIDEA32 uses "int"
|
||||
* register variables and masks explicitly only where
|
||||
* necessary. On a SPARC, for example, this boosts
|
||||
* performace by 30%.
|
||||
*
|
||||
* The IDEA(tm) block cipher is covered by patents held by ETH and a
|
||||
* Swiss company called Ascom-Tech AG. The Swiss patent number is
|
||||
* PCT/CH91/00117, the European patent number is EP 0 482 154 B1, and
|
||||
* the U.S. patent number is US005214703. IDEA(tm) is a trademark of
|
||||
* Ascom-Tech AG. There is no license fee required for noncommercial
|
||||
* use. Commercial users may obtain licensing details from Dieter
|
||||
* Profos, Ascom Tech AG, Solothurn Lab, Postfach 151, 4502 Solothurn,
|
||||
* Switzerland, Tel +41 65 242885, Fax +41 65 235761.
|
||||
*
|
||||
* The IDEA block cipher uses a 64-bit block size, and a 128-bit key
|
||||
* size. It breaks the 64-bit cipher block into four 16-bit words
|
||||
* because all of the primitive inner operations are done with 16-bit
|
||||
* arithmetic. It likewise breaks the 128-bit cipher key into eight
|
||||
* 16-bit words.
|
||||
*
|
||||
* For further information on the IDEA cipher, see the book:
|
||||
* Xuejia Lai, "On the Design and Security of Block Ciphers",
|
||||
* ETH Series on Information Processing (ed. J.L. Massey) Vol 1,
|
||||
* Hartung-Gorre Verlag, Konstanz, Switzerland, 1992. ISBN
|
||||
* 3-89191-573-X.
|
||||
*
|
||||
* This code runs on arrays of bytes by taking pairs in big-endian
|
||||
* order to make the 16-bit words that IDEA uses internally. This
|
||||
* produces the same result regardless of the byte order of the
|
||||
* native CPU.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#ifdef _MSC_VER
|
||||
#include "../crypt.h"
|
||||
#include "idea.h"
|
||||
#else
|
||||
#include "crypt.h"
|
||||
#include "idea/idea.h"
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef BIG_ENDIAN /* This code uses slightly different names */
|
||||
#define HIGHFIRST
|
||||
#endif /* BIG_ENDIAN */
|
||||
|
||||
#ifdef IDEA32 /* Use >16-bit temporaries */
|
||||
#define low16(x) ((x) & 0xFFFF)
|
||||
typedef unsigned int uint16; /* at LEAST 16 bits, maybe more */
|
||||
#else
|
||||
#define low16(x) (x) /* this is only ever applied to uint16's */
|
||||
typedef word16 uint16;
|
||||
#endif
|
||||
|
||||
#ifdef _GNUC_
|
||||
/* __const__ simply means there are no side effects for this function,
|
||||
* which is useful info for the gcc optimizer
|
||||
*/
|
||||
#define CONST __const__
|
||||
#else
|
||||
#define CONST
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Multiplication, modulo (2**16)+1
|
||||
* Note that this code is structured on the assumption that
|
||||
* untaken branches are cheaper than taken branches, and the
|
||||
* compiler doesn't schedule branches.
|
||||
*/
|
||||
#ifdef SMALL_CACHE
|
||||
CONST static uint16
|
||||
mul(register uint16 a, register uint16 b)
|
||||
{
|
||||
register word32 p;
|
||||
|
||||
p = (word32)a * b;
|
||||
if (p) {
|
||||
b = low16(p);
|
||||
a = p>>16;
|
||||
return (b - a) + (b < a);
|
||||
} else if (a) {
|
||||
return 1-b;
|
||||
} else {
|
||||
return 1-a;
|
||||
}
|
||||
} /* mul */
|
||||
#endif /* SMALL_CACHE */
|
||||
|
||||
/*
|
||||
* Compute the multiplicative inverse of x, modulo 65537, using Euclid's
|
||||
* algorithm. It is unrolled twice to avoid swapping the registers each
|
||||
* iteration, and some subtracts of t have been changed to adds.
|
||||
*/
|
||||
CONST static uint16
|
||||
mulInv(uint16 x)
|
||||
{
|
||||
uint16 t0, t1;
|
||||
uint16 q, y;
|
||||
|
||||
if (x <= 1)
|
||||
return x; /* 0 and 1 are self-inverse */
|
||||
t1 = 0x10001L / x; /* Since x >= 2, this fits into 16 bits */
|
||||
y = 0x10001L % x;
|
||||
if (y == 1)
|
||||
return ( uint16 ) low16(1-t1);
|
||||
t0 = 1;
|
||||
do {
|
||||
q = x / y;
|
||||
x = x % y;
|
||||
t0 += q * t1;
|
||||
if (x == 1)
|
||||
return t0;
|
||||
q = y / x;
|
||||
y = y % x;
|
||||
t1 += q * t0;
|
||||
} while (y != 1);
|
||||
return ( uint16 ) low16(1-t1);
|
||||
} /* mukInv */
|
||||
|
||||
/*
|
||||
* Expand a 128-bit user key to a working encryption key EK
|
||||
*/
|
||||
void
|
||||
ideaExpandKey(byte const *userkey, word16 *EK)
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for (j=0; j<8; j++) {
|
||||
EK[j] = (userkey[0]<<8) + userkey[1];
|
||||
userkey += 2;
|
||||
}
|
||||
for (i=0; j < IDEAKEYLEN; j++) {
|
||||
i++;
|
||||
EK[i+7] = (EK[i & 7] << 9) | (EK[i+1 & 7] >> 7);
|
||||
EK += i & 8;
|
||||
i &= 7;
|
||||
}
|
||||
} /* ideaExpandKey */
|
||||
|
||||
/*
|
||||
* Compute IDEA decryption key DK from an expanded IDEA encryption key EK
|
||||
* Note that the input and output may be the same. Thus, the key is
|
||||
* inverted into an internal buffer, and then copied to the output.
|
||||
*/
|
||||
void
|
||||
#ifdef _DCC
|
||||
ideaInvertKey(word16 *EK, word16 DK[IDEAKEYLEN])
|
||||
#else
|
||||
ideaInvertKey(word16 const *EK, word16 DK[IDEAKEYLEN])
|
||||
#endif
|
||||
{
|
||||
int i;
|
||||
uint16 t1, t2, t3;
|
||||
word16 temp[IDEAKEYLEN];
|
||||
word16 *p = temp + IDEAKEYLEN;
|
||||
|
||||
t1 = mulInv(*EK++);
|
||||
t2 = - ( int ) *EK++;
|
||||
t3 = - ( int ) *EK++;
|
||||
*--p = mulInv(*EK++);
|
||||
*--p = t3;
|
||||
*--p = t2;
|
||||
*--p = t1;
|
||||
|
||||
for (i = 0; i < IDEAROUNDS-1; i++) {
|
||||
t1 = *EK++;
|
||||
*--p = *EK++;
|
||||
*--p = t1;
|
||||
|
||||
t1 = mulInv(*EK++);
|
||||
t2 = - ( int ) *EK++;
|
||||
t3 = - ( int ) *EK++;
|
||||
*--p = mulInv(*EK++);
|
||||
*--p = t2;
|
||||
*--p = t3;
|
||||
*--p = t1;
|
||||
}
|
||||
t1 = *EK++;
|
||||
*--p = *EK++;
|
||||
*--p = t1;
|
||||
|
||||
t1 = mulInv(*EK++);
|
||||
t2 = - ( int ) *EK++;
|
||||
t3 = - ( int ) *EK++;
|
||||
*--p = mulInv(*EK++);
|
||||
*--p = t3;
|
||||
*--p = t2;
|
||||
*--p = t1;
|
||||
/* Copy and destroy temp copy */
|
||||
memcpy(DK, temp, sizeof(temp));
|
||||
burn(temp);
|
||||
} /* ideaInvertKey */
|
||||
|
||||
/*
|
||||
* MUL(x,y) computes x = x*y, modulo 0x10001. Requires two temps,
|
||||
* t16 and t32. x is modified, and must me a side-effect-free lvalue.
|
||||
* y may be anything, but unlike x, must be strictly 16 bits even if
|
||||
* low16() is #defined.
|
||||
* All of these are equivalent - see which is faster on your machine
|
||||
*/
|
||||
#ifdef SMALL_CACHE
|
||||
#define MUL(x,y) (x = mul(low16(x),y))
|
||||
#else /* !SMALL_CACHE */
|
||||
#ifdef AVOID_JUMPS
|
||||
#define MUL(x,y) (x = low16(x-1), t16 = low16((y)-1), \
|
||||
t32 = (word32)x*t16 + x + t16 + 1, x = low16(t32), \
|
||||
t16 = t32>>16, x = (x-t16) + (x<t16) )
|
||||
#else /* !AVOID_JUMPS (default) */
|
||||
#define MUL(x,y) \
|
||||
((t16 = (y)) ? \
|
||||
(x=low16(x)) ? \
|
||||
t32 = (word32)x*t16, \
|
||||
x = low16(t32), \
|
||||
t16 = t32>>16, \
|
||||
x = (x-t16)+(x<t16) \
|
||||
: \
|
||||
(x = 1-t16) \
|
||||
: \
|
||||
(x = 1-x))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* IDEA encryption/decryption algorithm */
|
||||
/* Note that in and out can be the same buffer */
|
||||
void
|
||||
#ifdef _DCC
|
||||
ideaCipher(byte (inbuf[8]), byte (outbuf[8]), word16 *key)
|
||||
#else
|
||||
ideaCipher(byte const (inbuf[8]), byte (outbuf[8]), word16 const *key)
|
||||
#endif
|
||||
{
|
||||
register uint16 x1, x2, x3, x4, s2, s3;
|
||||
word16 *in, *out;
|
||||
#ifndef SMALL_CACHE
|
||||
register uint16 t16; /* Temporaries needed by MUL macro */
|
||||
register word32 t32;
|
||||
#endif
|
||||
int r = IDEAROUNDS;
|
||||
|
||||
in = (word16 *)inbuf;
|
||||
x1 = *in++; x2 = *in++;
|
||||
x3 = *in++; x4 = *in;
|
||||
#ifndef HIGHFIRST
|
||||
x1 = (x1>>8) | (x1<<8);
|
||||
x2 = (x2>>8) | (x2<<8);
|
||||
x3 = (x3>>8) | (x3<<8);
|
||||
x4 = (x4>>8) | (x4<<8);
|
||||
#endif
|
||||
do {
|
||||
MUL(x1,*key++);
|
||||
x2 += *key++;
|
||||
x3 += *key++;
|
||||
MUL(x4, *key++);
|
||||
|
||||
s3 = x3;
|
||||
x3 ^= x1;
|
||||
MUL(x3, *key++);
|
||||
s2 = x2;
|
||||
x2 ^= x4;
|
||||
x2 += x3;
|
||||
MUL(x2, *key++);
|
||||
x3 += x2;
|
||||
|
||||
x1 ^= x2; x4 ^= x3;
|
||||
|
||||
x2 ^= s3; x3 ^= s2;
|
||||
} while (--r);
|
||||
MUL(x1, *key++);
|
||||
x3 += *key++;
|
||||
x2 += *key++;
|
||||
MUL(x4, *key);
|
||||
|
||||
out = (word16 *)outbuf;
|
||||
#ifdef HIGHFIRST
|
||||
*out++ = x1;
|
||||
*out++ = x3;
|
||||
*out++ = x2;
|
||||
*out = x4;
|
||||
#else /* !HIGHFIRST */
|
||||
x1 = low16(x1);
|
||||
x2 = low16(x2);
|
||||
x3 = low16(x3);
|
||||
x4 = low16(x4);
|
||||
*out++ = (x1>>8) | (x1<<8);
|
||||
*out++ = (x3>>8) | (x3<<8);
|
||||
*out++ = (x2>>8) | (x2<<8);
|
||||
*out = (x4>>8) | (x4<<8);
|
||||
#endif
|
||||
} /* ideaCipher */
|
||||
|
||||
/*-------------------------------------------------------------*/
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
/*
|
||||
* This is the number of Kbytes of test data to encrypt.
|
||||
* It defaults to 1 MByte.
|
||||
*/
|
||||
#ifndef BLOCKS
|
||||
#ifndef KBYTES
|
||||
#define KBYTES 1024
|
||||
#endif
|
||||
#define BLOCKS (64*KBYTES)
|
||||
#endif
|
||||
|
||||
int
|
||||
main(void)
|
||||
{ /* Test driver for IDEA cipher */
|
||||
int i, j, k;
|
||||
byte userkey[16];
|
||||
word16 EK[IDEAKEYLEN], DK[IDEAKEYLEN];
|
||||
byte XX[8], YY[8], ZZ[8];
|
||||
clock_t start, end;
|
||||
long l;
|
||||
|
||||
/* Make a sample user key for testing... */
|
||||
for(i=0; i<16; i++)
|
||||
userkey[i] = i+1;
|
||||
|
||||
/* Compute encryption subkeys from user key... */
|
||||
ideaExpandKey(userkey, EK);
|
||||
printf("\nEncryption key subblocks: ");
|
||||
for (j=0; j<IDEAROUNDS+1; j++) {
|
||||
printf("\nround %d: ", j+1);
|
||||
if (j < IDEAROUNDS)
|
||||
for(i=0; i<6; i++)
|
||||
printf(" %6u", EK[j*6+i]);
|
||||
else
|
||||
for(i=0; i<4; i++)
|
||||
printf(" %6u", EK[j*6+i]);
|
||||
}
|
||||
|
||||
/* Compute decryption subkeys from encryption subkeys... */
|
||||
ideaInvertKey(EK, DK);
|
||||
printf("\nDecryption key subblocks: ");
|
||||
for (j=0; j<IDEAROUNDS+1; j++) {
|
||||
printf("\nround %d: ", j+1);
|
||||
if (j < IDEAROUNDS)
|
||||
for(i=0; i<6; i++)
|
||||
printf(" %6u", DK[j*6+i]);
|
||||
else
|
||||
for(i=0; i<4; i++)
|
||||
printf(" %6u", DK[j*6+i]);
|
||||
}
|
||||
|
||||
/* Make a sample plaintext pattern for testing... */
|
||||
for (k=0; k<8; k++)
|
||||
XX[k] = k;
|
||||
|
||||
printf("\n Encrypting %d bytes (%ld blocks)...", BLOCKS*16, BLOCKS);
|
||||
fflush(stdout);
|
||||
start = clock();
|
||||
memcpy(YY, XX, 8);
|
||||
for (l = 0; l < BLOCKS; l++)
|
||||
ideaCipher(YY, YY, EK); /* repeated encryption */
|
||||
memcpy(ZZ, YY, 8);
|
||||
for (l = 0; l < BLOCKS; l++)
|
||||
ideaCipher(ZZ, ZZ, DK); /* repeated decryption */
|
||||
end = clock() - start;
|
||||
l = end / (CLOCKS_PER_SEC/1000) + 1;
|
||||
i = l/1000;
|
||||
j = l%1000;
|
||||
l = (16 * BLOCKS * (CLOCKS_PER_SEC/1000)) / (end/1000);
|
||||
printf("%d.%03d seconds = %ld bytes per second\n", i, j, l);
|
||||
|
||||
printf("\nX %3u %3u %3u %3u %3u %3u %3u %3u\n",
|
||||
XX[0], XX[1], XX[2], XX[3], XX[4], XX[5], XX[6], XX[7]);
|
||||
printf("\nY %3u %3u %3u %3u %3u %3u %3u %3u\n",
|
||||
YY[0], YY[1], YY[2], YY[3], YY[4], YY[5], YY[6], YY[7]);
|
||||
printf("\nZ %3u %3u %3u %3u %3u %3u %3u %3u\n",
|
||||
ZZ[0], ZZ[1], ZZ[2], ZZ[3], ZZ[4], ZZ[5], ZZ[6], ZZ[7]);
|
||||
|
||||
/* Now decrypted ZZ should be same as original XX */
|
||||
for (k=0; k<8; k++)
|
||||
if (XX[k] != ZZ[k]) {
|
||||
printf("\n\07Error! Noninvertable encryption.\n");
|
||||
exit(-1); /* error exit */
|
||||
}
|
||||
printf("\nNormal exit.\n");
|
||||
return 0; /* normal exit */
|
||||
} /* main */
|
||||
|
||||
#endif /* TEST */
|
||||
|
||||
/* end of idea.c */
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
#ifndef _IDEA_DEFINED
|
||||
|
||||
#define _IDEA_DEFINED
|
||||
|
||||
/* Defines for the PGP-style types used in IDEA.C */
|
||||
|
||||
#define byte unsigned char
|
||||
#define word16 unsigned short int
|
||||
#define word32 unsigned long int
|
||||
|
||||
/* Macros from PGP */
|
||||
|
||||
#define burn(x) memset( x, 0, sizeof( x ) )
|
||||
|
||||
/* IDEA algorithm constants */
|
||||
|
||||
#define IDEAKEYSIZE 16
|
||||
#define IDEABLOCKSIZE 8
|
||||
|
||||
#define IDEAROUNDS 8
|
||||
#define IDEAKEYLEN ( 6 * IDEAROUNDS + 4 )
|
||||
|
||||
/* Routines used to implement the IDEA encryption */
|
||||
void ideaExpandKey( byte const *userkey, word16 *EK );
|
||||
|
||||
#ifdef _DCC
|
||||
void ideaInvertKey( word16 *EK, word16 DK[IDEAKEYLEN] );
|
||||
void ideaCipher( byte (inbuf[8]), byte (outbuf[8]), word16 *key );
|
||||
#else
|
||||
void ideaInvertKey( word16 const *EK, word16 DK[IDEAKEYLEN] );
|
||||
void ideaCipher( byte const (inbuf[8]), byte (outbuf[8]), word16 const *key );
|
||||
#endif
|
||||
|
||||
#endif /* _IDEA_DEFINED */
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
;-------------------------------------------------------------------------
|
||||
; idea68k.a
|
||||
;
|
||||
; 68000 Assembler version of idea cipher, direct translation from c code
|
||||
; from PGP.
|
||||
;
|
||||
; Author: Risto Paasivirta, paasivir@jyu.fi.
|
||||
;
|
||||
|
||||
section text,code
|
||||
|
||||
xdef _asm_mul,_asm_inv
|
||||
xdef _asm_cipher_idea
|
||||
|
||||
; key schedule block
|
||||
|
||||
ROUNDS equ 8
|
||||
|
||||
Z0 equ 0
|
||||
Z1 equ (ROUNDS+1)*2
|
||||
Z2 equ (ROUNDS+1)*4
|
||||
Z3 equ (ROUNDS+1)*6
|
||||
Z4 equ (ROUNDS+1)*8
|
||||
Z5 equ (ROUNDS+1)*10
|
||||
|
||||
ZSIZE equ (ROUNDS+1)*12
|
||||
|
||||
KSSIZE equ ZSIZE*2
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
;
|
||||
; idmul da,db -- db = da * db mod 65537, d0 = scratch (da may be d0)
|
||||
;
|
||||
|
||||
idmul macro
|
||||
tst.w \2
|
||||
bne.b idmul1.\@
|
||||
|
||||
moveq #1,\2
|
||||
sub.w \1,\2
|
||||
bra.b idmul3.\@
|
||||
|
||||
idmul1.\@ tst.w \1
|
||||
bne.b idmul2.\@
|
||||
moveq #1,d0
|
||||
sub.w \2,d0
|
||||
move.w d0,\2
|
||||
bra.b idmul3.\@
|
||||
|
||||
idmul2.\@ mulu.w \1,\2
|
||||
move.l \2,d0
|
||||
swap d0
|
||||
sub.w d0,\2
|
||||
bcc.b idmul3.\@
|
||||
addq.w #1,\2
|
||||
idmul3.\@
|
||||
endm
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
; idea_cip (a0=inblock,a1=outblock,a2=keyshedule) (d0-d7/a3 scratch)
|
||||
;
|
||||
;
|
||||
;
|
||||
|
||||
idea_cip movem.w (a0),d1-d4
|
||||
moveq #0,d7
|
||||
|
||||
idea_cip_loop lea 0(a2,d7.w),a3
|
||||
idmul (a3),d1
|
||||
idmul Z3(a3),d4
|
||||
add.w Z1(a3),d2
|
||||
add.w Z2(a3),d3
|
||||
move.w d1,d6
|
||||
eor.w d3,d6
|
||||
idmul Z4(a3),d6
|
||||
move.w d4,d5
|
||||
eor.w d2,d5
|
||||
add.w d6,d5
|
||||
idmul Z5(a3),d5
|
||||
add.w d5,d6
|
||||
eor.w d5,d1
|
||||
eor.w d6,d4
|
||||
eor.w d6,d2
|
||||
eor.w d5,d3
|
||||
exg d2,d3
|
||||
addq.w #2,d7
|
||||
cmp.w #ROUNDS*2,d7
|
||||
bcs idea_cip_loop
|
||||
|
||||
lea 0(a2,d7.w),a3
|
||||
idmul (a3),d1
|
||||
idmul Z3(a3),d4
|
||||
add.w Z1(a3),d3
|
||||
add.w Z2(a3),d2
|
||||
exg d2,d3
|
||||
movem.w d1-d4,(a1)
|
||||
rts
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
; _asm_cipher_idea(word16 *in,word16 *out,word16 *ks)
|
||||
;
|
||||
;
|
||||
;
|
||||
|
||||
_asm_cipher_idea
|
||||
movem.l a2-a3/d2-d7,-(sp)
|
||||
movem.l 36(sp),a0-a2
|
||||
bsr idea_cip
|
||||
movem.l (sp)+,a2-a3/d2-d7
|
||||
rts
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
; word16 _asm_mul(word16, word16);
|
||||
;
|
||||
;
|
||||
|
||||
_asm_mul move.w 6(sp),d1
|
||||
idmul 10(sp),d1
|
||||
moveq #0,d0
|
||||
move.w d1,d0
|
||||
rts
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
; d0:16 = inv(d0)
|
||||
;
|
||||
|
||||
_asm_inv move.w 6(sp),d0
|
||||
|
||||
inv cmp.w #2,d0 ; inv(0)=0,inv(1)=1
|
||||
bcs.b 1$
|
||||
|
||||
cmp.w #3,d0
|
||||
bcc.b 2$
|
||||
|
||||
move.w #32769,d0 ; inv(2)
|
||||
1$ rts
|
||||
|
||||
2$ movem.l d1-d7,-(sp)
|
||||
move.l #$10001,d1 ; d1 = n1
|
||||
moveq #1,d2 ; d2 = b2
|
||||
moveq #0,d3 ; d3 = b1
|
||||
|
||||
inv_loop divu.w d0,d1
|
||||
move.l d1,d4
|
||||
swap d4 ; r = d4
|
||||
tst.w d4
|
||||
beq.b inv_done
|
||||
|
||||
move.w d2,d5
|
||||
muls.w d1,d5
|
||||
exg d3,d2
|
||||
sub.l d5,d2
|
||||
moveq #0,d1
|
||||
move.w d0,d1
|
||||
move.w d4,d0
|
||||
bra.b inv_loop
|
||||
|
||||
inv_done tst.l d2
|
||||
bpl.b 1$
|
||||
|
||||
move.l #$10001,d0
|
||||
add.l d2,d0
|
||||
bra.b 2$
|
||||
|
||||
1$ move.l d2,d0
|
||||
|
||||
2$ movem.l (sp)+,d1-d7
|
||||
rts
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
|
||||
end
|
||||
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
;A while ago I posted a message claiming a speed of 238,000
|
||||
;bytes/sec for an implementation of IDEA on a 33Mh 486. Below is
|
||||
;an explanation and some code to show how it works. The basic
|
||||
;trick should be useful on many (but not all) processors. I
|
||||
;expect only those familiar with IDEA and its reference
|
||||
;implementation will be able to follow the discussion. See:
|
||||
;
|
||||
;Lai, Xueja and Massey, James L. A Proposal for a New Block
|
||||
;Encryption Standard, Eurocrypt 90
|
||||
;
|
||||
;For those who have been asking for the code, sorry I kept
|
||||
;putting it off. I wanted to get it out of Turbo Pascal
|
||||
;ideal-mode, but I never had the time.
|
||||
;
|
||||
;Colin Plum wrote IDEA-386 code which is included in PGP
|
||||
;2.3a and uses the same tricks. I don't know who's is
|
||||
;faster, but I expect they will be very close. Now
|
||||
;here's how it's done.
|
||||
;
|
||||
;A major bottleneck in software IDEA is the mul() routine, which
|
||||
;is used 34 times per 64 bit block. The routine performs
|
||||
;multiplication in the multiplicative group mod 2^16+1. The two
|
||||
;factors are each in a 16 bit word, and the output is also in a 16
|
||||
;bit word. Note that 0 is not a member of the multiplicative
|
||||
;group and 2^16 does not fit in 16 bits. We therefor use the 0
|
||||
;word to represent 2^16. Now group elements map one to one onto
|
||||
;all possible 16 bit words, since 2^16+1 is prime.
|
||||
;
|
||||
;Here is (essentially) the reference implementation from [Lai].
|
||||
;
|
||||
;
|
||||
;unsigned mul( unsigned a, unsigned b ) {
|
||||
; long int p ;
|
||||
; long unsigned q ;
|
||||
; if( a==0 ) p= 0x00010001 - b ;
|
||||
; else if( b==0 ) p= 0x00010001 - a ;
|
||||
; else {
|
||||
; q= a*b;
|
||||
; p= (q & 0xffff) - (q>>16)
|
||||
; if( p<0 ) p= p + 0x00010001 ;
|
||||
; }
|
||||
; return (unsigned)(p & 0xffff) ;
|
||||
;}
|
||||
;
|
||||
;
|
||||
;Note the method of reducing a 32 bit word modulo 2^16-1. We
|
||||
;subtract the high word from the low word, and add the modulus
|
||||
;back if the result is less than 0. [Lai] contains a proof that
|
||||
;this works, and you can convince yourself fairly easily.
|
||||
;
|
||||
;To speed up this routine, we note that the tests for a=0 and b=0
|
||||
;will rarely be false. With the possible exception of the first 2
|
||||
;of the 34 multiplications, 0 should be no more likely than any of
|
||||
;the other 65535 numbers. Note that if (and only if) either a or
|
||||
;b is 0 then q will also be 0, and we can check for this in one
|
||||
;instruction if our processor sets a zero flag for multiplication
|
||||
;(as the 68000 does but 80x86 does not).
|
||||
;
|
||||
;Fortunately p will also be zero after the subtraction if and only
|
||||
;if either a or b is 0. Proof: r will be zero when the high order
|
||||
;word of q equals the low order word, and that happens when q is
|
||||
;divisible by 00010001 hex. Since 00010001h = 2^16+1 is prime,
|
||||
;this happens if either a or b is a multiple of 2^16+1, and 0 is
|
||||
;the only such multiple which will fit in a 16 bit word.
|
||||
;
|
||||
;The speed-up strategy is to proceed under the assumption that a
|
||||
;and b are not 0, check to be sure in one instruction, and
|
||||
;recompute if the assumption was wrong. Here's some 8086
|
||||
;assembler code:
|
||||
;
|
||||
; mov ax, [a]
|
||||
; mul [b] ; ax is implied. q is now in DX AX
|
||||
; sub ax, dx ; mod 2^16+1
|
||||
; jnz not0 ; Jump if neither op was 0. Usually taken.
|
||||
;
|
||||
; mov ax, 1 ; recompute result knowing one op is 0.
|
||||
; sub ax, [a]
|
||||
; sub ax, [b]
|
||||
; jmp out ; Just jump over adding the carry.
|
||||
;not0:
|
||||
; adc ax, 0 ; If r<0 add 1, otherwise do nothing.
|
||||
;out: ; Result is now in ax
|
||||
;
|
||||
;
|
||||
;Note that when r<0 we add 1 instead of 2^16+1 since the 2^16 part
|
||||
;overflows out of the result. The "adc ax, 0" does all the work
|
||||
;of checking for a negative result and adding the modulus if
|
||||
;needed.
|
||||
;
|
||||
;The multiplication takes 9 instructions, 4 of which are rarely
|
||||
;executed. I believe similar tricks are possible on many
|
||||
;processors. The one drawback to the check-after-multiply tactic
|
||||
;is that we can't let the multiply overwrite the only copy of an
|
||||
;operand.
|
||||
;
|
||||
;Note that most software implementations of IDEA will run at
|
||||
;slightly different speeds when 0's come up in the multiply
|
||||
;routine. The reference implementation is faster on 0, this one
|
||||
;is faster on non-zero. This may be a problem for some real-time
|
||||
;stuff, and also suggests an attack based on timing.
|
||||
;
|
||||
;Finally, below is an implementation of the complete encryption
|
||||
;function in 8086 assembler, to replace the cipher_idea() function
|
||||
;in PGP. It takes the same parameters as the function from PGP,
|
||||
;and uses the c language calling conventions. I tested it using
|
||||
;the debug features of the idea.c file in PGP. You will need to
|
||||
;add segment/assume directives. This version uses no global data
|
||||
;and should be reentrant.
|
||||
;
|
||||
;The handling of zero multipliers is outside the inner loop so
|
||||
;that a short conditional jump can loop back to the beginning.
|
||||
;Forward conditional jumps are usually not taken and backward
|
||||
;jumps are usually taken, which is consistent with 586 branch
|
||||
;prediction (or so I've heard). Stalls where the output of one
|
||||
;instruction is needed for the next seem unavoidable.
|
||||
;
|
||||
;Last I heard, IDEA was patent pending. My code is up for grabs,
|
||||
;although I would get a kick out being credited if you use it.
|
||||
;On the other hand Colin's code is already tested and ready
|
||||
;to assemble and link with PGP.
|
||||
;
|
||||
;--Bryan
|
||||
;
|
||||
;____________________CODE STARTS BELOW THIS LINE_________
|
||||
|
||||
; Called as: asmcrypt( inbuff, outbuff, zkey ) just like PGP
|
||||
|
||||
PROC _asmcrypt
|
||||
|
||||
; establish parameter and local space on stack
|
||||
; follow c language calling conventions
|
||||
|
||||
ARG inblock:Word, outblock:Word, zkey:Word
|
||||
LOCAL sx1:Word,sx4:Word,skk:Word,done8:Word =stacksize
|
||||
|
||||
push bp
|
||||
mov bp, sp
|
||||
sub sp, stacksize
|
||||
|
||||
; push ax ; My compiler assumes these are not saved.
|
||||
; push bx
|
||||
; push cx
|
||||
; push dx
|
||||
|
||||
push si
|
||||
push di
|
||||
|
||||
; Put the 16 bit sub-blocks in registers and/or local variables
|
||||
mov si, [inblock]
|
||||
mov ax, [si]
|
||||
mov [sx1], ax ; x1 is in ax and sx1
|
||||
mov di, [si+2] ; x2 is in di
|
||||
mov bx, [si+4] ; x3 is in bx
|
||||
mov dx, [si+6]
|
||||
mov [sx4], dx ; x4 is in sx4
|
||||
|
||||
mov si, [zkey] ; si points to next subkey
|
||||
mov [done8], si
|
||||
add [done8], 96 ; we will be finished with 8 rounds
|
||||
; when si=done8
|
||||
|
||||
@@loop: ; 8 rounds of this
|
||||
add di, [si+2] ; x2+=zkey[2] is in di
|
||||
add bx, [si+4] ; x3+=zkey[4] is in bx
|
||||
|
||||
mul [Word si] ;x1 *= zkey[0]
|
||||
sub ax, dx
|
||||
jz @@x1 ; if 0, use special case multiply
|
||||
adc ax, 0
|
||||
@@x1out:
|
||||
mov [sx1], ax ; x1 is in ax and sx1
|
||||
|
||||
xor ax, bx ; ax= x1^x3
|
||||
mul [Word si+8] ; compute kk
|
||||
sub ax, dx ; if 0, use special case multiply
|
||||
jz @@kk
|
||||
adc ax, 0
|
||||
@@kkout:
|
||||
mov cx, ax ; kk is in cx
|
||||
|
||||
mov ax, [sx4] ; x4 *= zkey[6]
|
||||
mul [Word si+6]
|
||||
sub ax, dx
|
||||
jz @@x4 ; if 0, use special case multiply
|
||||
adc ax, 0
|
||||
@@x4out:
|
||||
mov [sx4], ax ; x4 is in sx4 and ax
|
||||
|
||||
xor ax, di ; x4^x2
|
||||
add ax, cx ; kk+(x2^x4)
|
||||
mul [Word si+10] ; compute t1
|
||||
sub ax, dx
|
||||
jz @@t1 ; if 0, use special case multiply
|
||||
adc ax, 0
|
||||
@@t1out: ; t1 is in ax
|
||||
|
||||
add cx, ax ; t2 is in cx kk+t1
|
||||
|
||||
xor [sx4], cx ; x4 in sx4
|
||||
xor di, cx ; new x3 in di
|
||||
xor bx, ax ; new x2 in bx
|
||||
xchg bx, di ; x2 in di, x3 in bx
|
||||
xor ax, [sx1] ; x1 in ax
|
||||
mov [sx1], ax ; and [sx1]
|
||||
|
||||
add si, 12 ; point to next subkey
|
||||
cmp si, [done8]
|
||||
jne @@loop
|
||||
jmp @@out8
|
||||
|
||||
;------------------------------------------
|
||||
; Special case multiplications, when one factor is 0
|
||||
|
||||
@@x1: mov ax, 1
|
||||
sub ax, [sx1]
|
||||
sub ax, [Word si]
|
||||
jmp @@x1out
|
||||
|
||||
@@kk: mov ax, [sx1] ; rebuild overwritten operand
|
||||
xor ax, bx
|
||||
neg ax
|
||||
inc ax
|
||||
sub ax, [si+8]
|
||||
jmp @@kkout
|
||||
|
||||
@@x4: mov ax, 1
|
||||
sub ax, [sx4]
|
||||
sub ax, [Word si+6]
|
||||
jmp @@x4out
|
||||
|
||||
@@t1: mov ax, [sx4] ; rebuild
|
||||
xor ax, di
|
||||
add ax, cx
|
||||
neg ax
|
||||
inc ax
|
||||
sub ax, [si+10]
|
||||
jmp @@t1out
|
||||
|
||||
;---------------------------------------------------
|
||||
; 8 rounds are done, now that extra pseudo-round
|
||||
|
||||
@@out8:
|
||||
push di
|
||||
mov di, [outblock]
|
||||
|
||||
mul [Word si]
|
||||
sub ax, dx
|
||||
jnz @@o1n ; jump over special case code
|
||||
mov ax, 1
|
||||
sub ax, [sx1]
|
||||
sub ax, [si]
|
||||
jmp @@o1out
|
||||
@@o1n: adc ax, 0
|
||||
@@o1out: mov [di], ax ; final ciphertext block 1
|
||||
|
||||
mov ax, [sx4]
|
||||
mul [Word si+6]
|
||||
sub ax, dx
|
||||
jnz @@o4n ; jump over special case code
|
||||
mov ax, 1
|
||||
sub ax, [sx4]
|
||||
sub ax, [si+6]
|
||||
jmp @@o4out
|
||||
@@o4n: adc ax, 0
|
||||
@@o4out: mov [di+6], ax ; final ciphertext block 4
|
||||
|
||||
add bx, [si+2]
|
||||
mov [di+2], bx ; final ciphertext block 2
|
||||
pop ax
|
||||
add ax, [si+4]
|
||||
mov [di+4], ax ; final ciphertext block 3
|
||||
|
||||
; Restore the stack and return
|
||||
|
||||
pop di
|
||||
pop si
|
||||
; pop dx
|
||||
; pop cx
|
||||
; pop bx
|
||||
; pop ax
|
||||
|
||||
mov sp, bp
|
||||
pop bp
|
||||
ret
|
||||
ENDP _asmcrypt
|
||||
Reference in New Issue
Block a user