diff --git a/.gitignore b/.gitignore index 8a4c9f2..0c4dc4e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ *.ppu *~ tests/RandomTest +src/backup \ No newline at end of file diff --git a/src/Olive.Random.BSD.pas b/src/Olive.Random.BSD.pas new file mode 100644 index 0000000..31f8ec2 --- /dev/null +++ b/src/Olive.Random.BSD.pas @@ -0,0 +1,107 @@ +{********************************************************} +{ } +{ Olive BBS } +{ } +{ Copyleft (ↄ) 2020 Olive BBS } +{ } +{ This file is part of Olive BBS } +{ } +{ Olive BBS is free software: you can redistribute it } +{ and/or modify it under the terms of the GNU General } +{ Public License as published by the Free Software } +{ Foundation, either version 3 of the License, or } +{ (at your option) any later version. } +{ } +{ Olive BBS is distributed in the hope that it will } +{ be useful, but WITHOUT ANY WARRANTY; without even } +{ the implied warranty of MERCHANTABILITY or FITNESS } +{ FOR A PARTICULAR PURPOSE. See the GNU General } +{ Public License for more details. } +{ } +{ You should have received a copy of the GNU General } +{ Public License along with Olive BBS. If not, see } +{ . } +{ } +{********************************************************} +{ ___ ___ ___ } +{ ( ).-. ( ) ( ) } +{ .--. | |( __)___ ___ .--. | |.-. | |.-. .--. } +{ / \| |(''"( )( / \| / \| / \ / _ \ } +{ | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ; } +{ | | | | | | | | | | | | | | | | | | | || ' | | } +{ | | | | | | | | | | | |/ | | | | | | |_\_`.(___) } +{ | | | | | | | | | | | ' _.| | | | | | ( ). '. } +{ | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ | } +{ ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' ' } +{ `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.' } +{ } +{********************************************************} + +{$mode objfpc}{$H+} +Unit Olive.Random.BSD; + +interface + +uses + CTypes, + Objects, + Classes, + SysUtils, + Olive.Random.RandomInterface, + Olive.Random.URandom; + +type + PCChar = ^CChar; + PBSDRandom = ^BSDRandom; + BSDRandom = class (RandomTrait, RandomInterface) + private + function GetSystemBytes(var RandomByteBuffer : TBytes; NBytes : SizeUint) : CInt; + public + function GetBytes(NBytes : SizeUInt) : TBytes; + function GetString(NBytes : SizeUInt) : AnsiString; + end; + +procedure arc4random_buf(var Buffer; NBytes : csize_t); + cdecl;external 'c' name 'arc4random_buf'; + +implementation + +function BSDRandom.GetSystemBytes(var RandomByteBuffer : TBytes; NBytes : SizeUint) : CInt; +var + CharBuffer : array of pcuint8; +begin + SetLength(CharBuffer, NBytes); + arc4random_buf(CharBuffer[0], NBytes); + if Length(CharBuffer) <> NBytes then + begin + RandomByteBuffer[0] := 0; + Result := -1; + end else + begin + Move(CharBuffer[Low(CharBuffer)], RandomByteBuffer[0], NBytes); + Result := High(RandomByteBuffer); + end; +end; + +function BSDRandom.GetBytes(NBytes : SizeUInt) : TBytes; +var + RandomBuffer : AnsiString; +begin + SetLength(RandomBuffer, NBytes); + SetLength(Result, NBytes); + RandomBuffer := GetString(NBytes); + Move(RandomBuffer[1], Result[0], NBytes); +end; + +function BSDRandom.GetString(NBytes : SizeUInt) : AnsiString; +var + RandomBuffer : TBytes; + B : SizeInt; +begin + SetLength(RandomBuffer, (NBytes*2)); + SetLength(Result, NBytes); + B := GetSystemBytes(RandomBuffer, (NBytes*2)); + Move(RandomBuffer[0], Result[1], NBytes); +end; + +end. diff --git a/src/Olive.Random.Generic.pas b/src/Olive.Random.Generic.pas new file mode 100644 index 0000000..80273b6 --- /dev/null +++ b/src/Olive.Random.Generic.pas @@ -0,0 +1,81 @@ +{********************************************************} +{ } +{ Olive BBS } +{ } +{ Copyleft (ↄ) 2020 Olive BBS } +{ } +{ This file is part of Olive BBS } +{ } +{ Olive BBS is free software: you can redistribute it } +{ and/or modify it under the terms of the GNU General } +{ Public License as published by the Free Software } +{ Foundation, either version 3 of the License, or } +{ (at your option) any later version. } +{ } +{ Olive BBS is distributed in the hope that it will } +{ be useful, but WITHOUT ANY WARRANTY; without even } +{ the implied warranty of MERCHANTABILITY or FITNESS } +{ FOR A PARTICULAR PURPOSE. See the GNU General } +{ Public License for more details. } +{ } +{ You should have received a copy of the GNU General } +{ Public License along with Olive BBS. If not, see } +{ . } +{ } +{********************************************************} +{ ___ ___ ___ } +{ ( ).-. ( ) ( ) } +{ .--. | |( __)___ ___ .--. | |.-. | |.-. .--. } +{ / \| |(''"( )( / \| / \| / \ / _ \ } +{ | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ; } +{ | | | | | | | | | | | | | | | | | | | || ' | | } +{ | | | | | | | | | | | |/ | | | | | | |_\_`.(___) } +{ | | | | | | | | | | | ' _.| | | | | | ( ). '. } +{ | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ | } +{ ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' ' } +{ `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.' } +{ } +{********************************************************} + +{$mode objfpc}{$H+} +Unit Olive.Random.Generic; + +interface + +uses + Objects, + Classes, + SysUtils, + Olive.Random.RandomInterface; + +type + PRandomGeneric = ^RandomGeneric; + RandomGeneric = class (RandomTrait, RandomInterface) + public + function GetBytes(NBytes : SizeUInt) : TBytes; + function GetString(NBytes : SizeUInt) : AnsiString; + end; + +implementation + + +function RandomGeneric.GetBytes(NBytes : SizeUInt) : TBytes; +var + RandomBuffer : AnsiString; +begin + SetLength(Result, NBytes); + RandomBuffer := GetString(NBytes); + Move(RandomBuffer[1], Result[0], NBytes); +end; + +function RandomGeneric.GetString(NBytes : SizeUInt) : AnsiString; +var + ByteBuffer : TBytes; +begin + SetLength(Result, NBytes); + SetLength(ByteBuffer, (NBytes*2)); + ByteBuffer := MTRandomBytes((NBytes*2)); + Move(ByteBuffer[0], Result[1], NBytes); +end; + +end. diff --git a/src/Olive.Random.Linux.pas b/src/Olive.Random.Linux.pas new file mode 100644 index 0000000..0d47368 --- /dev/null +++ b/src/Olive.Random.Linux.pas @@ -0,0 +1,133 @@ +{********************************************************} +{ } +{ Olive BBS } +{ } +{ Copyleft (ↄ) 2020 Olive BBS } +{ } +{ This file is part of Olive BBS } +{ } +{ Olive BBS is free software: you can redistribute it } +{ and/or modify it under the terms of the GNU General } +{ Public License as published by the Free Software } +{ Foundation, either version 3 of the License, or } +{ (at your option) any later version. } +{ } +{ Olive BBS is distributed in the hope that it will } +{ be useful, but WITHOUT ANY WARRANTY; without even } +{ the implied warranty of MERCHANTABILITY or FITNESS } +{ FOR A PARTICULAR PURPOSE. See the GNU General } +{ Public License for more details. } +{ } +{ You should have received a copy of the GNU General } +{ Public License along with Olive BBS. If not, see } +{ . } +{ } +{********************************************************} +{ ___ ___ ___ } +{ ( ).-. ( ) ( ) } +{ .--. | |( __)___ ___ .--. | |.-. | |.-. .--. } +{ / \| |(''"( )( / \| / \| / \ / _ \ } +{ | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ; } +{ | | | | | | | | | | | | | | | | | | | || ' | | } +{ | | | | | | | | | | | |/ | | | | | | |_\_`.(___) } +{ | | | | | | | | | | | ' _.| | | | | | ( ). '. } +{ | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ | } +{ ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' ' } +{ `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.' } +{ } +{********************************************************} + +{$mode objfpc}{$H+} +Unit Olive.Random.Linux; + +interface + +uses + CTypes, + Objects, + Classes, + SysUtils, + Olive.Random.RandomInterface; + +const + {$IF DEFINED(CPU64)} SYS_getrandom = 318; + {$ELSEIF DEFINED(CPU32)} SYS_getrandom = 355; + {$ELSE} SYS_getrandom = 278; {$ENDIF} + GRND_DEFAULT = $0000; + +type + PCChar = ^CChar; + PLinuxRandom = ^LinuxRandom; + LinuxRandom = class (RandomTrait, RandomInterface) + private + function GetSystemBytes(var RandomByteBuffer : TBytes; NBytes : SizeUint) : CInt; + public + function GetBytes(NBytes : SizeUInt) : TBytes; + function GetString(NBytes : SizeUInt) : AnsiString; + end; + +function syscall(NRGetRandom : CInt) : CInt;cdecl;varargs;external 'c' name 'syscall'; + +implementation + +function LinuxRandom.GetSystemBytes(var RandomByteBuffer : TBytes; NBytes : SizeUint) : CInt; +var + RandomCharBuffer : PCChar; + Return : CInt; +begin + GetMem(RandomCharBuffer, NBytes); + Return := syscall(SYS_getrandom, @RandomCharBuffer^, NBytes, GRND_DEFAULT); + Move(RandomCharBuffer[0], RandomByteBuffer[0], NBytes); + FreeMem(RandomCharBuffer); + Result := Return; +end; + +function LinuxRandom.GetBytes(NBytes : SizeUInt) : TBytes; +var + RandomBuffer : AnsiString; +begin + SetLength(Result, NBytes); + SetLength(RandomBuffer, NBytes); + RandomBuffer := GetString(NBytes); + Move(RandomBuffer[1], Result[0], NBytes); +end; + +function LinuxRandom.GetString(NBytes : SizeUInt) : AnsiString; +var + Buffer : TFileStream; + RandomByteBuffer : TBytes; + ReadBytes : SizeUInt; + SysBytesRead : CInt; +begin + SetLength(RandomByteBuffer, (NBytes*2)); + SetLength(Result, NBytes); + SysBytesRead := GetSystemBytes(RandomByteBuffer, (NBytes*2)); + if (SysBytesRead <> (NBytes*2)) then + begin + if FileExists('/dev/urandom') then + begin + Writeln('URandom'); + Buffer := TFileStream.Create('/dev/urandom', fmOpenRead); + Buffer.Position := 0; + ReadBytes := 0; + while ReadBytes <= (NBytes*2) do + begin + Buffer.Read(RandomByteBuffer[ReadBytes], SizeOf(RandomByteBuffer)); + Inc(ReadBytes); + end; + Buffer.Free; + end + else if (not FileExists('/dev/udrandom')) then + begin + Writeln('Random'); + RandomByteBuffer := MTRandomBytes((NBytes*2)); + end else + begin + raise Exception.Create('All methods to aquire random bytes failed.') + at get_caller_addr(get_frame), get_caller_frame(get_frame); + end; + end; + Move(RandomByteBuffer[0], Result[1], NBytes); +end; + +end. diff --git a/src/Olive.Random.RandomInterface.pas b/src/Olive.Random.RandomInterface.pas new file mode 100644 index 0000000..af2464f --- /dev/null +++ b/src/Olive.Random.RandomInterface.pas @@ -0,0 +1,90 @@ +{********************************************************} +{ } +{ Olive BBS } +{ } +{ Copyleft (ↄ) 2020 Olive BBS } +{ } +{ This file is part of Olive BBS } +{ } +{ Olive BBS is free software: you can redistribute it } +{ and/or modify it under the terms of the GNU General } +{ Public License as published by the Free Software } +{ Foundation, either version 3 of the License, or } +{ (at your option) any later version. } +{ } +{ Olive BBS is distributed in the hope that it will } +{ be useful, but WITHOUT ANY WARRANTY; without even } +{ the implied warranty of MERCHANTABILITY or FITNESS } +{ FOR A PARTICULAR PURPOSE. See the GNU General } +{ Public License for more details. } +{ } +{ You should have received a copy of the GNU General } +{ Public License along with Olive BBS. If not, see } +{ . } +{ } +{********************************************************} +{ ___ ___ ___ } +{ ( ).-. ( ) ( ) } +{ .--. | |( __)___ ___ .--. | |.-. | |.-. .--. } +{ / \| |(''"( )( / \| / \| / \ / _ \ } +{ | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ; } +{ | | | | | | | | | | | | | | | | | | | || ' | | } +{ | | | | | | | | | | | |/ | | | | | | |_\_`.(___) } +{ | | | | | | | | | | | ' _.| | | | | | ( ). '. } +{ | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ | } +{ ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' ' } +{ `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.' } +{ } +{********************************************************} + +{$mode objfpc}{$H+} +{$interfaces corba} +{$codepage UTF8} +Unit Olive.Random.RandomInterface; + +interface + +uses + Classes, + SysUtils; + +type + RandomInterface = interface + ['{0750E585-C1D2-4C1F-A8A4-4EDC41847396}'] + function GetBytes(NBytes : SizeUInt) : TBytes; + function GetString(NBytes : SizeUInt) : AnsiString; + end; + + RandomTrait = class (TObject) + public + constructor Create; + destructor Destroy; override; + function MTRandomBytes(NBytes : SizeUInt) : TBytes; virtual; + end; + +implementation + +constructor RandomTrait.Create; +begin + inherited Create; +end; + +destructor RandomTrait.Destroy; +begin + inherited Destroy; +end; + +function RandomTrait.MTRandomBytes(NBytes : SizeUInt) : TBytes; +var + i : SizeUint; +begin + Randomize; + SetLength(Result, (NBytes*2)); + for i := 0 to (NBytes*2) do + begin + Result[i] := Random(MaxInt) mod 256; + end; + SetLength(Result, NBytes); +end; + +end. diff --git a/src/Olive.Random.URandom.pas b/src/Olive.Random.URandom.pas new file mode 100644 index 0000000..c6db58b --- /dev/null +++ b/src/Olive.Random.URandom.pas @@ -0,0 +1,131 @@ +{********************************************************} +{ } +{ Olive BBS } +{ } +{ Copyleft (ↄ) 2020 Olive BBS } +{ } +{ This file is part of Olive BBS } +{ } +{ Olive BBS is free software: you can redistribute it } +{ and/or modify it under the terms of the GNU General } +{ Public License as published by the Free Software } +{ Foundation, either version 3 of the License, or } +{ (at your option) any later version. } +{ } +{ Olive BBS is distributed in the hope that it will } +{ be useful, but WITHOUT ANY WARRANTY; without even } +{ the implied warranty of MERCHANTABILITY or FITNESS } +{ FOR A PARTICULAR PURPOSE. See the GNU General } +{ Public License for more details. } +{ } +{ You should have received a copy of the GNU General } +{ Public License along with Olive BBS. If not, see } +{ . } +{ } +{********************************************************} +{ ___ ___ ___ } +{ ( ).-. ( ) ( ) } +{ .--. | |( __)___ ___ .--. | |.-. | |.-. .--. } +{ / \| |(''"( )( / \| / \| / \ / _ \ } +{ | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ; } +{ | | | | | | | | | | | | | | | | | | | || ' | | } +{ | | | | | | | | | | | |/ | | | | | | |_\_`.(___) } +{ | | | | | | | | | | | ' _.| | | | | | ( ). '. } +{ | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ | } +{ ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' ' } +{ `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.' } +{ } +{********************************************************} + +{$mode objfpc}{$H+} +Unit Olive.Random.URandom; + +interface + +uses + CTypes, + Objects, + Classes, + SysUtils, + Olive.Random.RandomInterface; + +const + {$IF DEFINED(CPU64)} SYS_getrandom = 318; + {$ELSEIF DEFINED(CPU32)} SYS_getrandom = 355; + {$ELSE} SYS_getrandom = 278; {$ENDIF} + GRND_DEFAULT = $0000; + +type + PCChar = ^CChar; + PURandom = ^URandom; + URandom = class (RandomTrait, RandomInterface) + private + function GetSystemBytes(var RandomByteBuffer : TBytes; NBytes : SizeUint) : CInt; + public + function GetBytes(NBytes : SizeUInt) : TBytes; + function GetString(NBytes : SizeUInt) : AnsiString; + end; + +function syscall(NRGetRandom : CInt) : CInt;cdecl;varargs;external 'c' name 'syscall'; + +implementation + +function URandom.GetSystemBytes(var RandomByteBuffer : TBytes; NBytes : SizeUint) : CInt; +var + RandomCharBuffer : PCChar; + Return : CInt; +begin + GetMem(RandomCharBuffer, NBytes); + Return := syscall(SYS_getrandom, @RandomCharBuffer^, NBytes, GRND_DEFAULT); + Move(RandomCharBuffer[0], RandomByteBuffer[0], NBytes); + FreeMem(RandomCharBuffer); + Result := Return; +end; + +function URandom.GetBytes(NBytes : SizeUInt) : TBytes; +var + RandomBuffer : AnsiString; +begin + SetLength(Result, NBytes); + SetLength(RandomBuffer, NBytes); + RandomBuffer := GetString(NBytes); + Move(RandomBuffer[1], Result[0], NBytes); +end; + +function URandom.GetString(NBytes : SizeUInt) : AnsiString; +var + Buffer : TFileStream; + RandomByteBuffer : TBytes; + ReadBytes : SizeUInt; + SysBytesRead : CInt; +begin + SetLength(RandomByteBuffer, (NBytes*2)); + SetLength(Result, NBytes); + SysBytesRead := GetSystemBytes(RandomByteBuffer, (NBytes*2)); + if (SysBytesRead <> (NBytes*2)) then + begin + if FileExists('/dev/urandom') then + begin + Buffer := TFileStream.Create('/dev/urandom', fmOpenRead); + Buffer.Position := 0; + ReadBytes := 0; + while ReadBytes <= (NBytes*2) do + begin + Buffer.Read(RandomByteBuffer[ReadBytes], SizeOf(RandomByteBuffer)); + Inc(ReadBytes); + end; + Buffer.Free; + end + else if (not FileExists('/dev/udrandom')) then + begin + RandomByteBuffer := MTRandomBytes((NBytes*2)); + end else + begin + raise Exception.Create('All methods to aquire random bytes failed.') + at get_caller_addr(get_frame), get_caller_frame(get_frame); + end; + end; + Move(RandomByteBuffer[0], Result[1], NBytes); +end; + +end. diff --git a/src/Olive.Random.Windows.pas b/src/Olive.Random.Windows.pas new file mode 100644 index 0000000..e5e6210 --- /dev/null +++ b/src/Olive.Random.Windows.pas @@ -0,0 +1,123 @@ +{********************************************************} +{ } +{ Olive BBS } +{ } +{ Copyleft (ↄ) 2020 Olive BBS } +{ } +{ This file is part of Olive BBS } +{ } +{ Olive BBS is free software: you can redistribute it } +{ and/or modify it under the terms of the GNU General } +{ Public License as published by the Free Software } +{ Foundation, either version 3 of the License, or } +{ (at your option) any later version. } +{ } +{ Olive BBS is distributed in the hope that it will } +{ be useful, but WITHOUT ANY WARRANTY; without even } +{ the implied warranty of MERCHANTABILITY or FITNESS } +{ FOR A PARTICULAR PURPOSE. See the GNU General } +{ Public License for more details. } +{ } +{ You should have received a copy of the GNU General } +{ Public License along with Olive BBS. If not, see } +{ . } +{ } +{********************************************************} +{ ___ ___ ___ } +{ ( ).-. ( ) ( ) } +{ .--. | |( __)___ ___ .--. | |.-. | |.-. .--. } +{ / \| |(''"( )( / \| / \| / \ / _ \ } +{ | .-. | | | | | | | | .-. | .-. | .-. |. .' `. ; } +{ | | | | | | | | | | | | | | | | | | | || ' | | } +{ | | | | | | | | | | | |/ | | | | | | |_\_`.(___) } +{ | | | | | | | | | | | ' _.| | | | | | ( ). '. } +{ | ' | | | | | ' ' ; | .'.-| ' | | ' | || | `\ | } +{ ' `-' | | | | \ `' /' `-' ' `-' ;' `-' ; ; '._,' ' } +{ `.__.(___(___) '_.' `.__.' `.__. `.__. '.___.' } +{ } +{********************************************************} + +{$mode objfpc}{$H+} +Unit Olive.Random.Windows; + +interface + +uses + Objects, + Classes, + SysUtils, + Windows, + Olive.Random.RandomInterface; + +const + CRYPT_VERIFYCONTEXT = $F0000000; + CRYPT_MACHINE_KEYSET = 32; + PROV_RSA_FULL = 1; + CRYPT_NEWKEYSET = 8; + + +type + HCRYPTPROV = ULONG_PTR; + PWindowsRandom = ^WindowsRandom; + WindowsRandom = class (RandomTrait, RandomInterface) + public + function GetBytes(NBytes : SizeUInt) : TBytes; + function GetString(NBytes : SizeUInt) : AnsiString; + end; + + function CryptAcquireContextW(var phProv: HCRYPTPROV; pszContainer: LPCTSTR; + pszProvider: LPCTSTR; dwProvType: DWORD; dwFlags: DWORD): BOOL;stdcall; external 'advapi32' name 'CryptAcquireContextW'; + function CryptGenRandom(hProv: HCRYPTPROV; dwLen: DWORD; + var pbBuffer: BYTE): BOOL; stdcall; external 'advapi32' name 'CryptGenRandom'; + +implementation + + +function WindowsRandom.GetBytes(NBytes : SizeUInt) : TBytes; +var + RandomBuffer : AnsiString; +begin + SetLength(Result, NBytes); + SetLength(RandomBuffer, NBytes); + RandomBuffer := GetString(NBytes); + Move(RandomBuffer[1], Result[0], NBytes); +end; + +function WindowsRandom.GetString(NBytes : SizeUInt) : AnsiString; +var + RandomBuffer : ^BYTE; + hCryptProv : ^ULONG_PTR; + WinCrypt : Boolean; + ReturnString : AnsiString; + i, Bytes : SizeInt; + ReturnBytes : TBytes; +begin + GetMem(RandomBuffer, (NBytes * 2)); + CryptAcquireContextW(hCryptProv^, nil, nil, PROV_RSA_FULL, + CRYPT_NEWKEYSET or CRYPT_MACHINE_KEYSET or CRYPT_VERIFYCONTEXT ); + WinCrypt := CryptGenRandom(hCryptProv^, (NBytes * 2), RandomBuffer^); + SetLength(ReturnString, (NBytes*2)); + if WinCrypt then + begin + for i := 1 to (NBytes*2) do + begin + ReturnString[i] := Chr(RandomBuffer[i]); + end; + end else + begin + SetLength(ReturnBytes, (NBytes*2)); + ReturnBytes := MTRandomBytes((NBytes*2)); + end; + SetLength(Result, NBytes); + FreeMem(RandomBuffer, (NBytes * 2)); + if WinCrypt then + begin + Move(ReturnString[1], Result[1], NBytes); + end else + begin + Move(ReturnBytes[0], Result[1], NBytes); + end; + +end; + +end.