704 lines
22 KiB
ObjectPascal
704 lines
22 KiB
ObjectPascal
{Copyright: Hagen Reddmann mailto:HaReddmann@AOL.COM
|
|
Author: Hagen Reddmann
|
|
Remarks: freeware, but this Copyright must be included
|
|
known Problems: none
|
|
Version: 3.0
|
|
Delphi 2-4, designed and testet under D3 and D4
|
|
Description: Linear Feedback Shift Register (LFSR)
|
|
Random Number Generator with variable Period
|
|
from 2^32 -1 to 2^2032 -1, Standard is 2^128 -1
|
|
with .Seed('', -1) absolutly random
|
|
The Period have theoretical no effect on the Speed.
|
|
|
|
Speed: ca. 40 Mb/sec of a PII MMX 266 MHz 64Mb RAM
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''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 AUTHORS 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.
|
|
|
|
|
|
Speed: all times for PII MMX 266Mhz 64Mb
|
|
theoretical have the Period (Size of LFSR) no effect on the Speed,
|
|
but a greater Period will run faster. (Cache, little Branches on Pentium, etc.)
|
|
except the Period 2^128-1, this use a specially optimized method.
|
|
|
|
> 14.5 Mb/sec
|
|
> 40.5 Mb/sec with 128bit LFSR
|
|
Version 3.0
|
|
|
|
TRORandom is now a descend from TProtect, see Unit uRODECUtil.pas
|
|
|
|
}
|
|
unit uRORng;
|
|
|
|
interface
|
|
|
|
{$I uROVer.inc}
|
|
|
|
uses SysUtils, Classes, uRODECUtil;
|
|
|
|
type
|
|
ERORandom = class(Exception);
|
|
|
|
TRORandom = class(TROProtection) // Basicly RO_Rng, equal to Borland's Random()
|
|
private
|
|
FRegister: Integer;
|
|
FPassword: String;
|
|
protected
|
|
FCount: Integer; // not as private Fields, easier access for descends
|
|
FSize: Integer;
|
|
FBasicSeed: Integer;
|
|
procedure SetSize(Value: Integer); virtual;
|
|
function GetState: String; virtual;
|
|
procedure SetState(Value: String); virtual;
|
|
// override TProtect Methods
|
|
procedure CodeInit(Action: TPAction); override;
|
|
procedure CodeDone(Action: TPAction); override;
|
|
procedure CodeBuf(var Buffer; const BufferSize: Integer; Action: TPAction); override;
|
|
public
|
|
constructor Create(const APassword: String; ASize: Integer; ARandomize: Boolean; AProtection: TROProtection); virtual;
|
|
destructor Destroy; override;
|
|
// set the Seed register
|
|
// Size = 0 -> Seed to initial Value
|
|
// Size < 0 -> Seed to randomness Value, equal to Randomize
|
|
// Size > 0 -> Seed is set to Buffer
|
|
procedure Seed(const ABuffer; ASize: Integer); virtual;
|
|
// fill out ABuffer ASize Bytes randomly
|
|
procedure Buffer(var ABuffer; ASize: Integer); virtual;
|
|
// gives Random Integer in ARange
|
|
function Int(ARange: Integer): Integer; virtual;
|
|
// Stream loading/saving
|
|
procedure SaveToStream(Stream: TStream); virtual;
|
|
procedure LoadFromStream(Stream: TStream); virtual;
|
|
// File loading/saving
|
|
procedure SaveToFile(const FileName: String);
|
|
procedure LoadFromFile(const FileName: String);
|
|
// Count of Bytes that Int() or Buffer() has generated
|
|
property Count: Integer read FCount write FCount;
|
|
// the Size in Bits
|
|
property Size: Integer read FSize write SetSize;
|
|
// basicly Seed Value for use in .Seed(), Standard is DefaultSeed
|
|
property BasicSeed: Integer read FBasicSeed write FBasicSeed;
|
|
// the internal State as MIMIE Base64 String
|
|
property State: String read GetState write SetState;
|
|
end;
|
|
|
|
TRORandom_LFSR = class(TRORandom) // Linear Feedback Shift Register
|
|
private
|
|
FPtr: Integer; // Current Position in FRegister
|
|
FLast: Integer; // Highest Position in FRegister
|
|
FTable: array[0..255] of Word; // Lookup Table for FRegister
|
|
FRegister: array[0..255] of Byte; // Linear Feedback Shift Register
|
|
FFunc: procedure(Self: Pointer; var Buffer; Size: Integer);
|
|
protected
|
|
procedure SetSize(Value: Integer); override;
|
|
function GetState: String; override;
|
|
procedure SetState(Value: String); override;
|
|
public
|
|
procedure Seed(const ABuffer; ASize: Integer); override;
|
|
procedure Buffer(var ABuffer; ASize: Integer); override;
|
|
end;
|
|
|
|
{ Follow the used polynomial's for TRORandom_LFSR
|
|
size in bytes of register, XORCode, Polynomial, Period
|
|
|
|
4, $F5, x^32 + x^7 + x^5 + x^3 + x^2 + x + 1, 2^32 -1
|
|
5, $9C, x^40 + x^5 + x^4 + x^3 + 1, 2^40 -1
|
|
6, $ED, x^48 + x^7 + x^5 + x^4 + x^2 + x + 1, 2^48 -1
|
|
7, $A9, x^56 + x^7 + x^4 + x^2 + 1, 2^56 -1
|
|
8, $D8, x^64 + x^4 + x^3 + x + 1, 2^64 -1
|
|
9, $FA, x^72 + x^6 + x^4 + x^3 + x^2 + x + 1, 2^72 -1
|
|
10, $F5, x^80 + x^7 + x^5 + x^3 + x^2 + x + 1, 2^80 -1
|
|
12, $BB, x^96 + x^7 + x^6 + x^4 + x^3 + x^2 + 1, 2^96 -1
|
|
15, $E7, x^120 + x^7 + x^6 + x^5 + x^2 + x + 1, 2^120 -1
|
|
16, $E1, x^128 + x^7 + x^2 + x + 1, 2^128 -1
|
|
18, $A9, x^144 + x^7 + x^4 + x^2 + 1, 2^144 -1
|
|
19, $B2, x^152 + x^6 + x^3 + x^2 + 1, 2^152 -1
|
|
20, $B4, x^160 + x^5 + x^3 + x^2 + 1, 2^160 -1
|
|
22, $BD, x^176 + x^7 + x^5 + x^4 + x^3 + x^2 + 1, 2^176 -1
|
|
25, $B4, x^200 + x^5 + x^3 + x^2 + 1, 2^200 -1
|
|
27, $D1, x^216 + x^7 + x^3 + x + 1, 2^216 -1
|
|
38, $FC, x^304 + x^5 + x^4 + x^3 + x^2 + x + 1, 2^304 -1
|
|
40, $D8, x^320 + x^4 + x^3 + x + 1, 2^320 -1
|
|
42, $C9, x^336 + x^7 + x^4 + x + 1, 2^336 -1
|
|
44, $BD, x^352 + x^7 + x^5 + x^4 + x^3 + x^2 + 1, 2^352 -1
|
|
50, $B4, x^400 + x^5 + x^3 + x^2 + 1, 2^400 -1
|
|
51, $FA, x^408 + x^6 + x^4 + x^3 + x^2 + x + 1, 2^408 -1
|
|
55, $D8, x^440 + x^4 + x^3 + x + 1, 2^440 -1
|
|
60, $BB, x^480 + x^7 + x^6 + x^4 + x^3 + x^2 + 1, 2^480 -1
|
|
61, $D8, x^488 + x^4 + x^3 + x + 1, 2^488 -1
|
|
63, $FA, x^504 + x^6 + x^4 + x^3 + x^2 + x + 1, 2^504 -1
|
|
67, $95, x^536 + x^7 + x^5 + x^3 + 1, 2^536 -1
|
|
84, $F6, x^672 + x^6 + x^5 + x^3 + x^2 + x + 1, 2^672 -1
|
|
89, $9C, x^712 + x^5 + x^4 + x^3 + 1, 2^712 -1
|
|
91, $B8, x^728 + x^4 + x^3 + x^2 + 1, 2^728 -1
|
|
103, $FC, x^824 + x^5 + x^4 + x^3 + x^2 + x + 1, 2^824 -1
|
|
141, $D1, x^1128 + x^7 + x^3 + x + 1, 2^1128 -1
|
|
154, $F3, x^1232 + x^7 + x^6 + x^3 + x^2 + x + 1, 2^1232 -1
|
|
254, $A3, x^2032 + x^7 + x^6 + x^2 + 1, 2^2032 -1
|
|
|
|
follow various Periods
|
|
--------------------------------------------------------------------------------
|
|
2^32-1 = 4294967295
|
|
2^64-1 = 18446744073709551615
|
|
2^128-1 = 340282366920938463463374607431768211455
|
|
2^2032-1 = it's one Number
|
|
49311837877366649323600580884811328064642490645928167773636391338386009428204
|
|
17921935608125537553934278674005267623599165972833122328326583112816221076703
|
|
35702985799671951234310153163915857728680359766210694390385082889078409114931
|
|
66867209378778336289339669574030006474132653643098550122997363890264786354861
|
|
31947843882498538312526670313197249581325688984118966381501107686008635362008
|
|
71492771279798342546336760614070411100118371556871830774626226863061725361438
|
|
46476937385117828689155818331492509954024778049592066494651864619855274961300
|
|
9880449926596639031121858756000207590413184793166384097191709192063287295
|
|
--------------------------------------------------------------------------------
|
|
}
|
|
|
|
// Your actual Random Class, per default TRORandom_LFSR.Create(128, False)
|
|
function RND: TRORandom;
|
|
|
|
// internal used for the random initialization of the Seed Initial Value
|
|
// change this to produce Application dependent Randomness
|
|
const
|
|
DefaultSeed: Integer = 693258280;
|
|
|
|
implementation
|
|
|
|
uses uRODECConst;
|
|
|
|
const
|
|
FRND: TRORandom = nil;
|
|
|
|
// avaible Periods for the LFSR
|
|
LFSRPeriod: array[0..33, 0..1] of Word =
|
|
(( 32, $F5), ( 40, $9C), ( 48, $ED), ( 56, $A9),
|
|
( 64, $D8), ( 72, $FA), ( 80, $F5), ( 96, $BB),
|
|
( 120, $E7), ( 128, $E1), ( 144, $A9), ( 152, $B2),
|
|
( 160, $B4), ( 176, $BD), ( 200, $B4), ( 216, $D1),
|
|
( 304, $FC), ( 320, $D8), ( 336, $C9), ( 352, $BD),
|
|
( 400, $B4), ( 408, $FA), ( 440, $D8), ( 480, $BB),
|
|
( 488, $D8), ( 504, $FA), ( 536, $95), ( 672, $F6),
|
|
( 712, $9C), ( 728, $B8), ( 824, $FC), ( 1128, $D1),
|
|
( 1232, $F3), ( 2032, $A3));
|
|
|
|
function RND: TRORandom;
|
|
begin
|
|
if FRND = nil then
|
|
begin
|
|
FRND := TRORandom_LFSR.Create('', 0, False, nil);
|
|
FRND.AddRef;
|
|
end;
|
|
Result := FRND;
|
|
end;
|
|
|
|
procedure TRORandom.SetSize(Value: Integer);
|
|
begin
|
|
FSize := 32; // allways 32
|
|
end;
|
|
|
|
function TRORandom.GetState: String;
|
|
var
|
|
CRC: Word;
|
|
M: TMemoryStream;
|
|
begin
|
|
M := TMemoryStream.Create;
|
|
try
|
|
// write a Randomized Word to begin,
|
|
// any Encryption produce allways other outputs
|
|
RndXORBuffer(RndTimeSeed, CRC, SizeOf(CRC));
|
|
M.Write(CRC, SizeOf(CRC));
|
|
M.Write(FSize, SizeOf(FSize));
|
|
M.Write(FBasicSeed, SizeOf(FBasicSeed));
|
|
M.Write(FCount, SizeOf(FCount));
|
|
M.Write(FRegister, SizeOf(FRegister));
|
|
CRC := not CRC16($FFFF, M.Memory, M.Size);
|
|
M.Write(CRC, SizeOf(CRC));
|
|
CRC := $0100; // Version 1 without Protection
|
|
if Protection <> nil then
|
|
begin
|
|
CRC := CRC or 1; // with Protection
|
|
M.Position := 0;
|
|
Protection.CodeStream(M, M, M.Size, paEncode);
|
|
M.Position := M.Size;
|
|
end;
|
|
M.Write(CRC, SizeOf(CRC));
|
|
Result := StrToFormat(M.Memory, M.Size, fmtMIME64);
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRORandom.SetState(Value: String);
|
|
var
|
|
CRC: Word;
|
|
I: Integer;
|
|
M: TMemoryStream;
|
|
begin
|
|
M := TMemoryStream.Create;
|
|
try
|
|
Value := FormatToStr(PChar(Value), Length(Value), fmtMIME64);
|
|
M.Write(PChar(Value)^, Length(Value));
|
|
M.Position := M.Size - SizeOf(CRC);
|
|
M.Read(CRC, SizeOf(CRC));
|
|
if CRC and $FF00 <> $0100 then // it's Version $0100 ?
|
|
raise ERORandom.Create(sInvalidRandomStream);
|
|
if CRC and 1 <> 0 then
|
|
if Protection <> nil then
|
|
begin
|
|
M.Position := 0;
|
|
Protection.CodeStream(M, M, M.Size - SizeOf(CRC), paDecode);
|
|
end else raise ERORandom.Create(sRandomDataProtected);
|
|
M.Position := M.Size - SizeOf(CRC) * 2;
|
|
M.Read(CRC, SizeOf(CRC));
|
|
if CRC <> not CRC16($FFFF, M.Memory, M.Size - SizeOf(CRC) * 2) then
|
|
raise ERORandom.Create(sInvalidRandomStream);
|
|
M.Position := SizeOf(CRC); // skip Dummy Random Word
|
|
M.Read(I, SizeOf(FSize));
|
|
SetSize(I);
|
|
M.Read(FCount, SizeOf(FCount));
|
|
M.Read(FBasicSeed, SizeOf(FBasicSeed));
|
|
M.Read(FRegister, SizeOf(FRegister));
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
constructor TRORandom.Create(const APassword: String; ASize: Integer; ARandomize: Boolean; AProtection: TROProtection);
|
|
begin
|
|
inherited Create(AProtection);
|
|
FBasicSeed := DefaultSeed;
|
|
FSize := -1;
|
|
FPassword := APassword;
|
|
SetSize(ASize);
|
|
if ASize > 0 then
|
|
if not ARandomize then Seed(PChar(FPassword)^, Length(FPassword))
|
|
else Seed('', -1);
|
|
end;
|
|
|
|
destructor TRORandom.Destroy;
|
|
begin
|
|
Seed('', 0);
|
|
if Self = FRND then FRND := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TRORandom.Seed(const ABuffer; ASize: Integer);
|
|
var
|
|
I: Integer;
|
|
R: PByteArray;
|
|
begin
|
|
if (ASize > 0) and (@ABuffer <> nil) then
|
|
begin
|
|
FRegister := FBasicSeed;
|
|
FillChar(FRegister, SizeOf(FRegister), 0);
|
|
R := @FRegister;
|
|
for I := 0 to ASize -1 do
|
|
R[I and 3] := R[I and 3] + TByteArray(ABuffer)[I];
|
|
end else
|
|
if ASize < 0 then FRegister := RndTimeSeed + (FCount +1)
|
|
else FRegister := FBasicSeed;
|
|
if Protection <> nil then
|
|
Protection.CodeBuffer(FRegister, SizeOf(FRegister), paScramble);
|
|
end;
|
|
|
|
function TRORandom.Int(ARange: Integer): Integer;
|
|
begin
|
|
Buffer(Result, SizeOf(Result));
|
|
if (ARange = 0) or (Result = 0) then Exit;
|
|
if (ARange >= 0) and (Result < 0) then Result := -Result else
|
|
if ARange < 0 then ARange := -ARange;
|
|
Result := Result mod (ARange +1);
|
|
Inc(FCount, SizeOf(Result));
|
|
end;
|
|
|
|
procedure TRORandom.Buffer(var ABuffer; ASize: Integer);
|
|
begin
|
|
if ASize <= 0 then Exit;
|
|
FillChar(ABuffer, ASize, 0);
|
|
FRegister := RndXORBuffer(FRegister, ABuffer, ASize);
|
|
Inc(FCount, ASize);
|
|
if Protection <> nil then
|
|
Protection.CodeBuffer(ABuffer, ASize, paScramble);
|
|
end;
|
|
|
|
procedure TRORandom.SaveToStream(Stream: TStream);
|
|
var
|
|
I: Integer;
|
|
S,C: String;
|
|
begin
|
|
C := ClassName;
|
|
if C[1] = 'T' then Delete(C, 1, 1);
|
|
I := Pos('_', C);
|
|
if I > 0 then Delete(C, 1, I);
|
|
S := InsertCR(State, 64);
|
|
C := C + IntToHex(Length(S), 4) + #13#10 + S;
|
|
Stream.Write(PChar(C)^, Length(C));
|
|
end;
|
|
|
|
procedure TRORandom.LoadFromStream(Stream: TStream);
|
|
var
|
|
C,S: String;
|
|
I: Integer;
|
|
begin
|
|
// write the Name from ClassName (i.E. TRORandom_LFSR -> "LFSR"),
|
|
// the Size as a 4 Char HEX String and State.
|
|
// i.E. LFSR0FCB <CR> State
|
|
C := ClassName;
|
|
if C[1] = 'T' then Delete(C, 1, 1);
|
|
I := Pos('_', C);
|
|
if I > 0 then Delete(C, 1, I);
|
|
SetLength(S, Length(C));
|
|
Stream.Read(PChar(S)^, Length(C));
|
|
if S <> C then Abort;
|
|
SetLength(S, 6);
|
|
Stream.Read(PChar(S)^, 6);
|
|
SetLength(S, 4);
|
|
I := StrToInt('$' + S);
|
|
SetLength(S, I);
|
|
Stream.Read(PChar(S)^, I);
|
|
State := DeleteCR(S);
|
|
end;
|
|
|
|
procedure TRORandom.SaveToFile(const FileName: String);
|
|
var
|
|
S: TStream;
|
|
begin
|
|
S := TFileStream.Create(FileName, fmCreate);
|
|
try
|
|
SaveToStream(S);
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRORandom.LoadFromFile(const FileName: String);
|
|
var
|
|
S: TStream;
|
|
begin
|
|
S := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
|
|
try
|
|
LoadFromStream(S);
|
|
finally
|
|
S.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRORandom.CodeInit(Action: TPAction);
|
|
begin
|
|
if Action = paWipe then Seed('', -1)
|
|
else Seed(PChar(FPassword)^, Length(FPassword));
|
|
inherited CodeInit(Action);
|
|
end;
|
|
|
|
procedure TRORandom.CodeDone(Action: TPAction);
|
|
begin
|
|
inherited CodeDone(Action);
|
|
if Action = paWipe then Seed('', -1)
|
|
else Seed(PChar(FPassword)^, Length(FPassword));
|
|
end;
|
|
|
|
procedure TRORandom.CodeBuf(var Buffer; const BufferSize: Integer; Action: TPAction);
|
|
const
|
|
maxBufSize = 1024 * 4;
|
|
var
|
|
Buf: Pointer;
|
|
BPtr: PByte;
|
|
BSize,CSize: Integer;
|
|
begin
|
|
if Action <> paDecode then inherited CodeBuf(Buffer, BufferSize, Action);
|
|
if Action in Actions then
|
|
begin
|
|
BPtr := @Buffer;
|
|
if BPtr = nil then Exit;
|
|
BSize := maxBufSize;
|
|
if BSize > BufferSize then BSize := BufferSize;
|
|
Buf := AllocMem(BSize);
|
|
CSize := BufferSize;
|
|
try
|
|
if Action = paCalc then
|
|
begin
|
|
while CSize > 0 do
|
|
begin
|
|
BSize := CSize;
|
|
if BSize > maxBufSize then BSize := maxBufSize;
|
|
Self.Buffer(Buf^, BSize);
|
|
XORBuffers(Buf, BPtr, BSize, Buf);
|
|
Inc(BPtr, BSize);
|
|
Dec(CSize, BSize);
|
|
end
|
|
end else
|
|
begin
|
|
while CSize > 0 do
|
|
begin
|
|
BSize := CSize;
|
|
if BSize > maxBufSize then BSize := maxBufSize;
|
|
Self.Buffer(Buf^, BSize);
|
|
XORBuffers(Buf, BPtr, BSize, BPtr);
|
|
Inc(BPtr, BSize);
|
|
Dec(CSize, BSize);
|
|
end;
|
|
end;
|
|
finally
|
|
ReallocMem(Buf, 0);
|
|
end;
|
|
end;
|
|
if Action = paDecode then
|
|
inherited CodeBuf(Buffer, BufferSize, Action);
|
|
end;
|
|
|
|
// internal for TRORandom_LFSR
|
|
procedure LFSRBuf(Self: Pointer; var Buffer; Size: Integer); assembler;
|
|
asm
|
|
AND EDX,EDX // Buffer = nil ?
|
|
JZ @@9
|
|
AND ECX,ECX // BufferSize <= 0 ?
|
|
JLE @@9
|
|
|
|
PUSH EDI
|
|
PUSH ESI
|
|
PUSH EBX
|
|
PUSH EBP
|
|
PUSH EAX
|
|
|
|
MOV EDI,[EAX].TRORandom_LFSR.FPtr
|
|
MOV EBP,[EAX].TRORandom_LFSR.FLast
|
|
LEA ESI,[EAX].TRORandom_LFSR.FRegister
|
|
LEA EBX,[EAX].TRORandom_LFSR.FTable
|
|
DEC EDX
|
|
|
|
@@1: MOVZX EAX,Byte Ptr [ESI + EDI]
|
|
MOV [EDX + ECX],AL
|
|
MOV AX,[EBX + EAX * 2]
|
|
MOV [ESI + EDI],AL
|
|
DEC EDI
|
|
JS @@2
|
|
XOR [ESI + EDI],AH
|
|
ADD EDI,2
|
|
CMP EDI,EBP
|
|
JLE @@3
|
|
XOR EDI,EDI
|
|
JMP @@3
|
|
@@2: MOV EDI,EBP
|
|
XOR [ESI + EDI],AH
|
|
MOV EDI,1
|
|
@@3: DEC ECX
|
|
JNZ @@1
|
|
|
|
POP EAX
|
|
MOV [EAX].TRORandom_LFSR.FPtr,EDI
|
|
|
|
POP EBP
|
|
POP EBX
|
|
POP ESI
|
|
POP EDI
|
|
|
|
@@9:
|
|
end;
|
|
|
|
procedure LFSRBuf128(Self: Pointer; var Buffer; Size: Integer); assembler;
|
|
asm
|
|
AND EDX,EDX // Buffer = nil ?
|
|
JZ @@9
|
|
AND ECX,ECX // BufferSize <= 0 ?
|
|
JLE @@9
|
|
|
|
PUSH EDI
|
|
PUSH ESI
|
|
PUSH EBX
|
|
PUSH EBP
|
|
PUSH EAX
|
|
|
|
MOV EDI,[EAX].TRORandom_LFSR.FPtr
|
|
LEA EBP,[EAX].TRORandom_LFSR.FTable
|
|
LEA ESI,[EAX].TRORandom_LFSR.FRegister
|
|
DEC EDX
|
|
XOR EAX,EAX
|
|
|
|
@@1: MOV AL,[ESI + EDI]
|
|
MOV BX,[EBP + EAX * 2]
|
|
MOV [EDX + ECX],AL
|
|
MOV [ESI + EDI],BL
|
|
DEC EDI
|
|
AND EDI,0Fh
|
|
XOR [ESI + EDI],BH
|
|
ADD EDI,2
|
|
AND EDI,0Fh
|
|
DEC ECX
|
|
JNZ @@1
|
|
|
|
POP EAX
|
|
MOV [EAX].TRORandom_LFSR.FPtr,EDI
|
|
|
|
POP EBP
|
|
POP EBX
|
|
POP ESI
|
|
POP EDI
|
|
|
|
@@9:
|
|
end;
|
|
|
|
procedure TRORandom_LFSR.SetSize(Value: Integer);
|
|
|
|
procedure CalcLFSRTable(XORCode: Byte);
|
|
var
|
|
I,J,Z: Integer;
|
|
begin
|
|
asm // Reverse the bitorder
|
|
XOR AX,AX
|
|
MOV AL,XORCode
|
|
MOV CL,8
|
|
@@1: RCR AL,1
|
|
RCL AH,1
|
|
DEC CL
|
|
JNZ @@1
|
|
MOV XORCode,AH
|
|
end;
|
|
FillChar(FTable, SizeOf(FTable), 0);
|
|
for I := 0 to 255 do
|
|
begin
|
|
Z := I;
|
|
for J := 0 to 7 do
|
|
begin
|
|
FTable[I] := FTable[I] shl 1;
|
|
if Z and $80 <> 0 then FTable[I] := FTable[I] xor XORCode;
|
|
Z := Z shl 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure DoSet(Index: Integer);
|
|
begin
|
|
FSize := LFSRPeriod[Index, 0];
|
|
FLast := LFSRPeriod[Index, 0] div 8 -1;
|
|
if FSize = 128 then FFunc := LFSRBuf128 else FFunc := LFSRBuf;
|
|
CalcLFSRTable(LFSRPeriod[Index, 1]);
|
|
Seed('', 0);
|
|
end;
|
|
|
|
var
|
|
I: Integer;
|
|
begin
|
|
if Value <= 0 then Value := 128;
|
|
if Value <> FSize then
|
|
begin
|
|
for I := 33 downto 0 do
|
|
if Value >= LFSRPeriod[I, 0] then
|
|
begin
|
|
DoSet(I);
|
|
Exit;
|
|
end;
|
|
DoSet(9); // The Standard fast 2^128-1 Period
|
|
end;
|
|
end;
|
|
|
|
function TRORandom_LFSR.GetState: String;
|
|
var
|
|
CRC: Word;
|
|
M: TMemoryStream;
|
|
begin
|
|
M := TMemoryStream.Create;
|
|
try
|
|
// write randomized Dummy Word
|
|
RndXORBuffer(RndTimeSeed, CRC, SizeOf(CRC));
|
|
M.Write(CRC, SizeOf(CRC));
|
|
M.Write(FSize, SizeOf(FSize));
|
|
M.Write(FRegister, SizeOf(FRegister));
|
|
M.Write(FBasicSeed, SizeOf(FBasicSeed));
|
|
M.Write(FCount, SizeOf(FCount));
|
|
M.Write(FPtr, SizeOf(FPtr));
|
|
M.Write(FLast, SizeOf(FLast));
|
|
CRC := not CRC16($FFFF, M.Memory, M.Size);
|
|
M.Write(CRC, SizeOf(CRC));
|
|
CRC := $0100; // Version 1 without Protection
|
|
if Protection <> nil then
|
|
begin
|
|
CRC := CRC or 1; // with Protection
|
|
M.Position := 0;
|
|
Protection.CodeStream(M, M, M.Size, paEncode);
|
|
M.Position := M.Size;
|
|
end;
|
|
M.Write(CRC, SizeOf(CRC));
|
|
Result := StrToFormat(M.Memory, M.Size, fmtMIME64);
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRORandom_LFSR.SetState(Value: String);
|
|
var
|
|
P: Integer;
|
|
CRC: Word;
|
|
M: TMemoryStream;
|
|
begin
|
|
M := TMemoryStream.Create;
|
|
try
|
|
Value := FormatToStr(PChar(Value), Length(Value), fmtMIME64);
|
|
M.Write(PChar(Value)^, Length(Value));
|
|
M.Position := M.Size - SizeOf(CRC);
|
|
M.Read(CRC, SizeOf(CRC));
|
|
if CRC and $FF00 <> $0100 then // it's Version $0100 ?
|
|
raise ERORandom.Create(sInvalidRandomStream);
|
|
if CRC and 1 <> 0 then
|
|
if Protection <> nil then
|
|
begin
|
|
M.Position := 0;
|
|
Protection.CodeStream(M, M, M.Size - SizeOf(CRC), paDecode);
|
|
end else raise ERORandom.Create(sRandomDataProtected);
|
|
M.Position := M.Size - SizeOf(CRC) * 2;
|
|
M.Read(CRC, SizeOf(CRC));
|
|
if CRC <> not CRC16($FFFF, M.Memory, M.Size - SizeOf(CRC) * 2) then
|
|
raise ERORandom.Create(sInvalidRandomStream);
|
|
M.Position := SizeOf(CRC); // skip Dummy word
|
|
M.Read(P, SizeOf(FSize));
|
|
SetSize(P);
|
|
M.Read(FRegister, SizeOf(FRegister));
|
|
M.Read(FBasicSeed, SizeOf(FBasicSeed));
|
|
M.Read(FCount, SizeOf(FCount));
|
|
M.Read(FPtr, SizeOf(FPtr));
|
|
M.Read(FLast, SizeOf(FLast));
|
|
finally
|
|
M.Free;
|
|
end;
|
|
end;
|
|
|
|
procedure TRORandom_LFSR.Seed(const ABuffer; ASize: Integer);
|
|
var
|
|
I,S: Integer;
|
|
begin
|
|
FPtr := 0;
|
|
if (ASize > 0) and (@ABuffer <> nil) then
|
|
begin
|
|
FillChar(FRegister, SizeOf(FRegister), 0);
|
|
S := FSize div 8;
|
|
for I := 0 to ASize -1 do
|
|
FRegister[I mod S] := FRegister[I mod S] + TByteArray(ABuffer)[I];
|
|
end else
|
|
if ASize < 0 then RndXORBuffer(RndTimeSeed + (FCount +1), FRegister, SizeOf(FRegister))
|
|
else FillChar(FRegister, SizeOf(FRegister), 0);
|
|
RndXORBuffer(FBasicSeed, FRegister, SizeOf(FRegister));
|
|
if Protection <> nil then
|
|
Protection.CodeBuffer(FRegister, SizeOf(FRegister), paScramble);
|
|
end;
|
|
|
|
procedure TRORandom_LFSR.Buffer(var ABuffer; ASize: Integer);
|
|
begin
|
|
if ASize <= 0 then Exit;
|
|
FFunc(Self, ABuffer, ASize);
|
|
if Protection <> nil then
|
|
Protection.CodeBuffer(ABuffer, ASize, paScramble);
|
|
Inc(FCount, ASize);
|
|
end;
|
|
|
|
initialization
|
|
finalization
|
|
FRND.Release;
|
|
end.
|