MODULE CryptoUtils;
IMPORT S := SYSTEM, Out := KernelLog, Random, Kernel, B := CryptoBigNumbers;
VAR
hexd: ARRAY 17 OF CHAR;
PROCEDURE PrintHex*( CONST buf: ARRAY OF CHAR; p, n: LONGINT );
VAR ch, i: LONGINT;
BEGIN
FOR i := 0 TO n - 1 DO
IF i MOD 4 = 0 THEN
IF i MOD 24 = 0 THEN Out.Ln END;
Out.String( " " )
END;
ch := ORD( buf[p + i] );
Out.Char( hexd[ch DIV 10H] );
Out.Char( hexd[ch MOD 10H] );
END
END PrintHex;
PROCEDURE PrintBufferString*( CONST buf: ARRAY OF CHAR; pos: LONGINT );
VAR i, p, len: LONGINT;
BEGIN
p := pos;
GetLength( buf, p, len );
FOR i := 0 TO len - 1 DO Out.Char( buf[p + i] ) END
END PrintBufferString;
PROCEDURE PrintPackage*( CONST buf: ARRAY OF CHAR; len: LONGINT );
VAR i: LONGINT; c: CHAR;
BEGIN
FOR i := 0 TO len - 1 DO
IF i MOD 24 = 0 THEN Out.Ln END;
IF i MOD 4 = 0 THEN Out.Char( ' ' ) END;
c := buf[i];
Out.Char( hexd[ ORD( c ) DIV 16] );
Out.Char( hexd[ ORD( c ) MOD 16] );
END ;
Out.Ln
END PrintPackage;
PROCEDURE PutLength*( VAR buf: ARRAY OF CHAR; VAR pos: LONGINT; len: LONGINT );
VAR i: INTEGER;
BEGIN
FOR i := 3 TO 0 BY -1 DO
buf[pos + i] := CHR( len MOD 256 ); len := len DIV 256
END;
INC( pos, 4 )
END PutLength;
PROCEDURE GetLength*( CONST buf: ARRAY OF CHAR; VAR pos, len: LONGINT );
BEGIN
len := ASH( LONG( ORD( buf[pos] ) ), 24 ) +
ASH( LONG( ORD( buf[pos + 1] ) ), 16 ) +
ASH( LONG( ORD( buf[pos + 2] ) ), 8 ) +
ORD( buf[pos + 3] );
INC( pos, 4 );
END GetLength;
PROCEDURE GetInt*( CONST buf: ARRAY OF CHAR; pos: LONGINT ): LONGINT;
BEGIN
RETURN ASH( LONG( ORD( buf[pos] ) ), 24 ) +
ASH( LONG( ORD( buf[pos + 1] ) ), 16 ) +
ASH( LONG( ORD( buf[pos + 2] ) ), 8 ) +
ORD( buf[pos + 3] );
END GetInt;
PROCEDURE PutChar*( VAR buf: ARRAY OF CHAR; VAR pos: LONGINT; ch: CHAR );
BEGIN
buf[pos] := ch; INC( pos )
END PutChar;
PROCEDURE GetChar*( CONST buf: ARRAY OF CHAR; VAR pos: LONGINT; VAR ch: CHAR );
BEGIN
ch := buf[pos]; INC( pos )
END GetChar;
PROCEDURE PutString*( VAR buf: ARRAY OF CHAR; VAR pos: LONGINT; CONST str: ARRAY OF CHAR );
VAR i, len: LONGINT;
BEGIN
len := 0;
WHILE (len < LEN(str)) & (str[len] # 0X) DO INC( len ) END;
PutLength( buf, pos, len );
FOR i := 0 TO len -1 DO buf[pos] := str[i]; INC( pos ) END ;
END PutString;
PROCEDURE GetString*( CONST buf: ARRAY OF CHAR; VAR pos: LONGINT; VAR str: ARRAY OF CHAR );
VAR i, len: LONGINT;
BEGIN
GetLength( buf, pos, len );
FOR i := 0 TO len -1 DO str[i] := buf[pos]; INC( pos ) END;
str[len] := 0X
END GetString;
PROCEDURE PutArray*( VAR buf: ARRAY OF CHAR; VAR pos: LONGINT;
CONST arr: ARRAY OF CHAR; apos, len: LONGINT );
VAR i: LONGINT;
BEGIN
PutLength( buf, pos, len );
FOR i := 0 TO len -1 DO buf[pos] := arr[apos + i]; INC( pos ) END
END PutArray;
PROCEDURE PutBigNumber*( VAR buf: ARRAY OF CHAR; VAR pos: LONGINT; b: B.BigNumber );
VAR i, j, len, x: LONGINT; tmp: ARRAY 2048 OF CHAR;
BEGIN
len := 0;
FOR i := b.len - 1 TO 0 BY -1 DO
x := b.d[i];
FOR j := 3 TO 0 BY -1 DO
tmp[len + j] := CHR( x MOD 256 ); x := x DIV 256
END;
INC( len, 4 )
END;
j := 0;
WHILE tmp[j] = 0X DO INC( j ); DEC( len ) END;
IF ORD( tmp[j] ) >= 128 THEN PutLength( buf, pos, len + 1 ); buf[pos] := 0X; INC( pos )
ELSE PutLength( buf, pos, len );
END;
FOR i := 0 TO len - 1 DO buf[pos] := tmp[j + i]; INC( pos ) END;
END PutBigNumber;
PROCEDURE GetBigNumber*( CONST buf: ARRAY OF CHAR; VAR pos: LONGINT; VAR b: B.BigNumber );
VAR
len: LONGINT;
BEGIN
GetLength( buf, pos, len );
B.AssignBin( b, buf, pos, len );
INC( pos, len )
END GetBigNumber;
PROCEDURE Hex2Bin*( CONST hex: ARRAY OF CHAR; hp: LONGINT;
VAR bin: ARRAY OF CHAR; bp: LONGINT;
len: LONGINT );
VAR
i: INTEGER; h, b: LONGINT; c: CHAR;
BEGIN
i := 0;
WHILE i < 2*len DO
c := hex[hp + i];
IF (c >= '0') & (c <= '9') THEN h := ORD( c ) - ORD( '0' );
ELSIF (c >= 'a') & (c <= 'f') THEN h := ORD( c ) - ORD( 'a' ) + 10;
ELSIF (c >= 'A') & (c <= 'F') THEN h := ORD( c ) - ORD( 'A' ) + 10;
ELSIF c = 0X THEN
Out.String( "### error: hex source too short" ); Out.Ln;
HALT( 99 )
ELSE
Out.String( "### format error in hex string" ); Out.Ln;
HALT( 99 )
END;
IF ODD( i ) THEN bin[bp] := CHR( b + h ); INC( bp )
ELSE b := h * 16
END;
INC( i );
END
END Hex2Bin;
PROCEDURE Bin2Hex*( CONST bin: ARRAY OF CHAR; bp: LONGINT;
VAR hex: ARRAY OF CHAR; hp: LONGINT;
len: LONGINT );
VAR i, c: LONGINT;
BEGIN
FOR i := 0 TO len - 1 DO
c := ORD( bin[ bp + i] );
hex[hp] := hexd[ c DIV 16]; INC( hp );
hex[hp] := hexd[ c MOD 16]; INC( hp );
END
END Bin2Hex;
PROCEDURE RandomBytes*( VAR buf: ARRAY OF CHAR; ofs, len: LONGINT );
VAR
i: LONGINT;
rg: Random.Generator;
BEGIN
NEW( rg );
rg.InitSeed( Kernel.GetTicks() );
FOR i := 0 TO len - 1 DO buf[ ofs + i ] := CHR( ENTIER( rg.Uniform()*256 ) ) END
END RandomBytes;
PROCEDURE XORBlock*( VAR block, iv: ARRAY OF S.BYTE );
VAR a1, a2: S.ADDRESS; s1, s2: SET; i: LONGINT;
BEGIN
a1 := S.ADR( block ); a2 := S.ADR( iv );
FOR i := 1 TO LEN( block ) DIV 4 DO
S.GET( a1, s1 ); S.GET( a2, s2 ); S.PUT( a1, s1 / s2 );
INC( a1, 4 ); INC( a2, 4 )
END
END XORBlock;
PROCEDURE CharsToBlockBE*( CONST buf: ARRAY OF CHAR; pos: LONGINT; VAR block: ARRAY OF S.BYTE );
VAR i: LONGINT; a: S.ADDRESS;
BEGIN
a := S.ADR( block );
FOR i := 1 TO LEN( block ) DIV 4 DO
S.PUT( a,
ASH( LONG( ORD( buf[pos + 0] ) ), 24 ) +
ASH( LONG( ORD( buf[pos + 1] ) ), 16 ) +
ASH( LONG( ORD( buf[pos + 2] ) ), 8 ) +
ORD( buf[pos + 3] ) );
INC( a, 4 ); INC( pos, 4 )
END
END CharsToBlockBE;
PROCEDURE CharsToBlockLE*( CONST buf: ARRAY OF CHAR; pos: LONGINT; VAR block: ARRAY OF S.BYTE );
VAR i: LONGINT; a: S.ADDRESS;
BEGIN
a := S.ADR( block );
FOR i := 1 TO LEN( block ) DIV 4 DO
S.PUT( a,
ASH( LONG( ORD( buf[pos + 3] ) ), 24 ) +
ASH( LONG( ORD( buf[pos + 2] ) ), 16 ) +
ASH( LONG( ORD( buf[pos + 1] ) ), 8 ) +
ORD( buf[pos + 0] ) );
INC( a, 4 ); INC( pos, 4 )
END
END CharsToBlockLE;
PROCEDURE BlockToCharsBE*( CONST block: ARRAY OF S.BYTE; VAR buf: ARRAY OF CHAR; pos: LONGINT );
VAR a: S.ADDRESS; i, w: LONGINT;
BEGIN
a := S.ADR( block );
FOR i := 1 TO LEN( block ) DIV 4 DO
S.GET( a, w ); INC( a, 4 );
buf[pos + 3] := CHR( w MOD 256 ); w := w DIV 256;
buf[pos + 2] := CHR( w MOD 256 ); w := w DIV 256;
buf[pos + 1] := CHR( w MOD 256 ); w := w DIV 256;
buf[pos + 0] := CHR( w MOD 256 );
INC( pos, 4 )
END
END BlockToCharsBE;
PROCEDURE BlockToCharsLE*( CONST block: ARRAY OF S.BYTE; VAR buf: ARRAY OF CHAR; pos: LONGINT );
VAR a: S.ADDRESS; i, w: LONGINT;
BEGIN
a := S.ADR( block );
FOR i := 1 TO LEN( block ) DIV 4 DO
S.GET( a, w ); INC( a, 4 );
buf[pos + 0] := CHR( w MOD 100H ); w := w DIV 100H;
buf[pos + 1] := CHR( w MOD 100H ); w := w DIV 100H;
buf[pos + 2] := CHR( w MOD 100H ); w := w DIV 100H;
buf[pos + 3] := CHR( w MOD 100H );
INC( pos, 4 )
END
END BlockToCharsLE;
PROCEDURE BESetFrom*( CONST buf: ARRAY OF CHAR; pos: LONGINT ): SET;
BEGIN
RETURN S.VAL( SET,
ASH( LONG( ORD( buf[pos + 0] ) ), 24 ) +
ASH( LONG( ORD( buf[pos + 1] ) ), 16 ) +
ASH( LONG( ORD( buf[pos + 2] ) ), 8 ) +
ORD( buf[pos + 3] ) );
END BESetFrom;
PROCEDURE LESetFrom*( CONST buf: ARRAY OF CHAR; pos: LONGINT ): SET;
BEGIN
RETURN S.VAL( SET,
ASH( LONG( ORD( buf[pos + 3] ) ), 24 ) +
ASH( LONG( ORD( buf[pos + 2] ) ), 16 ) +
ASH( LONG( ORD( buf[pos + 1] ) ), 8 ) +
ORD( buf[pos] ) );
END LESetFrom;
BEGIN
hexd := "0123456789ABCDEF";
END CryptoUtils.