source upload

This commit is contained in:
Razor12911
2022-01-17 22:16:47 +02:00
parent 12936d065b
commit 098e8c48de
1778 changed files with 1206749 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipher.inc }
{ Description: Cipher library defines }
{ }
{******************************************************************************}
{.DEFINE DEBUG}
{.DEFINE TEST}
{$INCLUDE ..\flcInclude.inc}
{$IFDEF DEBUG}
{$IFDEF TEST}
{$DEFINE CIPHER_TEST}
{$ENDIF}
{$IFDEF PROFILE}
{$DEFINE CIPHER_PROFILE}
{$ENDIF}
{$ENDIF}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,761 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherAES.pas }
{ File version: 5.02 }
{ Description: AES cipher routines }
{ }
{ Copyright: Copyright (c) 2010-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ References: }
{ }
{ http://www.comms.scitech.sussex.ac.uk/fft/crypto/aesspec.pdf }
{ http://people.eku.edu/styere/Encrypt/JS-AES.html }
{ }
{ Revision history: }
{ }
{ 2010/12/15 4.01 Initial version. }
{ 2019/09/23 5.02 Optimisation. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
unit flcCipherAES;
interface
uses
{ Fundamentals }
flcStdTypes;
{ }
{ AES }
{ }
const
AESBlockSize = 16; // 128 bits
AES_Nb = 4; // Input bits (128) divided by 32. Fixed number for AES-128, AES-192 and AES-256.
AES_Nr_Max = 14; // Maximum number of rounds
AES_KeyScheduleSize = AES_Nb * (AES_Nr_Max + 1);
type
TAESState = array[0..3, 0..AES_Nb - 1] of Byte;
TAESKeySchedule = array[0..AES_KeyScheduleSize - 1] of Word32;
TAESContext = record
Nk : Byte; // Nk = length of cipher key in multiples of 32 bits (4, 6 or 8)
Nr : Byte; // Nr = number of rounds
State : TAESState;
W : TAESKeySchedule;
end;
PAESContext = ^TAESContext;
const
AESContextSize = SizeOf(TAESContext);
procedure AESContextInit(var Context: TAESContext; const KeySize: Integer);
procedure AESContextFinalise(var Context: TAESContext);
procedure AESInit(var Context: TAESContext;
const KeySize: Integer;
const KeyBuf; const KeyBufSize: Integer);
procedure AESEncryptBlock(
var Context: TAESContext;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
procedure AESDecryptBlock(
var Context: TAESContext;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
procedure AESFinalise(var Context: TAESContext);
procedure AESEncrypt(
const KeySize: Integer;
const KeyBuf; const KeyBufSize: Integer;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
procedure AESDecrypt(
const KeySize: Integer;
const KeyBuf; const KeyBufSize: Integer;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
{ }
{ Test cases }
{ }
{$IFDEF CIPHER_TEST}
procedure Test;
{$ENDIF}
implementation
uses
{ Cipher }
flcCipherUtils;
{ AES S-Box and inverse S-Box }
const
AES_S : array[Byte] of Byte = (
$63, $7c, $77, $7b, $f2, $6b, $6f, $c5, $30, $01, $67, $2b, $fe, $d7, $ab, $76,
$ca, $82, $c9, $7d, $fa, $59, $47, $f0, $ad, $d4, $a2, $af, $9c, $a4, $72, $c0,
$b7, $fd, $93, $26, $36, $3f, $f7, $cc, $34, $a5, $e5, $f1, $71, $d8, $31, $15,
$04, $c7, $23, $c3, $18, $96, $05, $9a, $07, $12, $80, $e2, $eb, $27, $b2, $75,
$09, $83, $2c, $1a, $1b, $6e, $5a, $a0, $52, $3b, $d6, $b3, $29, $e3, $2f, $84,
$53, $d1, $00, $ed, $20, $fc, $b1, $5b, $6a, $cb, $be, $39, $4a, $4c, $58, $cf,
$d0, $ef, $aa, $fb, $43, $4d, $33, $85, $45, $f9, $02, $7f, $50, $3c, $9f, $a8,
$51, $a3, $40, $8f, $92, $9d, $38, $f5, $bc, $b6, $da, $21, $10, $ff, $f3, $d2,
$cd, $0c, $13, $ec, $5f, $97, $44, $17, $c4, $a7, $7e, $3d, $64, $5d, $19, $73,
$60, $81, $4f, $dc, $22, $2a, $90, $88, $46, $ee, $b8, $14, $de, $5e, $0b, $db,
$e0, $32, $3a, $0a, $49, $06, $24, $5c, $c2, $d3, $ac, $62, $91, $95, $e4, $79,
$e7, $c8, $37, $6d, $8d, $d5, $4e, $a9, $6c, $56, $f4, $ea, $65, $7a, $ae, $08,
$ba, $78, $25, $2e, $1c, $a6, $b4, $c6, $e8, $dd, $74, $1f, $4b, $bd, $8b, $8a,
$70, $3e, $b5, $66, $48, $03, $f6, $0e, $61, $35, $57, $b9, $86, $c1, $1d, $9e,
$e1, $f8, $98, $11, $69, $d9, $8e, $94, $9b, $1e, $87, $e9, $ce, $55, $28, $df,
$8c, $a1, $89, $0d, $bf, $e6, $42, $68, $41, $99, $2d, $0f, $b0, $54, $bb, $16
);
AES_InvS : array[Byte] of Byte = (
$52, $09, $6a, $d5, $30, $36, $a5, $38, $bf, $40, $a3, $9e, $81, $f3, $d7, $fb,
$7c, $e3, $39, $82, $9b, $2f, $ff, $87, $34, $8e, $43, $44, $c4, $de, $e9, $cb,
$54, $7b, $94, $32, $a6, $c2, $23, $3d, $ee, $4c, $95, $0b, $42, $fa, $c3, $4e,
$08, $2e, $a1, $66, $28, $d9, $24, $b2, $76, $5b, $a2, $49, $6d, $8b, $d1, $25,
$72, $f8, $f6, $64, $86, $68, $98, $16, $d4, $a4, $5c, $cc, $5d, $65, $b6, $92,
$6c, $70, $48, $50, $fd, $ed, $b9, $da, $5e, $15, $46, $57, $a7, $8d, $9d, $84,
$90, $d8, $ab, $00, $8c, $bc, $d3, $0a, $f7, $e4, $58, $05, $b8, $b3, $45, $06,
$d0, $2c, $1e, $8f, $ca, $3f, $0f, $02, $c1, $af, $bd, $03, $01, $13, $8a, $6b,
$3a, $91, $11, $41, $4f, $67, $dc, $ea, $97, $f2, $cf, $ce, $f0, $b4, $e6, $73,
$96, $ac, $74, $22, $e7, $ad, $35, $85, $e2, $f9, $37, $e8, $1c, $75, $df, $6e,
$47, $f1, $1a, $71, $1d, $29, $c5, $89, $6f, $b7, $62, $0e, $aa, $18, $be, $1b,
$fc, $56, $3e, $4b, $c6, $d2, $79, $20, $9a, $db, $c0, $fe, $78, $cd, $5a, $f4,
$1f, $dd, $a8, $33, $88, $07, $c7, $31, $b1, $12, $10, $59, $27, $80, $ec, $5f,
$60, $51, $7f, $a9, $19, $b5, $4a, $0d, $2d, $e5, $7a, $9f, $93, $c9, $9c, $ef,
$a0, $e0, $3b, $4d, $ae, $2a, $f5, $b0, $c8, $eb, $bb, $3c, $83, $53, $99, $61,
$17, $2b, $04, $7e, $ba, $77, $d6, $26, $e1, $69, $14, $63, $55, $21, $0c, $7d
);
{ AES parameters }
function AES_Nr(const KeySize: Integer): Integer; // Number of rounds
begin
case KeySize of
128 : Result := 10;
192 : Result := 12;
256 : Result := 14;
else
raise ECipher.Create(CipherError_InvalidKeySize, 'Invalid AES key length');
end;
end;
{ AES context }
procedure AESContextInit(var Context: TAESContext; const KeySize: Integer);
begin
if (KeySize <> 128) and
(KeySize <> 192) and
(KeySize <> 256) then
raise ECipher.Create(CipherError_InvalidKeySize, 'Invalid AES key length');
FillChar(Context, SizeOf(Context), 0);
Context.Nk := KeySize div 32;
Context.Nr := AES_Nr(KeySize);
end;
procedure AESContextFinalise(var Context: TAESContext);
begin
SecureClear(Context, SizeOf(Context));
end;
{ AES transformations }
{$R-,Q-}
procedure SubBytes(var State: TAESState);
var R : Byte;
P : PByte;
begin
// assumes AES_Nb = 4
for R := 0 to 3 do
begin
P := @State[R, 0];
P^ := AES_S[P^];
Inc(P);
P^ := AES_S[P^];
Inc(P);
P^ := AES_S[P^];
Inc(P);
P^ := AES_S[P^];
end;
end;
procedure InvSubBytes(var State: TAESState);
var R : Byte;
P : PByte;
begin
// assumes AES_Nb = 4
for R := 0 to 3 do
begin
P := @State[R, 0];
P^ := AES_InvS[P^];
Inc(P);
P^ := AES_InvS[P^];
Inc(P);
P^ := AES_InvS[P^];
Inc(P);
P^ := AES_InvS[P^];
end;
end;
procedure ShiftRows(var State: TAESState);
// assumes AES_Nb = 4
var
// T : Word32;
T0, T1, T2, T3 : Byte;
begin
{
T := PWord32(@State[1])^;
T := (T shr 8) or Word32(T shl 24);
PWord32(@State[1])^ := T;
}
T0 := State[1, 1];
T1 := State[1, 2];
T2 := State[1, 3];
T3 := State[1, 0];
State[1, 0] := T0;
State[1, 1] := T1;
State[1, 2] := T2;
State[1, 3] := T3;
{
T := PWord32(@State[2])^;
T := (T shr 16) or Word32(T shl 16);
PWord32(@State[2])^ := T;
}
T0 := State[2, 2];
T1 := State[2, 3];
T2 := State[2, 0];
T3 := State[2, 1];
State[2, 0] := T0;
State[2, 1] := T1;
State[2, 2] := T2;
State[2, 3] := T3;
{
T := PWord32(@State[3])^;
T := (T shr 24) or Word32(T shl 8);
PWord32(@State[3])^ := T;
}
T0 := State[3, 3];
T1 := State[3, 0];
T2 := State[3, 1];
T3 := State[3, 2];
State[3, 0] := T0;
State[3, 1] := T1;
State[3, 2] := T2;
State[3, 3] := T3;
end;
procedure InvShiftRows(var State: TAESState);
// assumes AES_Nb = 4
var
T0, T1, T2, T3 : Byte;
begin
T1 := State[1, 0];
T2 := State[1, 1];
T3 := State[1, 2];
T0 := State[1, 3];
State[1, 0] := T0;
State[1, 1] := T1;
State[1, 2] := T2;
State[1, 3] := T3;
T2 := State[2, 0];
T3 := State[2, 1];
T0 := State[2, 2];
T1 := State[2, 3];
State[2, 0] := T0;
State[2, 1] := T1;
State[2, 2] := T2;
State[2, 3] := T3;
T3 := State[3, 0];
T0 := State[3, 1];
T1 := State[3, 2];
T2 := State[3, 3];
State[3, 0] := T0;
State[3, 1] := T1;
State[3, 2] := T2;
State[3, 3] := T3;
end;
const
FFLog : array[Byte] of Byte = (
$00, $00, $19, $01, $32, $02, $1a, $c6, $4b, $c7, $1b, $68, $33, $ee, $df, $03,
$64, $04, $e0, $0e, $34, $8d, $81, $ef, $4c, $71, $08, $c8, $f8, $69, $1c, $c1,
$7d, $c2, $1d, $b5, $f9, $b9, $27, $6a, $4d, $e4, $a6, $72, $9a, $c9, $09, $78,
$65, $2f, $8a, $05, $21, $0f, $e1, $24, $12, $f0, $82, $45, $35, $93, $da, $8e,
$96, $8f, $db, $bd, $36, $d0, $ce, $94, $13, $5c, $d2, $f1, $40, $46, $83, $38,
$66, $dd, $fd, $30, $bf, $06, $8b, $62, $b3, $25, $e2, $98, $22, $88, $91, $10,
$7e, $6e, $48, $c3, $a3, $b6, $1e, $42, $3a, $6b, $28, $54, $fa, $85, $3d, $ba,
$2b, $79, $0a, $15, $9b, $9f, $5e, $ca, $4e, $d4, $ac, $e5, $f3, $73, $a7, $57,
$af, $58, $a8, $50, $f4, $ea, $d6, $74, $4f, $ae, $e9, $d5, $e7, $e6, $ad, $e8,
$2c, $d7, $75, $7a, $eb, $16, $0b, $f5, $59, $cb, $5f, $b0, $9c, $a9, $51, $a0,
$7f, $0c, $f6, $6f, $17, $c4, $49, $ec, $d8, $43, $1f, $2d, $a4, $76, $7b, $b7,
$cc, $bb, $3e, $5a, $fb, $60, $b1, $86, $3b, $52, $a1, $6c, $aa, $55, $29, $9d,
$97, $b2, $87, $90, $61, $be, $dc, $fc, $bc, $95, $cf, $cd, $37, $3f, $5b, $d1,
$53, $39, $84, $3c, $41, $a2, $6d, $47, $14, $2a, $9e, $5d, $56, $f2, $d3, $ab,
$44, $11, $92, $d9, $23, $20, $2e, $89, $b4, $7c, $b8, $26, $77, $99, $e3, $a5,
$67, $4a, $ed, $de, $c5, $31, $fe, $18, $0d, $63, $8c, $80, $c0, $f7, $70, $07);
FFPow : array[Byte] of Byte = (
$01, $03, $05, $0f, $11, $33, $55, $ff, $1a, $2e, $72, $96, $a1, $f8, $13, $35,
$5f, $e1, $38, $48, $d8, $73, $95, $a4, $f7, $02, $06, $0a, $1e, $22, $66, $aa,
$e5, $34, $5c, $e4, $37, $59, $eb, $26, $6a, $be, $d9, $70, $90, $ab, $e6, $31,
$53, $f5, $04, $0c, $14, $3c, $44, $cc, $4f, $d1, $68, $b8, $d3, $6e, $b2, $cd,
$4c, $d4, $67, $a9, $e0, $3b, $4d, $d7, $62, $a6, $f1, $08, $18, $28, $78, $88,
$83, $9e, $b9, $d0, $6b, $bd, $dc, $7f, $81, $98, $b3, $ce, $49, $db, $76, $9a,
$b5, $c4, $57, $f9, $10, $30, $50, $f0, $0b, $1d, $27, $69, $bb, $d6, $61, $a3,
$fe, $19, $2b, $7d, $87, $92, $ad, $ec, $2f, $71, $93, $ae, $e9, $20, $60, $a0,
$fb, $16, $3a, $4e, $d2, $6d, $b7, $c2, $5d, $e7, $32, $56, $fa, $15, $3f, $41,
$c3, $5e, $e2, $3d, $47, $c9, $40, $c0, $5b, $ed, $2c, $74, $9c, $bf, $da, $75,
$9f, $ba, $d5, $64, $ac, $ef, $2a, $7e, $82, $9d, $bc, $df, $7a, $8e, $89, $80,
$9b, $b6, $c1, $58, $e8, $23, $65, $af, $ea, $25, $6f, $b1, $c8, $43, $c5, $54,
$fc, $1f, $21, $63, $a5, $f4, $07, $09, $1b, $2d, $77, $99, $b0, $cb, $46, $ca,
$45, $cf, $4a, $de, $79, $8b, $86, $91, $a8, $e3, $3e, $42, $c6, $51, $f3, $0e,
$12, $36, $5a, $ee, $29, $7b, $8d, $8c, $8f, $8a, $85, $94, $a7, $f2, $0d, $17,
$39, $4b, $dd, $7c, $84, $97, $a2, $fd, $1c, $24, $6c, $b4, $c7, $52, $f6, $01);
function FFmul(const A, B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if (A <> 0) and (B <> 0) then
begin
T := FFLog[A] + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
function FFmul2(const B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if B <> 0 then
begin
T := $19 + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
function FFmul3(const B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if B <> 0 then
begin
T := $01 + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
function FFmulE(const B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if B <> 0 then
begin
T := $df + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
function FFmulB(const B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if B <> 0 then
begin
T := $68 + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
function FFmulD(const B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if B <> 0 then
begin
T := $ee + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
function FFmul9(const B: Byte): Byte; {$IFDEF UseInline}inline;{$ENDIF}
var
T : Word;
begin
if B <> 0 then
begin
T := $c7 + FFLog[B];
if T >= 255 then
Dec(T, 255);
Result := FFPow[T];
end
else
Result := 0;
end;
procedure MixColumns(var State: TAESState);
var
T0, T1, T2, T3 : Byte;
C : Byte;
begin
for C := 0 to AES_Nb - 1 do
begin
T0 := State[0, C];
T1 := State[1, C];
T2 := State[2, C];
T3 := State[3, C];
State[0, C] := FFmul2(T0) xor FFmul3(T1) xor T2 xor T3;
State[1, C] := FFmul2(T1) xor FFmul3(T2) xor T3 xor T0;
State[2, C] := FFmul2(T2) xor FFmul3(T3) xor T0 xor T1;
State[3, C] := FFmul2(T3) xor FFmul3(T0) xor T1 xor T2;
end;
end;
procedure InvMixColumns(var State: TAESState);
var
T0, T1, T2, T3 : Byte;
C : Byte;
begin
for C := 0 to AES_Nb - 1 do
begin
T0 := State[0, C];
T1 := State[1, C];
T2 := State[2, C];
T3 := State[3, C];
State[0, C] := FFmulE(T0) xor FFmulB(T1) xor FFmulD(T2) xor FFmul9(T3);
State[1, C] := FFmulE(T1) xor FFmulB(T2) xor FFmulD(T3) xor FFmul9(T0);
State[2, C] := FFmulE(T2) xor FFmulB(T3) xor FFmulD(T0) xor FFmul9(T1);
State[3, C] := FFmulE(T3) xor FFmulB(T0) xor FFmulD(T1) xor FFmul9(T2);
end;
end;
function xbyte(const R: Byte; const K: Word32): Byte; {$IFDEF UseInline}inline;{$ENDIF}
begin
Result := Byte((K shr (R * 8)) and $FF);
end;
procedure XorRoundKey(var State: TAESState; const Rk: TAESKeySchedule; const RkIdx: Integer);
var C : Byte;
P : PByte;
RkP : PWord32;
RkC : Word32;
begin
RkP := @Rk[RkIdx];
for C := 0 to AES_Nb - 1 do
begin
RkC := RkP^;
P := @State[0, C];
P^ := P^ xor xbyte(0, RkC);
P := @State[1, C];
P^ := P^ xor xbyte(1, RkC);
P := @State[2, C];
P^ := P^ xor xbyte(2, RkC);
P := @State[3, C];
P^ := P^ xor xbyte(3, RkC);
Inc(RkP);
end;
end;
{ AES key expansion }
function SubWord(const A: Word32): Word32; {$IFDEF UseInline}inline;{$ENDIF}
begin
Result :=
AES_S[Byte (A and $000000FF)] or
(AES_S[Byte((A and $0000FF00) shr 8)] shl 8) or
(AES_S[Byte((A and $00FF0000) shr 16)] shl 16) or
(AES_S[Byte((A and $FF000000) shr 24)] shl 24);
end;
function RotWord(const A: Word32): Word32; {$IFDEF UseInline}inline;{$ENDIF}
begin
Result :=
((A and $FFFFFF00) shr 8) or
((A and $000000FF) shl 24);
end;
const
AES_Rcon : array[Byte] of Byte = (
$8d, $01, $02, $04, $08, $10, $20, $40, $80, $1b, $36, $6c, $d8, $ab, $4d, $9a,
$2f, $5e, $bc, $63, $c6, $97, $35, $6a, $d4, $b3, $7d, $fa, $ef, $c5, $91, $39,
$72, $e4, $d3, $bd, $61, $c2, $9f, $25, $4a, $94, $33, $66, $cc, $83, $1d, $3a,
$74, $e8, $cb, $8d, $01, $02, $04, $08, $10, $20, $40, $80, $1b, $36, $6c, $d8,
$ab, $4d, $9a, $2f, $5e, $bc, $63, $c6, $97, $35, $6a, $d4, $b3, $7d, $fa, $ef,
$c5, $91, $39, $72, $e4, $d3, $bd, $61, $c2, $9f, $25, $4a, $94, $33, $66, $cc,
$83, $1d, $3a, $74, $e8, $cb, $8d, $01, $02, $04, $08, $10, $20, $40, $80, $1b,
$36, $6c, $d8, $ab, $4d, $9a, $2f, $5e, $bc, $63, $c6, $97, $35, $6a, $d4, $b3,
$7d, $fa, $ef, $c5, $91, $39, $72, $e4, $d3, $bd, $61, $c2, $9f, $25, $4a, $94,
$33, $66, $cc, $83, $1d, $3a, $74, $e8, $cb, $8d, $01, $02, $04, $08, $10, $20,
$40, $80, $1b, $36, $6c, $d8, $ab, $4d, $9a, $2f, $5e, $bc, $63, $c6, $97, $35,
$6a, $d4, $b3, $7d, $fa, $ef, $c5, $91, $39, $72, $e4, $d3, $bd, $61, $c2, $9f,
$25, $4a, $94, $33, $66, $cc, $83, $1d, $3a, $74, $e8, $cb, $8d, $01, $02, $04,
$08, $10, $20, $40, $80, $1b, $36, $6c, $d8, $ab, $4d, $9a, $2f, $5e, $bc, $63,
$c6, $97, $35, $6a, $d4, $b3, $7d, $fa, $ef, $c5, $91, $39, $72, $e4, $d3, $bd,
$61, $c2, $9f, $25, $4a, $94, $33, $66, $cc, $83, $1d, $3a, $74, $e8, $cb, $00);
procedure AESKeyExpansion(var Context: TAESContext; const KeyBuf; const KeyBufSize: Integer);
var Nk : Byte;
I : Integer;
T : Word32;
P : PWord32;
begin
Nk := Context.Nk;
if KeyBufSize <> Nk * 4 then
raise ECipher.Create(CipherError_InvalidBufferSize, 'Invalid key size');
P := @KeyBuf;
for I := 0 to Nk - 1 do
begin
Context.W[I] := P^;
Inc(P);
end;
for I := Nk to AES_Nb * (Context.Nr + 1) - 1 do
begin
T := Context.W[I - 1];
if I mod Nk = 0 then
begin
T := RotWord(T);
T := SubWord(T);
T := T xor AES_Rcon[I div Nk];
end else
if (Nk = 8) and (I mod Nk = 4) then
T := SubWord(T);
Context.W[I] := Context.W[I - Nk] xor T;
end;
end;
{ AES cipher and inverse cipher }
procedure InBufToState(var Context: TAESContext; const InBuf; const InBufSize: Integer);
var R, C : Byte;
P : PByte;
begin
if InBufSize <> AES_Nb * 4 then
raise ECipher.Create(CipherError_InvalidBufferSize, 'Invalid buffer size');
for R := 0 to 3 do
for C := 0 to AES_Nb - 1 do
begin
P := @InBuf;
Inc(P, R + 4 * C);
Context.State[R, C] := P^;
end;
end;
procedure StateToOutBuf(var Context: TAESContext; var OutBuf; const OutBufSize: Integer);
var R, C : Byte;
P : PByte;
begin
if OutBufSize < AES_Nb * 4 then
raise ECipher.Create(CipherError_InvalidBufferSize, 'Invalid buffer size');
for C := 0 to AES_Nb - 1 do
for R := 0 to 3 do
begin
P := @OutBuf;
Inc(P, R + 4 * C);
P^ := Context.State[R, C];
end;
end;
procedure AESCipher(var Context: TAESContext;
const InBuf; const InBufSize: Integer;
var OutBuf; const OutBufSize: Integer);
var R : Integer;
begin
InBufToState(Context, InBuf, InBufSize);
XorRoundKey(Context.State, Context.W, 0);
for R := 1 to Context.Nr - 1 do
begin
SubBytes(Context.State);
ShiftRows(Context.State);
MixColumns(Context.State);
XorRoundKey(Context.State, Context.W, R * AES_Nb);
end;
SubBytes(Context.State);
ShiftRows(Context.State);
XorRoundKey(Context.State, Context.W, Context.Nr * AES_Nb);
StateToOutBuf(Context, OutBuf, OutBufSize);
end;
procedure AESInvCipher(var Context: TAESContext;
const InBuf; const InBufSize: Integer;
var OutBuf; const OutBufSize: Integer);
var R : Integer;
begin
InBufToState(Context, InBuf, InBufSize);
XorRoundKey(Context.State, Context.W, Context.Nr * AES_Nb);
for R := Context.Nr - 1 downto 1 do
begin
InvShiftRows(Context.State);
InvSubBytes(Context.State);
XorRoundKey(Context.State, Context.W, R * AES_Nb);
InvMixColumns(Context.State);
end;
InvShiftRows(Context.State);
InvSubBytes(Context.State);
XorRoundKey(Context.State, Context.W, 0);
StateToOutBuf(Context, OutBuf, OutBufSize);
end;
{ AES encrypt and decrypt }
procedure AESInit(var Context: TAESContext;
const KeySize: Integer;
const KeyBuf; const KeyBufSize: Integer);
begin
AESContextInit(Context, KeySize);
AESKeyExpansion(Context, KeyBuf, KeyBufSize);
end;
procedure AESEncryptBlock(
var Context: TAESContext;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
begin
AESCipher(Context, DataBuf, DataBufSize, CipherBuf, CipherBufSize)
end;
procedure AESDecryptBlock(
var Context: TAESContext;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
begin
AESInvCipher(Context, DataBuf, DataBufSize, CipherBuf, CipherBufSize)
end;
procedure AESFinalise(var Context: TAESContext);
begin
AESContextFinalise(Context);
end;
procedure AESEncrypt(
const KeySize: Integer;
const KeyBuf; const KeyBufSize: Integer;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
var Context: TAESContext;
begin
AESContextInit(Context, KeySize);
AESKeyExpansion(Context, KeyBuf, KeyBufSize);
AESCipher(Context, DataBuf, DataBufSize, CipherBuf, CipherBufSize);
AESContextFinalise(Context);
end;
procedure AESDecrypt(
const KeySize: Integer;
const KeyBuf; const KeyBufSize: Integer;
const DataBuf; const DataBufSize: Integer;
var CipherBuf; const CipherBufSize: Integer);
var Context: TAESContext;
begin
AESContextInit(Context, KeySize);
AESKeyExpansion(Context, KeyBuf, KeyBufSize);
AESInvCipher(Context, DataBuf, DataBufSize, CipherBuf, CipherBufSize);
AESContextFinalise(Context);
end;
{ }
{ Test cases }
{ }
{$IFDEF CIPHER_TEST}
{$ASSERTIONS ON}
procedure Test;
var K, T, B : RawByteString;
begin
K := RawByteString(#$0f#$15#$71#$c9#$47#$d9#$e8#$59#$0c#$b7#$ad#$d6#$af#$7f#$67#$98);
T := '1234567890123456';
SetLength(B, 16);
AESEncrypt(128, K[1], Length(K), T[1], Length(T), B[1], Length(B));
Assert(B = #$2f#$7d#$76#$42#$5e#$bb#$85#$e4#$f2#$e7#$b0#$08#$68#$bf#$0f#$ce);
T := '00000000000000000';
AESDecrypt(128, K[1], Length(K), B[1], Length(B), T[1], Length(T));
Assert(T = '12345678901234560');
end;
{$ENDIF}
end.

View File

@@ -0,0 +1,590 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherDES.pas }
{ File version: 5.04 }
{ Description: DES cipher routines }
{ }
{ Copyright: Copyright (c) 2007-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ References: }
{ }
{ DES 40 - http://www.watersprings.org/pub/id/draft-hoffman-des40-00.txt }
{ }
{ Revision history: }
{ }
{ 2007/01/06 4.01 DES and Triple-DES }
{ 2010/12/16 4.02 DES-40 }
{ 2019/06/09 5.03 Triple-DES3 buffer functions for Encrypt and Decrypt. }
{ 2019/09/22 5.04 Optimisations. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
{$IFDEF FREEPASCAL}
{$R-}
{$ENDIF}
unit flcCipherDES;
interface
uses
{ Fundamentals }
flcStdTypes;
{ }
{ DES }
{ Data Encryption Standard. }
{ FIPS-46 became a US NBS standard in 1977. }
{ }
type
TDESKey = array[0..7] of Byte;
PDESKey = ^TDESKey;
TDESWord32Pair = array[0..1] of Word32;
PDESWord32Pair = ^TDESWord32Pair;
TDESContext = array[1..16] of TDESWord32Pair;
PDESContext = ^TDESContext;
TDESBlock = array[0..7] of Byte;
PDESBlock = ^TDESBlock;
const
DESBlockSize = 8;
DESContextSize = SizeOf(TDESContext);
procedure DESInit(const Encrypt: Boolean; const Key: TDESKey; var Context: TDESContext);
procedure DESBuffer(const Context: TDESContext; var Block: TDESBlock);
{ }
{ DES-40 }
{ }
procedure DESKeyConvertToDES40(var Key: TDESKey);
{ }
{ Triple-DES-EDE }
{ Also known as 2-key Triple-DES }
{ }
type
TTripleDESKey = array[0..1] of TDESKey;
PTripleDESKey = ^TTripleDESKey;
TTripleDESContext = array[0..1] of TDESContext;
PTripleDESContext = ^TTripleDESContext;
const
TripleDESContextSize = SizeOf(TTripleDESContext);
procedure TripleDESInit(const Encrypt: Boolean; const Key: TTripleDESKey;
var Context: TTripleDESContext);
procedure TripleDESBuffer(const Context: TTripleDESContext; var Block: TDESBlock);
{ }
{ Triple-DES-3 (EDE and EEE modes) }
{ Also known as 3-key Triple-DES }
{ }
type
TTripleDES3Key = array[0..2] of TDESKey;
PTripleDES3Key = ^TTripleDES3Key;
TTripleDES3Context = array[0..2] of TDESContext;
PTripleDES3Context = ^TTripleDES3Context;
const
TripleDES3ContextSize = SizeOf(TTripleDES3Context);
procedure TripleDES3Init(const Encrypt: Boolean; const Key: TTripleDES3Key;
const EEEMode: Boolean; var Context: TTripleDES3Context);
procedure TripleDES3BufferEncrypt(const Context: TTripleDES3Context; var Block: TDESBlock);
procedure TripleDES3BufferDecrypt(const Context: TTripleDES3Context; var Block: TDESBlock);
implementation
uses
{ Cipher }
flcCipherUtils;
{ }
{ DES }
{ }
const
// DES PC-1 (key permutation 1) table
DESPC1Table : array[0..55] of Byte = (
57, 49, 41, 33, 25, 17, 9,
1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27,
19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15,
7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29,
21, 13, 5, 28, 20, 12, 4);
// DES key shift table
DESKeyShiftTable : array[1..16] of Byte = (
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1);
// DES PC-2 (key permuation 2) table
DESPC2Table : array[0..47] of Byte = (
14, 17, 11, 24, 1, 5,
3, 28, 15, 6, 21, 10,
23, 19, 12, 4, 26, 8,
16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55,
30, 40, 51, 45, 33, 48,
44, 49, 39, 56, 34, 53,
46, 42, 50, 36, 29, 32);
// DES IP (initial permutation) table
DESIPTable : array[0..63] of Byte = (
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6,
64, 56, 48, 40, 32, 24, 16, 8,
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7);
// DES E bit-selection table
DESETable : array[0..47] of Byte = (
32, 1, 2, 3, 4, 5,
4, 5, 6, 7, 8, 9,
8, 9, 10, 11, 12, 13,
12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21,
20, 21, 22, 23, 24, 25,
24, 25, 26, 27, 28, 29,
28, 29, 30, 31, 32, 1);
// DES S boxes (S1..S8)
DESSTable : array[0..7, 0..63] of Byte = (
(14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7,
0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8,
4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0,
15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13),
(15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10,
3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5,
0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15,
13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9),
(10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8,
13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1,
13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7,
1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12),
( 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15,
13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9,
10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4,
3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14),
( 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9,
14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6,
4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14,
11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3),
(12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11,
10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8,
9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6,
4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13),
( 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1,
13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6,
1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2,
6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12),
(13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7,
1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2,
7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8,
2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11));
// DES P (permutation) table
DESPTable : array[0..31] of Byte = (
16, 7, 20, 21, 29, 12, 28, 17,
1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9,
19, 13, 30, 6, 22, 11, 4, 25);
// DES IP-1 table
DESIP1Table : array[0..63] of Byte = (
40, 8, 48, 16, 56, 24, 64, 32,
39, 7, 47, 15, 55, 23, 63, 31,
38, 6, 46, 14, 54, 22, 62, 30,
37, 5, 45, 13, 53, 21, 61, 29,
36, 4, 44, 12, 52, 20, 60, 28,
35, 3, 43, 11, 51, 19, 59, 27,
34, 2, 42, 10, 50, 18, 58, 26,
33, 1, 41, 9, 49, 17, 57, 25);
// 28 bit ROL operation
function DESROL28(const Value: Word32; const Bits: Byte): Word32;
var I : Integer;
begin
Result := Value;
for I := 1 to Bits do
if Result and $08000000 = 0 then
Result := Result shl 1
else
Result := ((Result and $07FFFFFF) shl 1) or 1;
end;
// 32 bit swap endian
{$IFDEF ASM386}
function DESSwapEndian32(const Value: Word32): Word32;
asm
XCHG AH, AL
ROL EAX, 16
XCHG AH, AL
end;
{$ELSE}
function DESSwapEndian32(const Value: Word32): Word32;
begin
Result := ((Value and $000000FF) shl 24) or
((Value and $0000FF00) shl 8) or
((Value and $00FF0000) shr 8) or
((Value and $FF000000) shr 24);
end;
{$ENDIF}
// PC-1 permutation from K (64 bits) to K+ (56 bits)
function DESPC1Permutation(const K: TDESWord32Pair): TDESWord32Pair;
var I : Integer;
N : Byte;
begin
Result[0] := 0;
Result[1] := 0;
for I := 0 to 55 do
begin
N := DESPC1Table[I] - 1;
if K[N div 32] and (1 shl (31 - (N mod 32))) <> 0 then
Result[I div 32] := Result[I div 32] or (1 shl (31 - (I mod 32)));
end;
end;
// PC-2 permutation from CnDn (56 bits) to Kn (48 bits)
function DESPC2Permutation(const K: TDESWord32Pair): TDESWord32Pair;
var I : Integer;
N : Byte;
begin
Result[0] := 0;
Result[1] := 0;
for I := 0 to 47 do
begin
N := DESPC2Table[I] - 1;
if K[N div 32] and (1 shl (31 - (N mod 32))) <> 0 then
Result[I div 32] := Result[I div 32] or (1 shl (31 - (I mod 32)));
end;
end;
// DES initialization
procedure DESInit(const Encrypt: Boolean; const Key: TDESKey; var Context: TDESContext);
var K : TDESWord32Pair;
C, D : array[0..16] of Word32;
I, J : Integer;
N : Byte;
E : TDESWord32Pair;
begin
// Move key into K and swap endian
Move(Key, K, Sizeof(K));
K[0] := DESSwapEndian32(K[0]);
K[1] := DESSwapEndian32(K[1]);
// PC-1 permutation from KD (64 bits) into KP (56 bits)
K := DESPC1Permutation(K);
// Split KP into C0 and D0 (28 bits each)
C[0] := (K[0] and $FFFFFFF0) shr 4;
D[0] := ((K[0] and $0000000F) shl 24) or ((K[1] and $FFFFFF00) shr 8);
SecureClear(K, Sizeof(K));
// Generate C1..C16 and D1..D16 using shift table
for I := 1 to 16 do
begin
N := DESKeyShiftTable[I];
C[I] := DESROL28(C[I - 1], N);
D[I] := DESROL28(D[I - 1], N);
end;
// PC-2 permutation from C1..16 (28 bits) and D1..16 (28 bits) into K1..K16 (48 bits)
for I := 1 to 16 do
begin
E[0] := (C[I] shl 4) or (D[I] shr 24);
E[1] := D[I] shl 8;
if Encrypt then
J := I
else
J := 17 - I;
Context[J] := DESPC2Permutation(E);
end;
SecureClear(C, Sizeof(C));
SecureClear(D, Sizeof(D));
SecureClear(E, Sizeof(E));
end;
{$R-,Q-}
// DES E bit-selection table (modified for bit operation optimisation)
const
DESETable_Mod : array[0..47] of Word32 = (
1 shl (32 - 32), Word32(1) shl (32 - 1), 1 shl (32 - 2), 1 shl (32 - 3), 1 shl (32 - 4), 1 shl (32 - 5),
1 shl (32 - 4), 1 shl (32 - 5), 1 shl (32 - 6), 1 shl (32 - 7), 1 shl (32 - 8), 1 shl (32 - 9),
1 shl (32 - 8), 1 shl (32 - 9), 1 shl (32 - 10), 1 shl (32 - 11), 1 shl (32 - 12), 1 shl (32 - 13),
1 shl (32 - 12), 1 shl (32 - 13), 1 shl (32 - 14), 1 shl (32 - 15), 1 shl (32 - 16), 1 shl (32 - 17),
1 shl (32 - 16), 1 shl (32 - 17), 1 shl (32 - 18), 1 shl (32 - 19), 1 shl (32 - 20), 1 shl (32 - 21),
1 shl (32 - 20), 1 shl (32 - 21), 1 shl (32 - 22), 1 shl (32 - 23), 1 shl (32 - 24), 1 shl (32 - 25),
1 shl (32 - 24), 1 shl (32 - 25), 1 shl (32 - 26), 1 shl (32 - 27), 1 shl (32 - 28), 1 shl (32 - 29),
1 shl (32 - 28), 1 shl (32 - 29), 1 shl (32 - 30), 1 shl (32 - 31), 1 shl (32 - 32), Word32(1) shl (32 - 1));
// DES P (permutation) table (modified for bit operation optimisation)
DESPTable_Mod : array[0..31] of Word32 = (
1 shl (32 - 16), 1 shl (32 - 7), 1 shl (32 - 20), 1 shl (32 - 21), 1 shl (32 - 29), 1 shl (32 - 12), 1 shl (32 - 28), 1 shl (32 - 17),
Word32(1) shl (32 - 1), 1 shl (32 - 15), 1 shl (32 - 23), 1 shl (32 - 26), 1 shl (32 - 5), 1 shl (32 - 18), 1 shl (32 - 31), 1 shl (32 - 10),
1 shl (32 - 2), 1 shl (32 - 8), 1 shl (32 - 24), 1 shl (32 - 14), 1 shl (32 - 32), 1 shl (32 - 27), 1 shl (32 - 3), 1 shl (32 - 9),
1 shl (32 - 19), 1 shl (32 - 13), 1 shl (32 - 30), 1 shl (32 - 6), 1 shl (32 - 22), 1 shl (32 - 11), 1 shl (32 - 4), 1 shl (32 - 25));
// DES E-function
function DESEFunc(const R: Word32; const K: TDESWord32Pair): Word32;
var E0, E1 : Word32;
B : Word32;
I : Integer;
BI, SI : Byte;
X, Y : Byte;
S : Word32;
begin
// Expand R (32 bits) to E (48 bits) using E bit-selection table
E0 := 0;
E1 := 0;
B := Word32(1) shl 31;
for I := 0 to 31 do
begin
if R and DESETable_Mod[I] <> 0 then
E0 := E0 or B;
B := B shr 1;
end;
B := Word32(1) shl 31;
for I := 32 to 47 do
begin
if R and DESETable_Mod[I] <> 0 then
E1 := E1 or B;
B := B shr 1;
end;
// Apply key (48 bits) to E
E0 := E0 xor K[0];
E1 := E1 xor K[1];
// Apply S boxes on 8 groups of 6 bits
S := 0;
for I := 0 to 7 do
begin
case I of
0..4 : BI := (E0 shr (26 - (I * 6))) and $3F;
5 : BI := ((E0 and $00000003) shl 4) or
((E1 and $F0000000) shr 28);
else BI := (E1 shr (22 + 36 - (I * 6))) and $3F;
end; // BI = Bi (6 bits) from E
Y := (BI and 1) or ((BI and $20) shr 4); // Y = Row (first and last bits of Bi)
X := (BI and $1E) shr 1; // X = Column (middle 4 bits of Bi)
SI := DESSTable[I, Y * 16 + X]; // SI = Si (4 bits)
S := S or (SI shl (28 - (I * 4))); // S = S0..S7 (32 bits)
end;
// Apply permutation table to S
Result := 0;
B := Word32(1) shl 31;
for I := 0 to 31 do
begin
if S and DESPTable_Mod[I] <> 0 then
Result := Result or B;
B := B shr 1;
end;
end;
// DES block function
procedure DESBuffer(const Context: TDESContext; var Block: TDESBlock);
var IP : TDESBlock;
IPP : PByte;
I : Integer;
IH : Byte;
IL : Byte;
N : Byte;
L, R : array[0..16] of Word32;
P : array[0..1] of Word32;
begin
// Apply initial permuation on M (64 bits) to get IP (64 bits)
FillChar(IP, Sizeof(TDESBlock), 0);
IH := 0;
IPP := @IP[IH];
for I := 0 to 63 do
begin
IL := I and 7;
if IL = 0 then
begin
IH := I shr 3;
IPP := @IP[IH];
end;
N := DESIPTable[I] - 1;
if Block[N shr 3] and (1 shl (7 - (N and 7))) <> 0 then
IPP^ := IPP^ or (1 shl (7 - IL));
end;
// Split IP into L0 and R0 (32 bits each)
L[0] := IP[3] or (IP[2] shl 8) or (IP[1] shl 16) or (IP[0] shl 24);
R[0] := IP[7] or (IP[6] shl 8) or (IP[5] shl 16) or (IP[4] shl 24);
SecureClear(IP, Sizeof(IP));
// Generate L1..L16 and R1..R16
for I := 1 to 16 do
begin
L[I] := R[I - 1];
R[I] := L[I - 1] xor DESEFunc(R[I - 1], Context[I]);
end;
// Combine R16L16 (64 bits)
P[0] := R[16];
P[1] := L[16];
SecureClear(L, Sizeof(L));
SecureClear(R, Sizeof(R));
// Apply IP-1 permutation to R16L16 to get result (64 bits)
FillChar(Block, Sizeof(TDESBlock), 0);
IH := 0;
IPP := @Block[IH];
for I := 0 to 63 do
begin
IL := I and 7;
if IL = 0 then
begin
IH := I shr 3;
IPP := @Block[IH];
end;
N := DESIP1Table[I] - 1;
if P[N shr 5] and (1 shl (31 - (N and $1F))) <> 0 then
IPP^ := IPP^ or (1 shl (7 - IL));
end;
SecureClear(P, Sizeof(P));
end;
{ }
{ DES-40 }
{ }
const
BitCountTable : array[Byte] of Byte =
(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8);
procedure DESSetOddParity(var A: Byte);
begin
if not Odd(BitCountTable[A]) then
A := A xor $80;
end;
procedure DESKeyConvertToDES40(var Key: TDESKey);
var A, B, C, D : Byte;
begin
// clear lower 4 bits of every second byte starting at first byte
A := Key[0] and $F0;
B := Key[2] and $F0;
C := Key[4] and $F0;
D := Key[6] and $F0;
// make parity odd on modified bytes by toggling high bit
DESSetOddParity(A);
DESSetOddParity(B);
DESSetOddParity(C);
DESSetOddParity(D);
// modify key
Key[0] := A;
Key[2] := B;
Key[4] := C;
Key[6] := D;
end;
{ }
{ Triple-DES-EDE }
{ }
procedure TripleDESInit(const Encrypt: Boolean; const Key: TTripleDESKey;
var Context: TTripleDESContext);
begin
DESInit(Encrypt, Key[0], Context[0]);
DESInit(not Encrypt, Key[1], Context[1]);
end;
procedure TripleDESBuffer(const Context: TTripleDESContext; var Block: TDESBlock);
begin
DESBuffer(Context[0], Block);
DESBuffer(Context[1], Block);
DESBuffer(Context[0], Block);
end;
{ }
{ Triple-DES-EDE-3 }
{ }
procedure TripleDES3Init(const Encrypt: Boolean; const Key: TTripleDES3Key;
const EEEMode: Boolean; var Context: TTripleDES3Context);
begin
DESInit(Encrypt, Key[0], Context[0]);
DESInit(not Encrypt xor EEEMode, Key[1], Context[1]);
DESInit(Encrypt, Key[2], Context[2]);
end;
procedure TripleDES3BufferEncrypt(const Context: TTripleDES3Context; var Block: TDESBlock);
begin
DESBuffer(Context[0], Block);
DESBuffer(Context[1], Block);
DESBuffer(Context[2], Block);
end;
procedure TripleDES3BufferDecrypt(const Context: TTripleDES3Context; var Block: TDESBlock);
begin
DESBuffer(Context[2], Block);
DESBuffer(Context[1], Block);
DESBuffer(Context[0], Block);
end;
end.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,273 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherRC2.pas }
{ File version: 5.01 }
{ Description: RC2 cipher routines }
{ }
{ Copyright: Copyright (c) 2007-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2007/01/05 4.01 Initial version. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
unit flcCipherRC2;
interface
{ }
{ RC2 }
{ RC2 was developed by Ron Rivest in 1987. }
{ }
type
TRC2CipherKey = packed record
case Integer of
0 : (Bytes: array[0..127] of Byte);
1 : (Words: array[0..63] of Word);
end;
PRC2CipherKey = ^TRC2CipherKey;
TRC2Block = packed record
case Integer of
0 : (Bytes: array[0..7] of Byte);
1 : (Words: array[0..3] of Word);
2 : (A, B, C, D: Word);
end;
PRC2Block = ^TRC2Block;
const
RC2BlockSize = 8;
procedure RC2Init(const Key; const KeySize: Integer; const KeyBits: Integer;
var CipherKey: TRC2CipherKey);
procedure RC2EncryptBlock(const CipherKey: TRC2CipherKey; var Block: TRC2Block);
procedure RC2DecryptBlock(const CipherKey: TRC2CipherKey; var Block: TRC2Block);
implementation
uses
{ Cipher }
flcCipherUtils;
{ }
{ RC2 }
{ See RFC 2268 for details on the algorithm. }
{ }
// RC2 PITABLE - "Random" values based on value of Pi
const
RC2Table: array[Byte] of Byte = (
$D9, $78, $F9, $C4, $19, $DD, $B5, $ED, $28, $E9, $FD, $79, $4A, $A0, $D8, $9D,
$C6, $7E, $37, $83, $2B, $76, $53, $8E, $62, $4C, $64, $88, $44, $8B, $FB, $A2,
$17, $9A, $59, $F5, $87, $B3, $4F, $13, $61, $45, $6D, $8D, $09, $81, $7D, $32,
$BD, $8F, $40, $EB, $86, $B7, $7B, $0B, $F0, $95, $21, $22, $5C, $6B, $4E, $82,
$54, $D6, $65, $93, $CE, $60, $B2, $1C, $73, $56, $C0, $14, $A7, $8C, $F1, $DC,
$12, $75, $CA, $1F, $3B, $BE, $E4, $D1, $42, $3D, $D4, $30, $A3, $3C, $B6, $26,
$6F, $BF, $0E, $DA, $46, $69, $07, $57, $27, $F2, $1D, $9B, $BC, $94, $43, $03,
$F8, $11, $C7, $F6, $90, $EF, $3E, $E7, $06, $C3, $D5, $2F, $C8, $66, $1E, $D7,
$08, $E8, $EA, $DE, $80, $52, $EE, $F7, $84, $AA, $72, $AC, $35, $4D, $6A, $2A,
$96, $1A, $D2, $71, $5A, $15, $49, $74, $4B, $9F, $D0, $5E, $04, $18, $A4, $EC,
$C2, $E0, $41, $6E, $0F, $51, $CB, $CC, $24, $91, $AF, $50, $A1, $F4, $70, $39,
$99, $7C, $3A, $85, $23, $B8, $B4, $7A, $FC, $02, $36, $5B, $25, $55, $97, $31,
$2D, $5D, $FA, $98, $E3, $8A, $92, $AE, $05, $DF, $29, $10, $67, $6C, $BA, $C9,
$D3, $00, $E6, $CF, $E1, $9E, $A8, $2C, $63, $16, $01, $3F, $58, $E2, $89, $A9,
$0D, $38, $34, $1B, $AB, $33, $FF, $B0, $BB, $48, $0C, $5F, $B9, $B1, $CD, $2E,
$C5, $F3, $DB, $47, $E5, $A5, $9C, $77, $0A, $A6, $20, $68, $FE, $7F, $C1, $AD);
// RC2 ROR helper function (16 bit rotate right)
{$IFDEF ASM386_DELPHI}
function RC2ROR(const Value: Word; const Bits: Byte): Word;
asm
MOV CL, DL
ROR AX, CL
end;
{$ELSE}
function RC2ROR(const Value: Word; const Bits: Byte): Word;
var I : Integer;
begin
Result := Value;
for I := 1 to Bits do
if Result and 1 = 0 then
Result := Result shr 1
else
Result := (Result shr 1) or $8000;
end;
{$ENDIF}
// RC2 ROL helper function (16 bit rotate left)
{$IFDEF ASM386_DELPHI}
function RC2ROL(const Value: Word; const Bits: Byte): Word;
asm
MOV CL, DL
ROL AX, CL
end;
{$ELSE}
function RC2ROL(const Value: Word; const Bits: Byte): Word;
var I : Integer;
begin
Result := Value;
for I := 1 to Bits do
if Result and $8000 = 0 then
Result := Result shl 1
else
Result := Word(Result shl 1) or 1;
end;
{$ENDIF}
// RC2 initialization
procedure RC2Init(
const Key; const KeySize: Integer;
const KeyBits: Integer;
var CipherKey: TRC2CipherKey);
var I : Integer;
T8 : Byte;
TM : Byte;
begin
// Validate parameters
if KeySize > 128 then
raise ECipher.Create(CipherError_InvalidKeySize, 'Maximum RC2 key length is 128');
if KeySize < 1 then
raise ECipher.Create(CipherError_InvalidKeySize, 'Minimum RC2 key length is 1');
if (KeyBits <= 0) or (KeyBits > 1024) then
raise ECipher.Create(CipherError_InvalidKeyBits, 'Invalid number of key bits');
// RC2 key expansion
Move(Key, CipherKey, KeySize);
with CipherKey do
begin
for I := KeySize to 127 do
Bytes[I] := RC2Table[Byte(Bytes[I - 1] + Bytes[I - KeySize])];
T8 := (KeyBits + 7) div 8;
TM := 255 mod (1 shl (8 + KeyBits - 8 * T8));
Bytes[128 - T8] := RC2Table[Bytes[128 - T8] and TM];
for I := 127 - T8 downto 0 do
Bytes[I] := RC2Table[Bytes[I + 1] xor Bytes[I + T8]];
end;
end;
// RC2 Encrypt
// RC2 Mix: R[i] = R[i] + K[j] + (R[i-1] & R[i-2]) + ((~R[i-1]) & R[i-3])
// R[i] = R[i] rol s[i]
// RC2 Mash: R[i] = R[i] + K[R[i-1] & 63]
procedure RC2EncryptBlock(const CipherKey: TRC2CipherKey; var Block: TRC2Block);
var J : PWord;
I : Integer;
begin
J := @CipherKey.Words[0];
with Block do
begin
for I := 1 to 5 do
begin
A := RC2ROL(Word(A + J^ + (D and C) + (not D and B)), 1); Inc(J);
B := RC2ROL(Word(B + J^ + (A and D) + (not A and C)), 2); Inc(J);
C := RC2ROL(Word(C + J^ + (B and A) + (not B and D)), 3); Inc(J);
D := RC2ROL(Word(D + J^ + (C and B) + (not C and A)), 5); Inc(J);
end;
A := Word(A + CipherKey.Words[D and $3F]);
B := Word(B + CipherKey.Words[A and $3F]);
C := Word(C + CipherKey.Words[B and $3F]);
D := Word(D + CipherKey.Words[C and $3F]);
for I := 1 to 6 do
begin
A := RC2ROL(Word(A + J^ + (D and C) + (not D and B)), 1); Inc(J);
B := RC2ROL(Word(B + J^ + (A and D) + (not A and C)), 2); Inc(J);
C := RC2ROL(Word(C + J^ + (B and A) + (not B and D)), 3); Inc(J);
D := RC2ROL(Word(D + J^ + (C and B) + (not C and A)), 5); Inc(J);
end;
A := Word(A + CipherKey.Words[D and $3F]);
B := Word(B + CipherKey.Words[A and $3F]);
C := Word(C + CipherKey.Words[B and $3F]);
D := Word(D + CipherKey.Words[C and $3F]);
for I := 1 to 5 do
begin
A := RC2ROL(Word(A + J^ + (D and C) + (not D and B)), 1); Inc(J);
B := RC2ROL(Word(B + J^ + (A and D) + (not A and C)), 2); Inc(J);
C := RC2ROL(Word(C + J^ + (B and A) + (not B and D)), 3); Inc(J);
D := RC2ROL(Word(D + J^ + (C and B) + (not C and A)), 5); Inc(J);
end;
end;
end;
// RC2 Decrypt
// RC2 r-Mix: R[i] = R[i] ror s[i]
// R[i] = R[i] - K[j] - (R[i-1] & R[i-2]) - ((~R[i-1]) & R[i-3])
// RC2 r-Mash: R[i] = R[i] - K[R[i-1] & 63]
procedure RC2DecryptBlock(const CipherKey: TRC2CipherKey; var Block: TRC2Block);
var J : PWord;
I : Integer;
begin
J := @CipherKey.Words[63];
with Block do
begin
for I := 1 to 5 do
begin
D := Word(RC2ROR(D, 5) - J^ - (C and B) - (not C and A)); Dec(J);
C := Word(RC2ROR(C, 3) - J^ - (B and A) - (not B and D)); Dec(J);
B := Word(RC2ROR(B, 2) - J^ - (A and D) - (not A and C)); Dec(J);
A := Word(RC2ROR(A, 1) - J^ - (D and C) - (not D and B)); Dec(J);
end;
D := Word(D - CipherKey.Words[C and $3F]);
C := Word(C - CipherKey.Words[B and $3F]);
B := Word(B - CipherKey.Words[A and $3F]);
A := Word(A - CipherKey.Words[D and $3F]);
for I := 1 to 6 do
begin
D := Word(RC2ROR(D, 5) - J^ - (C and B) - (not C and A)); Dec(J);
C := Word(RC2ROR(C, 3) - J^ - (B and A) - (not B and D)); Dec(J);
B := Word(RC2ROR(B, 2) - J^ - (A and D) - (not A and C)); Dec(J);
A := Word(RC2ROR(A, 1) - J^ - (D and C) - (not D and B)); Dec(J);
end;
D := Word(D - CipherKey.Words[C and $3F]);
C := Word(C - CipherKey.Words[B and $3F]);
B := Word(B - CipherKey.Words[A and $3F]);
A := Word(A - CipherKey.Words[D and $3F]);
for I := 1 to 5 do
begin
D := Word(RC2ROR(D, 5) - J^ - (C and B) - (not C and A)); Dec(J);
C := Word(RC2ROR(C, 3) - J^ - (B and A) - (not B and D)); Dec(J);
B := Word(RC2ROR(B, 2) - J^ - (A and D) - (not A and C)); Dec(J);
A := Word(RC2ROR(A, 1) - J^ - (D and C) - (not D and B)); Dec(J);
end;
end;
end;
end.

View File

@@ -0,0 +1,148 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherRC4.pas }
{ File version: 5.06 }
{ Description: RC4 cipher routines }
{ }
{ Copyright: Copyright (c) 2007-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ References: }
{ }
{ * www.mozilla.org/projects/security/pki/nss/ }
{ draft-kaukonen-cipher-arcfour-03.txt }
{ }
{ Revision history: }
{ }
{ 2007/01/05 4.01 Initial version. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
unit flcCipherRC4;
interface
{ }
{ RC4 }
{ Also known as Arcfour. }
{ }
type
TRC4SBox = packed array[Byte] of Byte;
TRC4Context = packed record
S : TRC4SBox;
SI : Byte;
SJ : Byte;
end;
PRC4Context = ^TRC4Context;
procedure RC4Init(const Key; const KeySize: Integer; var Context: TRC4Context);
procedure RC4Buffer(var Context: TRC4Context; var Buffer; const BufferSize: NativeInt);
implementation
uses
{ Cipher }
flcCipherUtils;
{ }
{ RC4 }
{ }
procedure RC4Init(const Key; const KeySize: Integer; var Context: TRC4Context);
type
TRC4KeyBuffer = array[Byte] of Byte;
PRC4KeyBuffer = ^TRC4KeyBuffer;
var I, J, T : Byte;
K : PRC4KeyBuffer;
begin
// Validate parameters
if KeySize > 256 then
raise ECipher.Create(CipherError_InvalidKeySize, 'Maximum RC4 key length is 256');
if KeySize < 1 then
raise ECipher.Create(CipherError_InvalidKeySize, 'Minimum RC4 key length is 1');
// Prepare RC4 context
with Context do
begin
for I := 0 to 255 do
S[I] := I;
K := @Key;
J := 0;
for I := 0 to 255 do
begin
J := Byte(Byte(J + S[I]) + K^[I mod KeySize]);
T := S[I];
S[I] := S[J];
S[J] := T;
end;
SI := 0;
SJ := 0;
end;
end;
procedure RC4Buffer(var Context: TRC4Context; var Buffer; const BufferSize: NativeInt);
var
SI : Byte;
SJ : Byte;
P : PByte;
F : NativeInt;
T : Byte;
U : Byte;
begin
SI := Context.SI;
SJ := Context.SJ;
P := @Buffer;
for F := 0 to BufferSize - 1 do
begin
SI := Byte(SI + 1);
T := Context.S[SI];
SJ := Byte(SJ + T);
U := Context.S[SJ];
Context.S[SI] := U;
Context.S[SJ] := T;
T := Byte(T + U);
T := Context.S[T];
P^ := P^ xor T;
Inc(P);
end;
Context.SI := SI;
Context.SJ := SJ;
end;
end.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,318 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherRandom.pas }
{ File version: 5.06 }
{ Description: Cipher random }
{ }
{ Copyright: Copyright (c) 2010-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2010/12/17 4.01 Initial version. }
{ 2013/09/25 4.02 UnicodeString version. }
{ 2015/05/05 4.03 Multiple PRNGs and PRSS and SHA512 hash in random block }
{ generator. }
{ 2016/01/09 5.04 Revised for Fundamentals 5. }
{ 2019/06/06 5.05 SecureRandomBytes function. }
{ 2020/02/13 5.06 Remove MD5 from generator. }
{ Use 8 random bits in generator for each secure }
{ random bit. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
unit flcCipherRandom;
interface
uses
{ System }
SysUtils,
{ Fundamentals }
flcStdTypes;
procedure SecureRandomBuf(var Buf; const Size: Integer);
function SecureRandomBytes(const Size: Integer): TBytes;
function SecureRandomStrA(const Size: Integer): RawByteString;
function SecureRandomHexStr(const Digits: Integer; const UpperCase: Boolean = True): String;
function SecureRandomHexStrB(const Digits: Integer; const UpperCase: Boolean = True): RawByteString;
function SecureRandomHexStrU(const Digits: Integer; const UpperCase: Boolean = True): UnicodeString;
function SecureRandomWord32: Word32;
implementation
uses
{ Fundamentals }
flcUtils,
flcRandom,
flcHash;
const
SecureRandomBlockBits = 128;
SecureRandomBlockSize = SecureRandomBlockBits div 8; // 16 bytes
type
TSecureRandomBlock = array[0..SecureRandomBlockSize - 1] of Byte;
PSecureRandomBlock = ^TSecureRandomBlock;
// produces a block of SecureRandomBlockSize bytes of secure random material
procedure SecureRandomBlockGenerator(var Block: TSecureRandomBlock);
const
RandomDataBits = SecureRandomBlockBits * 8; // 1024 bits (128 bytes)
RandomDataLen = RandomDataBits div 32; // 32 * Word32
var
I : Integer;
RData : array[0..RandomDataLen - 1] of Word32;
S32 : Word32;
H512 : T512BitDigest;
H256 : T256BitDigest;
begin
try
// initialise 1024 bits with multiple Pseudo Random Numbers Generators (PRNG)
// and Pseudo Random System State (PRSS)
FillChar(RData, SizeOf(RData), $FF);
S32 := RandomSeed32;
RData[0] := RData[0] xor S32;
for I := 0 to RandomDataLen - 1 do
RData[I] := RData[I] xor RandomUniform32;
for I := 0 to RandomDataLen - 1 do
RData[I] := RData[I] xor urnRandom32;
S32 := RandomSeed32;
RData[RandomDataLen - 1] := RData[RandomDataLen - 1] xor S32;
// hash 1024 bits using SHA512 into 512 bits
H512 := CalcSHA512(RData, SizeOf(RData));
// hash 512 bits using SHA256 into 256 bits
H256 := CalcSHA256(H512, SizeOf(T512BitDigest));
// move 128 bits to secure random block
Assert(SizeOf(H256) >= SecureRandomBlockSize);
Move(H256, Block, SecureRandomBlockSize);
finally
SecureClear(H256, SizeOf(T256BitDigest));
SecureClear(H512, SizeOf(T512BitDigest));
SecureClear(RData, SizeOf(RData));
end;
end;
procedure SecureRandomBuf(var Buf; const Size: Integer);
var
P : PSecureRandomBlock;
L : Integer;
B : TSecureRandomBlock;
begin
P := @Buf;
L := Size;
while L >= SecureRandomBlockSize do
begin
SecureRandomBlockGenerator(P^);
Inc(P);
Dec(L, SecureRandomBlockSize);
end;
if L > 0 then
begin
SecureRandomBlockGenerator(B);
Move(B, P^, L);
SecureClear(B, SecureRandomBlockSize);
end;
end;
function SecureRandomBytes(const Size: Integer): TBytes;
begin
SetLength(Result, Size);
if Size <= 0 then
exit;
SecureRandomBuf(Pointer(Result)^, Size);
end;
function SecureRandomStrA(const Size: Integer): RawByteString;
begin
SetLength(Result, Size);
if Size <= 0 then
exit;
SecureRandomBuf(Result[1], Size);
end;
function SecureRandomHexStr(const Digits: Integer; const UpperCase: Boolean = True): String;
var
B : TSecureRandomBlock;
S, T : String;
L, N : Integer;
P : PWord32;
Q : PChar;
begin
if Digits <= 0 then
begin
Result := '';
exit;
end;
SetLength(S, Digits);
Q := PChar(S);
L := Digits;
while L >= 8 do
begin
SecureRandomBlockGenerator(B);
P := @B;
N := SecureRandomBlockSize div 4;
while (L >= 8) and (N > 0) do
begin
T := Word32ToHex(P^, 8, UpperCase);
Move(PChar(T)^, Q^, 8 * SizeOf(Char));
SecureClearStr(T);
Inc(Q, 8);
Dec(N);
Inc(P);
Dec(L, 8);
end;
end;
if L > 0 then
begin
SecureRandomBlockGenerator(B);
P := @B;
T := Word32ToHex(P^, L, UpperCase);
Move(PChar(T)^, Q^, L * SizeOf(Char));
SecureClearStr(T);
end;
SecureClear(B, SecureRandomBlockSize);
Result := S;
end;
function SecureRandomHexStrB(const Digits: Integer; const UpperCase: Boolean): RawByteString;
var
B : TSecureRandomBlock;
S, T : RawByteString;
L, N : Integer;
P : PWord32;
Q : PByte;
begin
if Digits <= 0 then
begin
Result := '';
exit;
end;
SetLength(S, Digits);
Q := PByte(S);
L := Digits;
while L >= 8 do
begin
SecureRandomBlockGenerator(B);
P := @B;
N := SecureRandomBlockSize div 4;
while (L >= 8) and (N > 0) do
begin
T := Word32ToHexB(P^, 8, UpperCase);
Move(PByte(T)^, Q^, 8);
SecureClearStrB(T);
Inc(Q, 8);
Dec(N);
Inc(P);
Dec(L, 8);
end;
end;
if L > 0 then
begin
SecureRandomBlockGenerator(B);
P := @B;
T := Word32ToHexB(P^, L, UpperCase);
Move(PByte(T)^, Q^, L);
SecureClearStrB(T);
end;
SecureClear(B, SecureRandomBlockSize);
Result := S;
end;
function SecureRandomHexStrU(const Digits: Integer; const UpperCase: Boolean): UnicodeString;
var
B : TSecureRandomBlock;
S, T : UnicodeString;
L, N : Integer;
P : PWord32;
Q : PWideChar;
begin
if Digits <= 0 then
begin
Result := '';
exit;
end;
SetLength(S, Digits);
Q := PWideChar(S);
L := Digits;
while L >= 8 do
begin
SecureRandomBlockGenerator(B);
P := @B;
N := SecureRandomBlockSize div 4;
while (L >= 8) and (N > 0) do
begin
T := Word32ToHexU(P^, 8, UpperCase);
Move(PWideChar(T)^, Q^, 8 * SizeOf(WideChar));
SecureClear(T[1], 8 * SizeOf(WideChar));
Inc(Q, 8);
Dec(N);
Inc(P);
Dec(L, 8);
end;
end;
if L > 0 then
begin
SecureRandomBlockGenerator(B);
P := @B;
T := Word32ToHexU(P^, L, UpperCase);
Move(PWideChar(T)^, Q^, L * SizeOf(WideChar));
SecureClear(T[1], 8 * SizeOf(WideChar));
end;
SecureClear(B, SecureRandomBlockSize);
Result := S;
end;
function SecureRandomWord32: Word32;
var
L : Word32;
begin
SecureRandomBuf(L, SizeOf(Word32));
Result := L;
SecureClear(L, SizeOf(Word32));
end;
end.

View File

@@ -0,0 +1,495 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherTest.pas }
{ File version: 5.08 }
{ Description: Cipher Test }
{ }
{ Copyright: Copyright (c) 2007-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2007/01/05 0.01 Initial version. }
{ 2007/01/07 0.02 ECB and padding support. }
{ 2008/06/15 0.03 CBC mode. }
{ 2008/06/17 0.04 CFB and OFB modes. }
{ 2010/12/16 4.05 AES cipher. }
{ 2016/01/09 5.06 Revised for Fundamentals 5. }
{ 2019/06/09 5.07 Tests for Triple-DES-EDE-3. }
{ 2020/05/20 5.08 Create flcCipherTest unit from flcCipher unit. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
{$DEFINE Cipher_SupportEC}
unit flcCipherTest;
interface
{ }
{ Test }
{ }
{$IFDEF CIPHER_TEST}
procedure Test;
{$ENDIF}
{$IFDEF CIPHER_PROFILE}
procedure Profile;
{$ENDIF}
implementation
uses
SysUtils,
flcStdTypes,
flcUtils,
flcCipherRandom,
flcCipherRC2,
flcCipherAES,
flcCipherDES,
flcCipherDH,
flcCipherRSA,
{$IFDEF Cipher_SupportEC}
flcCipherEllipticCurve,
{$ENDIF}
flcCipher;
{ }
{ Test }
{ }
{$IFDEF CIPHER_TEST}
{$ASSERTIONS ON}
type
TCipherTestCase = record
Cipher : TCipherType;
Mode : TCipherMode;
KeyBits : Integer; // Effective key length (bits)
Key : RawByteString;
InitVector : RawByteString;
PlainText : RawByteString;
CipherText : RawByteString;
end;
const
CipherTestCaseCount = 36;
var
CipherTestCases : array[0..CipherTestCaseCount - 1] of TCipherTestCase = (
// RC2 test vectors from RFC 2268
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 63;
Key: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$eb#$b7#$73#$f9#$93#$27#$8e#$ff)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$ff#$ff#$ff#$ff#$ff#$ff#$ff#$ff);
PlainText: RawByteString(#$ff#$ff#$ff#$ff#$ff#$ff#$ff#$ff);
CipherText: RawByteString(#$27#$8b#$27#$e4#$2e#$2f#$0d#$49)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$30#$00#$00#$00#$00#$00#$00#$00);
PlainText: RawByteString(#$10#$00#$00#$00#$00#$00#$00#$01);
CipherText: RawByteString(#$30#$64#$9e#$df#$9b#$e7#$d2#$c2)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$88);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$61#$a8#$a2#$44#$ad#$ac#$cc#$f0)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$88#$bc#$a9#$0e#$90#$87#$5a);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$6c#$cf#$43#$08#$97#$4c#$26#$7f)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$88#$bc#$a9#$0e#$90#$87#$5a#$7f#$0f#$79#$c3#$84#$62#$7b#$af#$b2);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$1a#$80#$7d#$27#$2b#$be#$5d#$b1)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 128;
Key: RawByteString(#$88#$bc#$a9#$0e#$90#$87#$5a#$7f#$0f#$79#$c3#$84#$62#$7b#$af#$b2);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$22#$69#$55#$2a#$b0#$f8#$5c#$a6)),
(Cipher: ctRC2;
Mode: cmECB;
KeyBits: 129;
Key: RawByteString(#$88#$bc#$a9#$0e#$90#$87#$5a#$7f#$0f#$79#$c3#$84#$62#$7b#$af#$b2#$16#$f8#$0a#$6f#$85#$92#$05#$84#$c4#$2f#$ce#$b0#$be#$25#$5d#$af#$1e);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$5b#$78#$d3#$a4#$3d#$ff#$f1#$f1)),
// RC4 test vectors from http://en.wikipedia.org/wiki/RC4
(Cipher: ctRC4;
Mode: cmECB;
KeyBits: 24;
Key: 'Key';
PlainText: 'Plaintext';
CipherText: RawByteString(#$BB#$F3#$16#$E8#$D9#$40#$AF#$0A#$D3)),
(Cipher: ctRC4;
Mode: cmECB;
KeyBits: 32;
Key: 'Wiki';
PlainText: 'pedia';
CipherText: RawByteString(#$10#$21#$BF#$04#$20)),
(Cipher: ctRC4;
Mode: cmECB;
KeyBits: 48;
Key: 'Secret';
PlainText: 'Attack at dawn';
CipherText: RawByteString(#$45#$A0#$1F#$64#$5F#$C3#$5B#$38#$35#$52#$54#$4B#$9B#$F5)),
// RC4 test vectors from Internet Draft on ARCFOUR
(Cipher: ctRC4;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$01#$23#$45#$67#$89#$AB#$CD#$EF);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$74#$94#$C2#$E7#$10#$4B#$08#$79)),
(Cipher: ctRC4;
Mode: cmECB;
KeyBits: 40;
Key: RawByteString(#$61#$8a#$63#$d2#$fb);
PlainText: RawByteString(#$dc#$ee#$4c#$f9#$2c);
CipherText: RawByteString(#$f1#$38#$29#$c9#$de)),
(Cipher: ctRC4;
Mode: cmECB;
KeyBits: 128;
Key: RawByteString(#$29#$04#$19#$72#$fb#$42#$ba#$5f#$c7#$12#$77#$12#$f1#$38#$29#$c9);
PlainText: RawByteString(#$52#$75#$69#$73#$6c#$69#$6e#$6e#$75#$6e#$20#$6c#$61#$75#$6c#$75 +
#$20#$6b#$6f#$72#$76#$69#$73#$73#$73#$61#$6e#$69#$2c#$20#$74#$e4 +
#$68#$6b#$e4#$70#$e4#$69#$64#$65#$6e#$20#$70#$e4#$e4#$6c#$6c#$e4 +
#$20#$74#$e4#$79#$73#$69#$6b#$75#$75#$2e#$20#$4b#$65#$73#$e4#$79 +
#$f6#$6e#$20#$6f#$6e#$20#$6f#$6e#$6e#$69#$20#$6f#$6d#$61#$6e#$61 +
#$6e#$69#$2c#$20#$6b#$61#$73#$6b#$69#$73#$61#$76#$75#$75#$6e#$20 +
#$6c#$61#$61#$6b#$73#$6f#$74#$20#$76#$65#$72#$68#$6f#$75#$75#$2e +
#$20#$45#$6e#$20#$6d#$61#$20#$69#$6c#$6f#$69#$74#$73#$65#$2c#$20 +
#$73#$75#$72#$65#$20#$68#$75#$6f#$6b#$61#$61#$2c#$20#$6d#$75#$74 +
#$74#$61#$20#$6d#$65#$74#$73#$e4#$6e#$20#$74#$75#$6d#$6d#$75#$75 +
#$73#$20#$6d#$75#$6c#$6c#$65#$20#$74#$75#$6f#$6b#$61#$61#$2e#$20 +
#$50#$75#$75#$6e#$74#$6f#$20#$70#$69#$6c#$76#$65#$6e#$2c#$20#$6d +
#$69#$20#$68#$75#$6b#$6b#$75#$75#$2c#$20#$73#$69#$69#$6e#$74#$6f +
#$20#$76#$61#$72#$61#$6e#$20#$74#$75#$75#$6c#$69#$73#$65#$6e#$2c +
#$20#$6d#$69#$20#$6e#$75#$6b#$6b#$75#$75#$2e#$20#$54#$75#$6f#$6b +
#$73#$75#$74#$20#$76#$61#$6e#$61#$6d#$6f#$6e#$20#$6a#$61#$20#$76 +
#$61#$72#$6a#$6f#$74#$20#$76#$65#$65#$6e#$2c#$20#$6e#$69#$69#$73 +
#$74#$e4#$20#$73#$79#$64#$e4#$6d#$65#$6e#$69#$20#$6c#$61#$75#$6c +
#$75#$6e#$20#$74#$65#$65#$6e#$2e#$20#$2d#$20#$45#$69#$6e#$6f#$20 +
#$4c#$65#$69#$6e#$6f);
CipherText: RawByteString(#$35#$81#$86#$99#$90#$01#$e6#$b5#$da#$f0#$5e#$ce#$eb#$7e#$ee#$21 +
#$e0#$68#$9c#$1f#$00#$ee#$a8#$1f#$7d#$d2#$ca#$ae#$e1#$d2#$76#$3e +
#$68#$af#$0e#$ad#$33#$d6#$6c#$26#$8b#$c9#$46#$c4#$84#$fb#$e9#$4c +
#$5f#$5e#$0b#$86#$a5#$92#$79#$e4#$f8#$24#$e7#$a6#$40#$bd#$22#$32 +
#$10#$b0#$a6#$11#$60#$b7#$bc#$e9#$86#$ea#$65#$68#$80#$03#$59#$6b +
#$63#$0a#$6b#$90#$f8#$e0#$ca#$f6#$91#$2a#$98#$eb#$87#$21#$76#$e8 +
#$3c#$20#$2c#$aa#$64#$16#$6d#$2c#$ce#$57#$ff#$1b#$ca#$57#$b2#$13 +
#$f0#$ed#$1a#$a7#$2f#$b8#$ea#$52#$b0#$be#$01#$cd#$1e#$41#$28#$67 +
#$72#$0b#$32#$6e#$b3#$89#$d0#$11#$bd#$70#$d8#$af#$03#$5f#$b0#$d8 +
#$58#$9d#$bc#$e3#$c6#$66#$f5#$ea#$8d#$4c#$79#$54#$c5#$0c#$3f#$34 +
#$0b#$04#$67#$f8#$1b#$42#$59#$61#$c1#$18#$43#$07#$4d#$f6#$20#$f2 +
#$08#$40#$4b#$39#$4c#$f9#$d3#$7f#$f5#$4b#$5f#$1a#$d8#$f6#$ea#$7d +
#$a3#$c5#$61#$df#$a7#$28#$1f#$96#$44#$63#$d2#$cc#$35#$a4#$d1#$b0 +
#$34#$90#$de#$c5#$1b#$07#$11#$fb#$d6#$f5#$5f#$79#$23#$4d#$5b#$7c +
#$76#$66#$22#$a6#$6d#$e9#$2b#$e9#$96#$46#$1d#$5e#$4d#$c8#$78#$ef +
#$9b#$ca#$03#$05#$21#$e8#$35#$1e#$4b#$ae#$d2#$fd#$04#$f9#$46#$73 +
#$68#$c4#$ad#$6a#$c1#$86#$d0#$82#$45#$b2#$63#$a2#$66#$6d#$1f#$6c +
#$54#$20#$f1#$59#$9d#$fd#$9f#$43#$89#$21#$c2#$f5#$a4#$63#$93#$8c +
#$e0#$98#$22#$65#$ee#$f7#$01#$79#$bc#$55#$3f#$33#$9e#$b1#$a4#$c1 +
#$af#$5f#$6a#$54#$7f)),
// AES test vectors generated from online AES calculator at http://www.unsw.adfa.edu.au/~lpb/src/AEScalc/AEScalc.html
(Cipher: ctAES;
Mode: cmECB;
KeyBits: 128;
Key: RawByteString(#$0f#$15#$71#$c9#$47#$d9#$e8#$59#$0c#$b7#$ad#$d6#$af#$7f#$67#$98);
PlainText: '1234567890123456';
CipherText: RawByteString(#$2f#$7d#$76#$42#$5e#$bb#$85#$e4#$f2#$e7#$b0#$08#$68#$bf#$0f#$ce)),
(Cipher: ctAES;
Mode: cmECB;
KeyBits: 128;
Key: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00);
PlainText: RawByteString(#$14#$0f#$0f#$10#$11#$b5#$22#$3d#$79#$58#$77#$17#$ff#$d9#$ec#$3a);
CipherText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00)),
(Cipher: ctAES;
Mode: cmECB;
KeyBits: 192;
Key: RawByteString(#$96#$43#$D8#$33#$4A#$63#$DF#$4D#$48#$E3#$1E#$9E#$25#$67#$18#$F2#$92#$29#$31#$9C#$19#$F1#$5B#$A4);
PlainText: RawByteString(#$23#$00#$ea#$46#$3f#$43#$72#$64#$12#$75#$5f#$4c#$83#$e2#$cb#$78);
CipherText: RawByteString(#$48#$E3#$1E#$9E#$25#$67#$18#$F2#$92#$29#$31#$9C#$19#$F1#$5B#$A4)),
(Cipher: ctAES;
Mode: cmECB;
KeyBits: 256;
Key: RawByteString(#$85#$C6#$B2#$BB#$23#$00#$14#$8F#$94#$5A#$EB#$F1#$F0#$21#$CF#$79#$05#$8C#$CF#$FD#$BB#$CB#$38#$2D#$1F#$6F#$56#$58#$5D#$8A#$4A#$DE);
PlainText: RawByteString(#$e7#$0f#$9e#$09#$08#$87#$0a#$1d#$cf#$09#$60#$ae#$13#$d0#$7c#$68);
CipherText: RawByteString(#$05#$8C#$CF#$FD#$BB#$CB#$38#$2D#$1F#$6F#$56#$58#$5D#$8A#$4A#$DE)),
// AES test vectors generated from online AES calculator at http://www.riscure.com/tech-corner/online-crypto-tools/aes.html
(Cipher: ctAES;
Mode: cmCBC;
KeyBits: 128;
Key: RawByteString(#$84#$52#$35#$BA#$BE#$BD#$14#$84#$63#$E9#$DB#$46#$74#$77#$F9#$D2);
InitVector: RawByteString(#$01#$02#$03#$04#$05#$06#$07#$08#$09#$10#$11#$12#$13#$14#$15#$16);
PlainText: RawByteString(#$8F#$98#$3F#$D0#$99#$A3#$6D#$1E#$2F#$A5#$B3#$86#$31#$14#$42#$08);
CipherText: RawByteString(#$7E#$50#$7D#$C5#$D8#$ED#$3B#$A9#$F4#$C9#$30#$C8#$13#$D4#$A7#$BC)),
// DES test vectors from http://www.aci.net/Kalliste/des.htm
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$13#$34#$57#$79#$9B#$BC#$DF#$F1);
PlainText: RawByteString(#$01#$23#$45#$67#$89#$AB#$CD#$EF);
CipherText: RawByteString(#$85#$E8#$13#$54#$0F#$0A#$B4#$05)),
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$0E#$32#$92#$32#$EA#$6D#$0D#$73);
PlainText: RawByteString(#$87#$87#$87#$87#$87#$87#$87#$87);
CipherText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00)),
// DES test vectors from http://groups.google.com/group/sci.crypt/msg/1e08a60f44daa890?&hl=en
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$01#$01#$01#$01#$01#$01#$01#$01);
PlainText: RawByteString(#$95#$F8#$A5#$E5#$DD#$31#$D9#$00);
CipherText: RawByteString(#$80#$00#$00#$00#$00#$00#$00#$00)),
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$7C#$A1#$10#$45#$4A#$1A#$6E#$57);
PlainText: RawByteString(#$01#$A1#$D6#$D0#$39#$77#$67#$42);
CipherText: RawByteString(#$69#$0F#$5B#$0D#$9A#$26#$93#$9B)),
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$80#$01#$01#$01#$01#$01#$01#$01);
PlainText: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00);
CipherText: RawByteString(#$95#$A8#$D7#$28#$13#$DA#$A9#$4D)),
// DES test vectors from http://tero.co.uk/des/show.php
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: '12345678';
PlainText: 'This is the message to encrypt!!';
CipherText: RawByteString(#$05#$c9#$c4#$ca#$fb#$99#$37#$d9#$5b#$bf#$be#$df#$c5#$d7#$7f#$19 +
#$a6#$cd#$5a#$5d#$ab#$18#$8a#$33#$df#$d8#$97#$9f#$c4#$b7#$b2#$be)),
(Cipher: ctDES;
Mode: cmCBC;
KeyBits: 64;
Key: '12345678';
InitVector: 'abcdefgh';
PlainText: 'This is the message to encrypt!!';
CipherText: RawByteString(#$6c#$a9#$47#$0c#$84#$9d#$1c#$c1#$a5#$9f#$fc#$14#$8f#$1c#$b5#$e9 +
#$cf#$1f#$5c#$03#$28#$a7#$e8#$75#$63#$87#$ff#$4d#$0f#$e4#$60#$50)),
(Cipher: ctDES;
Mode: cmECB;
KeyBits: 64;
Key: RawByteString(#$01#$23#$45#$67#$89#$ab#$cd#$ef);
PlainText: 'Now is the time for all ';
CipherText: RawByteString(#$3f#$a4#$0e#$8a#$98#$4d#$48#$15#$6a#$27#$17#$87#$ab#$88#$83#$f9 +
#$89#$3d#$51#$ec#$4b#$56#$3b#$53)),
// DES test vectors from http://www.herongyang.com/crypto/des_php_implementation_mcrypt_2.html
(Cipher: ctDES;
Mode: cmCBC;
KeyBits: 64;
Key: RawByteString(#$01#$23#$45#$67#$89#$ab#$cd#$ef);
InitVector: RawByteString(#$12#$34#$56#$78#$90#$ab#$cd#$ef);
PlainText: RawByteString(#$4e#$6f#$77#$20#$69#$73#$20#$74#$68#$65#$20#$74#$69#$6d#$65#$20 +
#$66#$6f#$72#$20#$61#$6c#$6c#$20);
CipherText: RawByteString(#$e5#$c7#$cd#$de#$87#$2b#$f2#$7c#$43#$e9#$34#$00#$8c#$38#$9c#$0f +
#$68#$37#$88#$49#$9a#$7c#$05#$f6)),
(Cipher: ctDES;
Mode: cmCFB;
KeyBits: 64;
Key: RawByteString(#$01#$23#$45#$67#$89#$ab#$cd#$ef);
InitVector: RawByteString(#$12#$34#$56#$78#$90#$ab#$cd#$ef);
PlainText: RawByteString(#$4e#$6f#$77#$20#$69#$73#$20#$74#$68#$65#$20#$74#$69#$6d#$65#$20 +
#$66#$6f#$72#$20#$61#$6c#$6c#$20);
CipherText: RawByteString(#$f3#$1f#$da#$07#$01#$14#$62#$ee#$18#$7f#$43#$d8#$0a#$7c#$d9#$b5 +
#$b0#$d2#$90#$da#$6e#$5b#$9a#$87)),
(Cipher: ctDES;
Mode: cmOFB;
KeyBits: 64;
Key: RawByteString(#$01#$23#$45#$67#$89#$ab#$cd#$ef);
InitVector: RawByteString(#$12#$34#$56#$78#$90#$ab#$cd#$ef);
PlainText: RawByteString(#$4e#$6f#$77#$20#$69#$73#$20#$74#$68#$65#$20#$74#$69#$6d#$65#$20 +
#$66#$6f#$72#$20#$61#$6c#$6c#$20);
CipherText: RawByteString(#$f3#$4a#$28#$50#$c9#$c6#$49#$85#$d6#$84#$ad#$96#$d7#$72#$e2#$f2 +
#$43#$ea#$49#$9a#$be#$e8#$ae#$95)),
// Triple-DES test vectors generated from online DES calculator at http://www.riscure.com/tech-corner/online-crypto-tools/des.html
(Cipher: ctTripleDESEDE;
Mode: cmECB;
KeyBits: 128;
Key: '1234567890123456';
PlainText: '1234567890123456';
CipherText: RawByteString(#$BC#$57#$08#$BC#$02#$FE#$BF#$2F#$F6#$AD#$24#$D2#$1E#$FB#$70#$3A)),
(Cipher: ctTripleDESEDE;
Mode: cmECB;
KeyBits: 128;
Key: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00);
PlainText: '1234567890123456';
CipherText: RawByteString(#$62#$DD#$8E#$4A#$61#$4E#$1A#$F9#$BE#$3D#$31#$47#$71#$1F#$A2#$77)),
(Cipher: ctTripleDESEDE;
Mode: cmCBC;
KeyBits: 128;
Key: RawByteString(#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00#$00);
InitVector: '12345678';
PlainText: '1234567890123456';
CipherText: RawByteString(#$8C#$A6#$4D#$E9#$C1#$B1#$23#$A7#$97#$8D#$A5#$4E#$AE#$E5#$7B#$46)),
// Triple-DES-3 from https://www.cosic.esat.kuleuven.be/nessie/testvectors/bc/des/Triple-Des-3-Key-192-64.unverified.test-vectors
(Cipher: ctTripleDES3EDE;
Mode: cmECB;
KeyBits: 192;
Key: RawByteString(#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1);
InitVector: '';
PlainText: RawByteString(#$F1#$F1#$F1#$F1#$F1#$F1#$F1#$F1);
CipherText: RawByteString(#$5D#$1B#$8F#$AF#$78#$39#$49#$4B)),
(Cipher: ctTripleDES3EDE;
Mode: cmECB;
KeyBits: 192;
Key: RawByteString(#$00#$01#$02#$03#$04#$05#$06#$07#$08#$09#$0A#$0B#$0C#$0D#$0E#$0F#$10#$11#$12#$13#$14#$15#$16#$17);
InitVector: '';
PlainText: RawByteString(#$00#$11#$22#$33#$44#$55#$66#$77);
CipherText: RawByteString(#$97#$A2#$5B#$A8#$2B#$56#$4F#$4C)),
(Cipher: ctTripleDES3EDE;
Mode: cmECB;
KeyBits: 192;
Key: RawByteString(#$2B#$D6#$45#$9F#$82#$C5#$B3#$00#$95#$2C#$49#$10#$48#$81#$FF#$48#$2B#$D6#$45#$9F#$82#$C5#$B3#$00);
InitVector: '';
PlainText: RawByteString(#$EA#$02#$47#$14#$AD#$5C#$4D#$84);
CipherText: RawByteString(#$C6#$16#$AC#$E8#$43#$95#$82#$47))
);
procedure Test_TestCases;
var I : Integer;
B : array[0..1023] of AnsiChar;
L : Integer;
C : RawByteString;
M : RawByteString;
X : Integer;
begin
for I := 0 to CipherTestCaseCount - 1 do
with CipherTestCases[I] do
try
if Assigned(GetCipherInfo(Cipher)) then
begin
M := IntToStringB(I);
L := Length(PlainText);
Move(Pointer(PlainText)^, B[0], L);
L := Encrypt(Cipher, Mode, cpNone, KeyBits, Pointer(Key), Length(Key),
@B[0], L, @B[0], Sizeof(B), Pointer(InitVector), Length(InitVector));
C := '';
SetLength(C, L);
Move(B[0], Pointer(C)^, L);
if C <> CipherText then
begin
for X := 1 to L do
if C[X] <> CipherText[X] then Writeln(X, '!', Ord(C[X]), '<>', Ord(CipherText[X]), ' L=', L);
end;
{ Freepascal issue with RawByteString constant conversion }
{
if I = 13 then
begin
T := CipherText;
for X := 1 to L do
Write(IntToHex(Ord(T[X]), 2));
Writeln;
end;
}
Assert(C = CipherText, M);
L := Decrypt(Cipher, Mode, cpNone, KeyBits, Pointer(Key), Length(Key),
@B[0], L, Pointer(InitVector), Length(InitVector));
Move(B[0], PByteChar(C)^, L);
Assert(C = PlainText, M);
Assert(Encrypt(Cipher, Mode, cpNone, KeyBits, Key, PlainText, InitVector) = CipherText, M);
Assert(Decrypt(Cipher, Mode, cpNone, KeyBits, Key, CipherText, InitVector) = PlainText, M);
end;
except
on E : Exception do
raise Exception.Create('Test case ' + IntToStr(I) + ': ' + E.Message);
end;
end;
procedure Test_CipherRandom;
begin
Assert(Length(SecureRandomHexStrB(0)) = 0);
Assert(Length(SecureRandomHexStrB(1)) = 1);
Assert(Length(SecureRandomHexStrB(511)) = 511);
Assert(Length(SecureRandomHexStrB(512)) = 512);
Assert(Length(SecureRandomHexStrB(513)) = 513);
Assert(Length(SecureRandomHexStr(513)) = 513);
Assert(Length(SecureRandomHexStrU(513)) = 513);
Assert(Length(SecureRandomStrA(0)) = 0);
Assert(Length(SecureRandomStrA(1)) = 1);
Assert(Length(SecureRandomStrA(1023)) = 1023);
Assert(Length(SecureRandomStrA(1024)) = 1024);
Assert(Length(SecureRandomStrA(1025)) = 1025);
end;
procedure Test;
begin
Assert(RC2BlockSize = 8);
Assert(RC2BlockSize = Sizeof(TRC2Block));
Assert(DESBlockSize = 8);
Assert(DESBlockSize = Sizeof(TDESBlock));
flcCipherAES.Test;
flcCipherDH.Test;
flcCipherRSA.Test;
{$IFDEF Cipher_SupportEC}
flcCipherEllipticCurve.Test;
{$ENDIF}
flcCipher.Test;
Test_CipherRandom;
Test_TestCases;
end;
{$ENDIF}
{$IFDEF CIPHER_PROFILE}
procedure Profile;
begin
end;
{$ENDIF}
end.

View File

@@ -0,0 +1,137 @@
{******************************************************************************}
{ }
{ Library: Fundamentals 5.00 }
{ File name: flcCipherUtils.pas }
{ File version: 5.02 }
{ Description: Cipher library }
{ }
{ Copyright: Copyright (c) 2007-2020, David J Butler }
{ All rights reserved. }
{ This file is licensed under the BSD License. }
{ See http://www.opensource.org/licenses/bsd-license.php }
{ Redistribution and use in source and binary forms, with }
{ or without modification, are permitted provided that }
{ the following conditions are met: }
{ Redistributions of source code must retain the above }
{ copyright notice, this list of conditions and the }
{ following disclaimer. }
{ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND }
{ CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED }
{ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED }
{ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A }
{ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL }
{ THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, }
{ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR }
{ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, }
{ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF }
{ USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) }
{ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER }
{ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING }
{ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE }
{ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE }
{ POSSIBILITY OF SUCH DAMAGE. }
{ }
{ Github: https://github.com/fundamentalslib }
{ E-mail: fundamentals.library at gmail.com }
{ }
{ Revision history: }
{ }
{ 2007/01/05 4.01 Initial version }
{ 2016/01/09 5.02 Revised for Fundamentals 5. }
{ }
{******************************************************************************}
{$INCLUDE flcCipher.inc}
unit flcCipherUtils;
interface
uses
{ System }
SysUtils,
{ Fundamentals }
flcStdTypes;
{ }
{ Cipher errors }
{ }
const
CipherError_InvalidCipher = 1;
CipherError_InvalidKeySize = 2;
CipherError_InvalidKeyBits = 3;
CipherError_InvalidCipherMode = 4;
CipherError_InvalidBufferSize = 5;
CipherError_InvalidBuffer = 6;
CipherError_InvalidData = 7;
type
ECipher = class(Exception)
protected
FErrorCode : Integer;
public
constructor Create(const ErrorCode: Integer; const Msg: String);
property ErrorCode: Integer read FErrorCode;
end;
{ }
{ Secure clear }
{ }
procedure SecureClear(var Buffer; const BufferSize: Integer);
procedure SecureClearBytes(var B: TBytes);
procedure SecureClearStr(var S: RawByteString);
implementation
{ }
{ Cipher errors }
{ }
constructor ECipher.Create(const ErrorCode: Integer; const Msg: String);
begin
FErrorCode := ErrorCode;
inherited Create(Msg);
end;
{ }
{ Secure clear helper function }
{ Securely clears a piece of memory before it is released to help prevent }
{ sensitive information from being exposed. }
{ }
procedure SecureClear(var Buffer; const BufferSize: Integer);
begin
if BufferSize <= 0 then
exit;
FillChar(Buffer, BufferSize, $00);
end;
procedure SecureClearBytes(var B: TBytes);
begin
SecureClear(Pointer(B)^, Length(B));
B := nil;
end;
procedure SecureClearStr(var S: RawByteString);
var L : Integer;
begin
L := Length(S);
if L = 0 then
exit;
SecureClear(S[1], L);
SetLength(S, 0);
end;
end.