/*IDEA.C v2.2
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. Optimized for speed 21 Oct 92 by Colin Plumb
<colin@nsq.gts.org> This code assumes that each pair of 8-bit bytes
comprising a 16-bit word in the key and in the cipher block are
externally represented with the Most Significant Byte (MSB) first,
regardless of internal native byte order of the target cpu.
modified for use with PC files by Colin Maroney 4/1/94*/
/* USAGE: pass a key made up of 8 16-bit numbers (word16) in an array
("word16 key[8];"), an input FILE * and an output temporary
FILE * to either encode_file() or decode_file().
where the key comes from is up to you.
then call swap_files_and_clean_up() with the original file's
name as the argument, to replace the original file
with the encoded data (stored in the temporary file).
you can remname the tempfile to be used in idea.h
noisy is an integer which tells encrypting/decrypting
functions to echo a "." every 256 writes, so the user can
see that something is happening. set it to 0 for quiet
running.
please note that for really good security the original file
is overwritten before being erased if you use the w switch.
otherwise it outputs a file "<filename>.enc"
the main() used here as illustration reads the filename
from the command line arguments, as well as a command
"e" or "d" to tell it whether to encrypt or
decrypt, and a key. the older versions had an interface
for when a command line was not use. lack of editing
features made this buggy, so i axed it. */
#include "idea.h"
static uint16 inv(uint16 x)
{
uint16 t0,t1;
uint16 q,y;
if (x<=1)
return x;
t1=(uint16)(0x10001l/x);
y=(uint16)(0x10001l%x);
if (y==1)
return 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 low16(1-t1);
}
while (x<4)
{
input[x]=((word16)(read_char_from_file(in)<<8));
if (!end_of_file)
{
temp=read_char_from_file(in);
if (temp<0) temp+=256;
input[x]=input[x]|temp;
x++;
}
if (end_of_file)
{
while (x<4) input[x++]=0;
break;
}
}
cipher_idea(input,output,Z);
for (y=0;y<x;y++)
{
if (noisy) if (count++%256==0) printf(".");
write_word16_to_file(output[y],out);
}
}
}
void decipher_file(FILE *in,FILE *out,word16 *key)
{
word16 input[4],output[4];
int x,y;
IDEAkey Z,DK;
int count=0;
long length=0;
en_key_idea(key,Z);
de_key_idea(Z,DK);
end_of_file=0;
fread(&length,sizeof(long),1,in);
while (!end_of_file)
{
x=0;
while (x<4)
{
input[x]=read_word16_from_file(in);
if (end_of_file)
break;
x++;
}
cipher_idea(input,output,DK);
for (y=0;y<x;y++)
{
if (noisy) if (count++%256==0) printf(".");
if (length-->0)
write_char_to_file(((char)(output[y]>>8)),out);
if (length-->0)
write_char_to_file(((char)(output[y]&255)),out);
}
}
}
void swap_files_and_clean_up(char *file)
{
long fsize,count;
FILE *fp;
char temp[100];
if (overwrite)
{
if ((fp=fopen(file,"r+b"))==NULL)
{
printf("\nError overwriting old file, security compromised.\n");
}
else
{
fseek(fp,0l,SEEK_END);
fsize=ftell(fp);
fseek(fp,0l,SEEK_SET);
for (count=0;count<fsize;count++)
fputc('0',fp);
fclose(fp);
}
if ((remove(file))!=0)
{
printf("\nERROR removing old file <%s>\n",file);
printf("encoded data remains in temporary file <%s>\n",tempfilename);
exit(-1);
}
}
else
{
strcpy(temp,file);
file=strtok(temp,".");
strcat(file,".enc");
}
if ((rename(tempfilename,file))!=0)
{
printf("\nERROR renaming temporary file <%s>!!\n",tempfilename);
printf("Data is safely processed and stored in that file.\n");
exit(-1);
}
}
if (argc!=4)
{
printf("\nUsage: idea filename.ext [e|d[w]] key\n");
printf(" e=encode d=decode w=overwrite file\n");
printf(" NOTE: Key must be no longer than 8 characters long!!!\n");
exit(-1);
}
else
{
strncpy(filename,argv[1],99);
filename[99]='\0';
if (argv[2][0]=='e') to_or_from=1;
else if (argv[2][0]=='d') to_or_from=0;
else
{
printf("\nUsage: idea filename.ext [e|d[w]] key\n");
printf(" e=encrypt d=decrypt w=overwrite file\n");
printf(" NOTE: Key must be no longer than 8 characters long!!!\n");
exit(-1);
}
if (argv[2][1]=='w') overwrite=1;
getuserkeyfromargv(userkey,argv[3]);
}
if ((fp=fopen(filename,"r+b"))==NULL)
{
printf("\nError opening File %s\n",filename);
exit (-1);
}
if ((temp=fopen(tempfilename,"w+b"))==NULL)
{
printf("\nError opening temporary file\n");
exit(-1);
}
Type
TDCP_idea = Class(TDCP_blockcipher)
protected
EK, DK: Array[0..51] Of word;
public
Class Function GetID: longint; override;
Class Function GetAlgorithm: String; override;
Class Function GetMaxKeySize: longint; override;
Class Function GetBlockSize: longint; override;
Class Function SelfTest: boolean; override;
Procedure Init(Const Key; Size: longint; InitVector: pointer); override;
Procedure Burn; override;
Procedure EncryptECB(Const InData; Var OutData); override;
Procedure DecryptECB(Const InData; Var OutData); override;
End;
Class Function TDCP_idea.GetMaxKeySize: longint;
Begin
Result := 128;
End;
Class Function TDCP_idea.GetBlockSize: longint;
Begin
Result := 64;
End;
Class Function TDCP_idea.GetID: longint;
Begin
Result := DCP_idea;
End;
Class Function TDCP_idea.GetAlgorithm: String;
Begin
Result := 'IDEA';
End;
Class Function TDCP_idea.SelfTest: boolean;
Const
Key1: Array[0..15] Of byte =
($3A, $98, $4E, $20, $00, $19, $5D, $B3, $2E, $E5, $01, $C8, $C4, $7C, $EA, $60);
InData1: Array[0..7] Of byte =
($01, $02, $03, $04, $05, $06, $07, $08);
OutData1: Array[0..7] Of byte =
($97, $BC, $D8, $20, $07, $80, $DA, $86);
Key2: Array[0..15] Of byte =
($00, $64, $00, $C8, $01, $2C, $01, $90, $01, $F4, $02, $58, $02, $BC, $03, $20);
InData2: Array[0..7] Of byte =
($05, $32, $0A, $64, $14, $C8, $19, $FA);
OutData2: Array[0..7] Of byte =
($65, $BE, $87, $E7, $A2, $53, $8A, $ED);
Var
Cipher: TDCP_idea;
Data: Array[0..7] Of byte;
Begin
Cipher := TDCP_idea.Create(Nil);
Cipher.Init(Key1, SizeOf(Key1) * 8, Nil);
Cipher.EncryptECB(InData1, Data);
Result := boolean(CompareMemory(@Data, @OutData1, SizeOf(Data)));
Cipher.DecryptECB(Data, Data);
Result := Result And boolean(CompareMemory(@Data, @InData1, SizeOf(Data)));
Cipher.Burn;
Cipher.Init(Key2, SizeOf(Key2) * 8, Nil);
Cipher.EncryptECB(InData2, Data);
Result := Result And boolean(CompareMemory(@Data, @OutData2, SizeOf(Data)));
Cipher.DecryptECB(Data, Data);
Result := Result And boolean(CompareMemory(@Data, @InData2, SizeOf(Data)));
Cipher.Burn;
Cipher.Free;
End;
Function MulInv(x: word): word;
Var
t0, t1, q, y: word;
Begin
If x <= 1 Then
Begin
Result := x;
Exit;
End;
t1 := DWord($10001) Div x;
y := DWord($10001) Mod x;
If y = 1 Then
Begin
Result := (1 - t1) And $FFFF;
Exit;
End;
t0 := 1;
Repeat
q := x Div y;
x := x Mod y;
t0 := t0 + (q * t1);
If x = 1 Then
Begin
Result := t0;
Exit;
End;
q := y Div x;
y := y Mod x;
t1 := t1 + (q * t0);
Until y = 1;
Result := (1 - t1) And $FFFF;
End;
Procedure TDCP_idea.Init(Const Key; Size: longint; InitVector: pointer);
Var
i: integer;
Begin
Inherited Init(Key, Size, InitVector);
Size := Size Div 8;
DK[51] := MulInv(EK[3]);
DK[50] := -EK[2];
DK[49] := -EK[1];
DK[48] := MulInv(EK[0]);
For i := 0 To 6 Do
Begin
DK[47 - i * 6] := EK[i * 6 + 5];
DK[46 - i * 6] := EK[i * 6 + 4];
DK[45 - i * 6] := MulInv(EK[i * 6 + 9]);
DK[44 - i * 6] := -EK[i * 6 + 7];
DK[43 - i * 6] := -EK[i * 6 + 8];
DK[42 - i * 6] := MulInv(EK[i * 6 + 6]);
End;
DK[5] := EK[47];
DK[4] := EK[46];
DK[3] := MulInv(EK[51]);
DK[2] := -EK[50];
DK[1] := -EK[49];
DK[0] := MulInv(EK[48]);
{ Generate a "random" IV }
If InitVector = Nil Then
Begin
FillChar(IV^, BS, 0);
EncryptECB(IV^, IV^);
Reset;
End
Else
Begin
Move(InitVector^, IV^, BS);
Reset;
End;
End;
Procedure Mul(Var x: word; Const y: word);
Var
p: DWord;
t16: word;
Begin
p := DWord(x) * y;
If p = 0 Then
x := 1 - x - y
Else
Begin
x := p Shr 16;
t16 := p And $FFFF;
x := t16 - x;
If (t16 < x) Then
Inc(x);
End;
End;
Procedure TDCP_idea.EncryptECB(Const InData; Var OutData);
Var
x: Array[1..4] Of word;
s3, s2: word;
i: longint;
Begin
If Not fInitialized Then
Raise EDCP_blockcipher.Create('Cipher not initialized');
PDword(@x[1])^ := PDword(@InData)^;
PDword(@x[3])^ := PDword(DWord(@InData) + 4)^;
For i := 1 To 4 Do
x[i] := (x[i] Shl 8) Or (x[i] Shr 8);
For i := 0 To 7 Do
Begin
Mul(x[1], EK[(i * 6) + 0]);
Inc(x[2], EK[(i * 6) + 1]);
Inc(x[3], EK[(i * 6) + 2]);
Mul(x[4], EK[(i * 6) + 3]);
s3 := x[3];
x[3] := x[3] Xor x[1];
Mul(x[3], EK[(i * 6) + 4]);
s2 := x[2];
x[2] := x[2] Xor x[4];
Inc(x[2], x[3]);
Mul(x[2], EK[(i * 6) + 5]);
Inc(x[3], x[2]);
x[1] := x[1] Xor x[2];
x[4] := x[4] Xor x[3];
x[2] := x[2] Xor s3;
x[3] := x[3] Xor s2;
End;
Mul(x[1], EK[48]);
Inc(x[3], EK[49]);
Inc(x[2], EK[50]);
Mul(x[4], EK[51]);
x[1] := (x[1] Shl 8) Or (x[1] Shr 8);
s2 := (x[3] Shl 8) Or (x[3] Shr 8);
x[3] := (x[2] Shl 8) Or (x[2] Shr 8);
x[4] := (x[4] Shl 8) Or (x[4] Shr 8);
x[2] := s2;
PDword(@OutData)^ := PDword(@x[1])^;
PDword(DWord(@OutData) + 4)^ := PDword(@x[3])^;
End;
Procedure TDCP_idea.DecryptECB(Const InData; Var OutData);
Var
x: Array[1..4] Of word;
s3, s2: word;
i: longint;
Begin
If Not fInitialized Then
Raise EDCP_blockcipher.Create('Cipher not initialized');
PDword(@x[1])^ := PDword(@InData)^;
PDword(@x[3])^ := PDword(DWord(@InData) + 4)^;
For i := 1 To 4 Do
x[i] := (x[i] Shl 8) Or (x[i] Shr 8);
For i := 0 To 7 Do
Begin
Mul(x[1], DK[(i * 6) + 0]);
Inc(x[2], DK[(i * 6) + 1]);
Inc(x[3], DK[(i * 6) + 2]);
Mul(x[4], DK[(i * 6) + 3]);
s3 := x[3];
x[3] := x[3] Xor x[1];
Mul(x[3], DK[(i * 6) + 4]);
s2 := x[2];
x[2] := x[2] Xor x[4];
Inc(x[2], x[3]);
Mul(x[2], DK[(i * 6) + 5]);
Inc(x[3], x[2]);
x[1] := x[1] Xor x[2];
x[4] := x[4] Xor x[3];
x[2] := x[2] Xor s3;
x[3] := x[3] Xor s2;
End;
Mul(x[1], DK[48]);
Inc(x[3], DK[49]);
Inc(x[2], DK[50]);
Mul(x[4], DK[51]);
x[1] := (x[1] Shl 8) Or (x[1] Shr 8);
s2 := (x[3] Shl 8) Or (x[3] Shr 8);
x[3] := (x[2] Shl 8) Or (x[2] Shr 8);
x[4] := (x[4] Shl 8) Or (x[4] Shr 8);
x[2] := s2;
PDword(@OutData)^ := PDword(@x[1])^;
PDword(DWord(@OutData) + 4)^ := PDword(@x[3])^;
End;