summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorErich Eckner <git@eckner.net>2015-07-10 14:59:23 +0200
committerErich Eckner <git@eckner.net>2015-07-10 14:59:23 +0200
commita86ecfdaccf8c050e4a22fdb2807d48b1d7748b6 (patch)
tree63c4e32bea88d826ec958d4d0107e600d2b3207e
downloadrsa-a86ecfdaccf8c050e4a22fdb2807d48b1d7748b6.tar.xz
initialer CommitHEADmaster
-rw-r--r--.gitignore12
-rw-r--r--rsa.lpi93
-rw-r--r--rsa.lpr430
-rw-r--r--rsa.lps220
-rw-r--r--rsaunit.pas709
5 files changed, 1464 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6c22073
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+*.bmp
+*.png
+*.bak
+*.ppu
+*.o
+*.zip
+*.tar.gz
+*.out
+lib
+rsa
+*~
+Log*
diff --git a/rsa.lpi b/rsa.lpi
new file mode 100644
index 0000000..0255e95
--- /dev/null
+++ b/rsa.lpi
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+ <ProjectOptions>
+ <Version Value="9"/>
+ <General>
+ <Flags>
+ <MainUnitHasCreateFormStatements Value="False"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <Title Value="RSA Application"/>
+ <UseAppBundle Value="False"/>
+ <ResourceType Value="res"/>
+ </General>
+ <i18n>
+ <EnableI18N LFM="False"/>
+ </i18n>
+ <VersionInfo>
+ <StringTable ProductVersion=""/>
+ </VersionInfo>
+ <BuildModes Count="1">
+ <Item1 Name="Default" Default="True"/>
+ </BuildModes>
+ <PublishOptions>
+ <Version Value="2"/>
+ </PublishOptions>
+ <RunParams>
+ <local>
+ <FormatVersion Value="1"/>
+ </local>
+ </RunParams>
+ <Units Count="4">
+ <Unit0>
+ <Filename Value="rsa.lpr"/>
+ <IsPartOfProject Value="True"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="rsaunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="rsaunit"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="mlockunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="mlockunit"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="mmanunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ </Unit3>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="11"/>
+ <Target>
+ <Filename Value="rsa"/>
+ </Target>
+ <SearchPaths>
+ <IncludeFiles Value="$(ProjOutDir)"/>
+ <Libraries Value="/usr/lib/"/>
+ <OtherUnitFiles Value="/usr/src/dcpcrypt/;/usr/src/dcpcrypt/Ciphers/;/usr/src/dcpcrypt/Hashes/;../units"/>
+ <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
+ </SearchPaths>
+ <CodeGeneration>
+ <Checks>
+ <IOChecks Value="True"/>
+ <RangeChecks Value="True"/>
+ <OverflowChecks Value="True"/>
+ <StackChecks Value="True"/>
+ </Checks>
+ </CodeGeneration>
+ <Linking>
+ <Options>
+ <Win32>
+ <GraphicApplication Value="True"/>
+ </Win32>
+ </Options>
+ </Linking>
+ </CompilerOptions>
+ <Debugging>
+ <Exceptions Count="3">
+ <Item1>
+ <Name Value="EAbort"/>
+ </Item1>
+ <Item2>
+ <Name Value="ECodetoolError"/>
+ </Item2>
+ <Item3>
+ <Name Value="EFOpenError"/>
+ </Item3>
+ </Exceptions>
+ </Debugging>
+</CONFIG>
diff --git a/rsa.lpr b/rsa.lpr
new file mode 100644
index 0000000..015c2f4
--- /dev/null
+++ b/rsa.lpr
@@ -0,0 +1,430 @@
+program rsa;
+
+{$mode objfpc}{$H+}
+
+{$DEFINE UseCThreads}
+
+uses
+ {$IFDEF UNIX}{$IFDEF UseCThreads}
+ cthreads,
+ {$ENDIF}{$ENDIF}
+ Classes, SysUtils, CustApp,
+ { you can add units after this }
+ gmp, math, rsaunit, crt;
+
+type
+
+ { TRSAApplication }
+
+ TRSAApplication = class(TCustomApplication)
+ protected
+ procedure DoRun; override;
+ public
+ constructor Create(TheOwner: TComponent); override;
+ destructor Destroy; override;
+ procedure WriteHelp; virtual;
+ end;
+
+{ TRSAApplication }
+
+procedure TRSAApplication.DoRun;
+var
+ ErrorMsg,s,version: String;
+ pass: tLockedString;
+ n1,n2,n3,modul,
+ e_exponent,d_exponent: mpz_t;
+ state: randstate_t;
+ i,j,bits,maxThreads: longint;
+ gelesen,zulesen: int64;
+ binf: file;
+ textf: textfile;
+ buff: array of byte;
+ privOut,pubOut: textfile;
+ act: tRSAAction;
+begin
+ // parse parameters
+ maxThreads:=1;
+ pass:=nil;
+ if HasOption('g','generate') then begin
+ act:=raGen;
+ ErrorMsg:=CheckOptions('g:b:rt:','generate: bits: randomize threads:');
+ if HasOption('b','bits') then
+ bits:=strtoint(GetOptionValue('b','bits')) div 2 + 1
+ else
+ bits:=64;
+
+ if HasOption('t','threads') then
+ maxThreads:=strtoint(GetOptionValue('t','threads'));
+ end
+ else if HasOption('e','encrypt') then begin
+ act:=raEnc;
+ ErrorMsg:=CheckOptions('e:i:o:','encrypt: input: output:');
+ if (ErrorMsg='') and not (HasOption('i','input') and HasOption('o','output')) then
+ ErrorMsg:='Ich benötige zum Verschlüsseln Dateien!';
+ end
+ else if HasOption('d','decrypt') then begin
+ act:=raDec;
+ ErrorMsg:=CheckOptions('d:i:o:','decrypt: input: output:');
+ if (ErrorMsg='') and not (HasOption('i','input') and HasOption('o','output')) then
+ ErrorMsg:='Ich benötige zum Entschlüsseln Dateien!';
+ end
+ else if HasOption('c','check') then begin
+ act:=raChk;
+ ErrorMsg:=CheckOptions('c:','check:');
+ end
+ else if HasOption('u','update') then begin
+ act:=raUpd;
+ ErrorMsg:=CheckOptions('u:','update:');
+ end
+ else begin
+ act:=raUnk;
+ WriteHelp;
+ Terminate;
+ Exit;
+ end;
+
+ if ErrorMsg<>'' then begin
+ ShowException(Exception.Create(ErrorMsg));
+ Terminate;
+ Exit;
+ end;
+
+ { add your program here }
+
+ case act of
+ raGen: begin
+ readNewPassword(pass,ceil(sqrt(bits/8)));
+
+ mpz_init(n1);
+ mpz_init(n2);
+ mpz_init(n3);
+ mpz_init(modul);
+ mpz_init(e_exponent);
+ mpz_init(d_exponent);
+
+ assignfile(privOut,GetOptionValue('g','generate'));
+ rewrite(privOut);
+ assignfile(pubOut,GetOptionValue('g','generate')+'.pub');
+ rewrite(pubOut);
+ if HasOption('r','randomize') then begin
+ s:=acquireRandomness(bits div 4 + 1);
+ mpz_set_str(n1,@(s[1]),16);
+ end
+ else
+ mpz_set_str(n1,'1234567890',10);
+
+ mp_randinit_default(state);
+ mp_randseed(state,n1);
+
+ mpz_urandomb(n1,state,bits);
+ mpz_urandomb(n2,state,bits);
+ mpz_ui_pow_ui(n3,2,bits);
+ mpz_add(n1,n1,n3);
+ mpz_add(n2,n2,n3);
+
+ writeln;
+ write('Suche erste Primzahl ...');
+ nextPrime(n1,maxThreads);
+ writeln;
+ write('... suche zweite Primzahl ...');
+ repeat
+ nextPrime(n2,maxThreads);
+ until mpz_cmp(n1,n2)<>0;
+
+ mpz_mul(modul,n2,n1);
+
+ mpz_sub_ui(n1,n1,1);
+ mpz_sub_ui(n2,n2,1);
+ mpz_mul(n3,n1,n2);
+
+ writeln;
+ writeln('... suche Exponenten ...');
+ repeat
+ mpz_urandomb(e_exponent,state,min(16,bits div 2));
+ mpz_setbit(e_exponent,0);
+ until mpz_invert(d_exponent,e_exponent,n3)<>0;
+ mpz_set_ui(e_exponent,1025);
+ mpz_sub_ui(d_exponent,modul,1000);
+
+ writeln('... verschlüssele ...');
+ symmetricEncryption(d_exponent,pass,edEnc,'latest');
+ writeln('... speichere ...');
+
+ pass.free;
+
+ writeln(privOut,'Modul: '+mpz_get_str(nil,16,modul));
+ writeln(privOut,'e-Exponent: '+mpz_get_str(nil,16,e_exponent));
+ writeln(privOut,'d-Exponent: '+mpz_get_str(nil,16,d_exponent));
+ writeln(pubOut,'Modul: '+mpz_get_str(nil,16,modul));
+ writeln(pubOut,'e-Exponent: '+mpz_get_str(nil,16,e_exponent));
+ writeln('... fertig');
+
+ mpz_clear(n1);
+ mpz_clear(n2);
+ mpz_clear(n3);
+ mpz_clear(modul);
+ mpz_clear(e_exponent);
+ mpz_clear(d_exponent);
+
+ closefile(privOut);
+ closefile(pubOut);
+ end;
+
+ raEnc: begin
+ mpz_init(n1);
+ mpz_init(n2);
+ mpz_init(n3);
+ mpz_init(modul);
+ mpz_init(e_exponent);
+ mpz_init(d_exponent);
+ if (importKey(modul,e_exponent,d_exponent,version,GetOptionValue('e','encrypt')) and $01) = 0 then begin
+ writeln('Keinen öffentlichen Schlüssel in Datei '''+GetOptionValue('e','encrypt')+''' gefunden!');
+ Terminate;
+ Exit;
+ end;
+
+ assignfile(binf,GetOptionValue('i','input'));
+ reset(binf,1);
+ assignfile(textf,GetOptionValue('o','output'));
+ rewrite(textf);
+
+ setlength(buff,1);
+ setlength(buff,(mpz_sizeinbase(modul,256) div sizeof(buff[0]))-1);
+ gelesen:=0;
+ zulesen:=8+filesize(binf);
+ fillchar(buff[0],length(buff)*sizeof(buff[0]),0);
+ while gelesen<zulesen do begin
+ if gelesen=0 then begin
+ for i:=0 to 7 do
+ buff[i]:=(filesize(binf) shr (8*i)) and $ff;
+ gelesen:=8;
+ i:=8 div sizeof(buff[0]);
+ end
+ else i:=0;
+
+ j:=min((length(buff)-i)*sizeof(buff[0]),zulesen-gelesen);
+ blockread(binf,buff[i],j);
+ gelesen:=gelesen + j;
+
+ mpz_set_ui(n1,0);
+ for j:=0 to length(buff)-1 do begin
+ mpz_mul_2exp(n1,n1,sizeof(buff[j])*8);
+ mpz_add_ui(n1,n1,buff[j]);
+ end;
+
+ mpz_powm(n2,n1,e_Exponent,modul);
+ writeln(textf,mpz_get_str(nil,16,n2));
+ end;
+
+ closefile(binf);
+ closefile(textf);
+
+ mpz_clear(n1);
+ mpz_clear(n2);
+ mpz_clear(n3);
+ mpz_clear(modul);
+ mpz_clear(e_exponent);
+ mpz_clear(d_exponent);
+ end;
+
+ raDec: begin
+ write('Passwort des Schlüssels eingeben: ');
+ readlnblind(pass);
+
+ mpz_init(n1);
+ mpz_init(n2);
+ mpz_init(n3);
+ mpz_init(modul);
+ mpz_init(e_exponent);
+ mpz_init(d_exponent);
+
+ if (importKey(modul,e_exponent,d_exponent,version,GetOptionValue('d','decrypt')) and $02) = 0 then begin
+ writeln('Keinen privaten Schlüssel in Datei '''+GetOptionValue('d','decrypt')+''' gefunden!');
+ Terminate;
+ Exit;
+ end;
+ symmetricEncryption(d_exponent,pass,edDec,version);
+
+ setlength(buff,1);
+ setlength(buff,(mpz_sizeinbase(modul,256) div sizeof(buff[0]))-1);
+ fillchar(buff[0],length(buff)*sizeof(buff[0]),0);
+
+ gelesen:=0;
+ zulesen:=-1;
+
+ assignfile(textf,GetOptionValue('i','input'));
+ reset(textf);
+ assignfile(binf,GetOptionValue('o','output'));
+ rewrite(binf,1);
+ while not eof(textf) do begin
+ readln(textf,s);
+ mpz_set_str(n1,pchar(s),16);
+ mpz_powm(n2,n1,d_Exponent,modul);
+
+ for i:=length(buff)-1 downto 0 do begin
+ buff[i]:=mpz_get_ui(n2) and $ff;
+ mpz_fdiv_q_2exp(n2,n2,8);
+ end;
+
+ if gelesen=0 then begin
+ zulesen:=0;
+ for i:=0 to 7 do
+ zulesen:=zulesen*256+buff[7-i];
+ i:=8 div sizeof(buff[0]);
+ end
+ else
+ i:=0;
+
+ j:=min(zulesen-gelesen,(length(buff)-i)*sizeof(buff[0]));
+ if j>0 then blockwrite(binf,buff[i],j);
+
+ gelesen:=gelesen+j;
+ end;
+
+ if gelesen <> zulesen then
+ writeln(inttostr(gelesen)+' Bytes geschrieben, aber es waren '+inttostr(zulesen)+' angekündigt!');
+
+ closefile(binf);
+ closefile(textf);
+
+ mpz_clear(n1);
+ mpz_clear(n2);
+ mpz_clear(n3);
+ mpz_clear(modul);
+ mpz_clear(e_exponent);
+ mpz_clear(d_exponent);
+ end;
+
+ raChk: begin
+ write('Passwort des Schlüssels eingeben: ');
+ readlnblind(pass);
+
+ mpz_init(n1);
+ mpz_init(n2);
+ mpz_init(modul);
+ mpz_init(e_exponent);
+ mpz_init(d_exponent);
+
+ if importKey(modul,e_exponent,d_exponent,version,GetOptionValue('c','check')) <> $03 then begin
+ writeln('Der Datei '''+GetOptionValue('c','check')+''' fehlt mindestens ein Schlüsselteil!');
+ Terminate;
+ Exit;
+ end;
+ symmetricEncryption(d_exponent,pass,edDec,version);
+
+ for i:=0 to 100 do begin
+ s:=copy(inttostr(i)+paramstr(0),1,mpz_sizeinbase(modul,256)-1);
+ mpz_set_str(n1,pchar(s),256);
+ mpz_powm(n2,n1,e_exponent,modul);
+ mpz_powm(n2,n2,d_exponent,modul);
+ if mpz_cmp(n1,n2)<>0 then
+ writeln('Entschlüsselter Text ist ungleich Original! - Passwort falsch?');
+ end;
+
+ writeln('Tests abgeschlossen.');
+
+ mpz_clear(n1);
+ mpz_clear(n2);
+ mpz_clear(modul);
+ mpz_clear(e_exponent);
+ mpz_clear(d_exponent);
+ end;
+
+ raUpd: begin
+ write('Passwort des Schlüssels eingeben: ');
+ readlnblind(pass);
+
+ mpz_init(n1);
+ mpz_init(n2);
+ mpz_init(modul);
+ mpz_init(e_exponent);
+ mpz_init(d_exponent);
+
+ if importKey(modul,e_exponent,d_exponent,version,GetOptionValue('u','update')) <> $03 then begin
+ writeln('Der Datei '''+GetOptionValue('u','update')+''' fehlt mindestens ein Schlüsselteil!');
+ Terminate;
+ Exit;
+ end;
+ symmetricEncryption(d_exponent,pass,edDec,version);
+
+ write('Neues Passwort vergeben? (j/n) ');
+ readln(s);
+ if pos('j',s)=1 then
+ readNewPassword(pass,ceil(sqrt(mpz_sizeinbase(modul,2)/8)));
+
+ version:='latest';
+ symmetricEncryption(d_exponent,pass,edEnc,version);
+ pass.free;
+
+ repeat
+ write('Ziel zum Speichern eingeben: ');
+ readln(s);
+ until (not fileexists(s)) and (not fileexists(s+'.pub'));
+
+ assignfile(privOut,s);
+ rewrite(privOut);
+ assignfile(pubOut,s+'.pub');
+ rewrite(pubOut);
+
+ writeln(privOut,'Modul: '+mpz_get_str(nil,16,modul));
+ writeln(privOut,'Version: '+version);
+ writeln(privOut,'e-Exponent: '+mpz_get_str(nil,16,e_exponent));
+ writeln(privOut,'d-Exponent: '+mpz_get_str(nil,16,d_exponent));
+ writeln(pubOut,'Modul: '+mpz_get_str(nil,16,modul));
+ writeln(pubOut,'e-Exponent: '+mpz_get_str(nil,16,e_exponent));
+
+ closefile(pubOut);
+ closefile(privOut);
+
+ mpz_clear(n1);
+ mpz_clear(n2);
+ mpz_clear(modul);
+ mpz_clear(e_exponent);
+ mpz_clear(d_exponent);
+ end;
+
+ else
+ writeln('Fehler: Funktion noch nicht implementiert!');
+ end{of case};
+
+ // stop program loop
+ Terminate;
+end;
+
+constructor TRSAApplication.Create(TheOwner: TComponent);
+begin
+ inherited Create(TheOwner);
+ StopOnException:=True;
+end;
+
+destructor TRSAApplication.Destroy;
+begin
+ inherited Destroy;
+end;
+
+procedure TRSAApplication.WriteHelp;
+begin
+ { add your help code here }
+ writeln('Usage: ',ExeName,' -h');
+ writeln(' get help');
+ writeln('Usage: ',ExeName,' -g/--generate $key [-b/--bits $Bits] [-r/--randomize] [-t/--threads $maxThreads]');
+ writeln(' generate key');
+ writeln('Usage: ',ExeName,' -e/--encrypt $key -i/--input $input -o/--output $output');
+ writeln(' encrypt with key');
+ writeln('Usage: ',ExeName,' -d/--decrypt $key -i/--input $input -o/--output $output');
+ writeln(' decrypt with key');
+ writeln('Usage: ',ExeName,' -c/--check $key');
+ writeln(' check integrity of key');
+ writeln('Usage: ',ExeName,' -u/--update $key');
+ writeln(' update key, possibly change passphrase');
+end;
+
+var
+ Application: TRSAApplication;
+begin
+ Application:=TRSAApplication.Create(nil);
+ Application.Title:='RSA Application';
+ Application.Run;
+ Application.Free;
+end.
+
diff --git a/rsa.lps b/rsa.lps
new file mode 100644
index 0000000..5b7c4fe
--- /dev/null
+++ b/rsa.lps
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+ <ProjectSession>
+ <Version Value="9"/>
+ <BuildModes Active="Default"/>
+ <Units Count="15">
+ <Unit0>
+ <Filename Value="rsa.lpr"/>
+ <IsPartOfProject Value="True"/>
+ <TopLine Value="45"/>
+ <CursorPos Y="45"/>
+ <UsageCount Value="60"/>
+ <Loaded Value="True"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="rsaunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="rsaunit"/>
+ <IsVisibleTab Value="True"/>
+ <EditorIndex Value="1"/>
+ <CursorPos X="72" Y="18"/>
+ <UsageCount Value="58"/>
+ <Loaded Value="True"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="mlockunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="mlockunit"/>
+ <EditorIndex Value="-1"/>
+ <CursorPos X="28" Y="6"/>
+ <UsageCount Value="41"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="mmanunit.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UsageCount Value="41"/>
+ </Unit3>
+ <Unit4>
+ <Filename Value="/usr/lib/fpc/src/packages/gmp/src/gmp.pas"/>
+ <TopLine Value="70"/>
+ <CursorPos X="18" Y="485"/>
+ <UsageCount Value="9"/>
+ </Unit4>
+ <Unit5>
+ <Filename Value="/usr/src/dcpcrypt/Ciphers/dcprijndael.pas"/>
+ <TopLine Value="22"/>
+ <UsageCount Value="8"/>
+ </Unit5>
+ <Unit6>
+ <Filename Value="/usr/src/dcpcrypt/dcpcrypt2.pas"/>
+ <TopLine Value="201"/>
+ <CursorPos X="39" Y="222"/>
+ <UsageCount Value="9"/>
+ </Unit6>
+ <Unit7>
+ <Filename Value="/usr/src/dcpcrypt/dcpblockciphers.pas"/>
+ <TopLine Value="61"/>
+ <CursorPos X="3" Y="81"/>
+ <UsageCount Value="8"/>
+ </Unit7>
+ <Unit8>
+ <Filename Value="/usr/src/dcpcrypt/Hashes/dcphaval.pas"/>
+ <TopLine Value="25"/>
+ <UsageCount Value="7"/>
+ </Unit8>
+ <Unit9>
+ <Filename Value="/usr/src/dcpcrypt/Ciphers/dcpmars.pas"/>
+ <TopLine Value="16"/>
+ <UsageCount Value="7"/>
+ </Unit9>
+ <Unit10>
+ <Filename Value="/usr/src/dcpcrypt/Ciphers/dcpblowfish.pas"/>
+ <TopLine Value="19"/>
+ <UsageCount Value="7"/>
+ </Unit10>
+ <Unit11>
+ <Filename Value="/usr/src/dcpcrypt/Ciphers/dcptwofish.pas"/>
+ <TopLine Value="22"/>
+ <CursorPos X="33" Y="54"/>
+ <UsageCount Value="7"/>
+ </Unit11>
+ <Unit12>
+ <Filename Value="/usr/src/dcpcrypt/Ciphers/dcpserpent.pas"/>
+ <TopLine Value="22"/>
+ <UsageCount Value="7"/>
+ </Unit12>
+ <Unit13>
+ <Filename Value="/usr/lib/fpc/src/rtl/inc/ctypes.pp"/>
+ <TopLine Value="37"/>
+ <UsageCount Value="8"/>
+ </Unit13>
+ <Unit14>
+ <Filename Value="/usr/lib/fpc/src/rtl/unix/baseunix.pp"/>
+ <TopLine Value="18"/>
+ <UsageCount Value="8"/>
+ </Unit14>
+ </Units>
+ <JumpHistory Count="30" HistoryIndex="29">
+ <Position1>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="282" Column="29" TopLine="234"/>
+ </Position1>
+ <Position2>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="50" Column="20" TopLine="29"/>
+ </Position2>
+ <Position3>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="54" Column="29" TopLine="24"/>
+ </Position3>
+ <Position4>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="30" Column="10" TopLine="21"/>
+ </Position4>
+ <Position5>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="53" Column="24" TopLine="30"/>
+ </Position5>
+ <Position6>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="49" Column="32" TopLine="33"/>
+ </Position6>
+ <Position7>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="50" Column="23" TopLine="28"/>
+ </Position7>
+ <Position8>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="63" Column="16" TopLine="43"/>
+ </Position8>
+ <Position9>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="516" Column="28" TopLine="499"/>
+ </Position9>
+ <Position10>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="64" Column="24" TopLine="37"/>
+ </Position10>
+ <Position11>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="433" Column="30" TopLine="397"/>
+ </Position11>
+ <Position12>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="65" TopLine="46"/>
+ </Position12>
+ <Position13>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="670" Column="76" TopLine="635"/>
+ </Position13>
+ <Position14>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="677" TopLine="637"/>
+ </Position14>
+ <Position15>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="77" TopLine="40"/>
+ </Position15>
+ <Position16>
+ <Filename Value="rsa.lpr"/>
+ <Caret Line="47" Column="23" TopLine="23"/>
+ </Position16>
+ <Position17>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="423" Column="97" TopLine="403"/>
+ </Position17>
+ <Position18>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="196" Column="32" TopLine="164"/>
+ </Position18>
+ <Position19>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="46" Column="18" TopLine="25"/>
+ </Position19>
+ <Position20>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="511" TopLine="470"/>
+ </Position20>
+ <Position21>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="690" Column="41" TopLine="659"/>
+ </Position21>
+ <Position22>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="45" Column="12" TopLine="25"/>
+ </Position22>
+ <Position23>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="206" Column="26" TopLine="185"/>
+ </Position23>
+ <Position24>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="665" Column="17" TopLine="645"/>
+ </Position24>
+ <Position25>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="690" Column="8" TopLine="659"/>
+ </Position25>
+ <Position26>
+ <Filename Value="rsaunit.pas"/>
+ </Position26>
+ <Position27>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="700" TopLine="659"/>
+ </Position27>
+ <Position28>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="690" Column="8" TopLine="659"/>
+ </Position28>
+ <Position29>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="56" Column="75" TopLine="46"/>
+ </Position29>
+ <Position30>
+ <Filename Value="rsaunit.pas"/>
+ <Caret Line="12" Column="41"/>
+ </Position30>
+ </JumpHistory>
+ </ProjectSession>
+</CONFIG>
diff --git a/rsaunit.pas b/rsaunit.pas
new file mode 100644
index 0000000..cf0c5e7
--- /dev/null
+++ b/rsaunit.pas
@@ -0,0 +1,709 @@
+unit rsaunit;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, gmp, math, crt, mlockunit,
+ dcprijndael, dcpmars, dcpblowfish, dcptwofish, dcpserpent, dcpcrypt2,
+ dcphaval;
+
+type
+ tRSAAction = (raUnk,raGen,raEnc,raDec,raChk,raUpd);
+ tEncryptionDirection = (edEnc,edDec);
+ tUsedCiphers = (ucRijndael,ucMars,ucBlowfish,ucTwofish,ucSerpent);
+
+ tLockedString = class
+ private
+ _inh: pchar;
+ memstart: pointer;
+ locked,memlen,
+ pagesize: longint;
+ procedure lock;
+ procedure unlock;
+ procedure wInh(i: pchar);
+ public
+ constructor create;
+ destructor destroy; override;
+ procedure assign(ls: tLockedString);
+ procedure delete(posi,leng: longint);
+ procedure append(s: string);
+ function substr(start,leng: longint): string;
+ function len: longint;
+ function isEqual(s: tLockedString): boolean;
+ function teil(num,tot: longint): string; overload;
+ function teil(cph: tUsedCiphers): string; overload;
+ property inh: pchar
+ read _inh
+ write wInh;
+ end;
+
+ tNextPrimeThread = class(tThread)
+ fertig: byte; // Bit 0: Primzahl gefunden; Bit 1: execute beendet
+ myNum: mpz_t;
+ abbruch,
+ arbeite: boolean;
+ myStep: longint;
+ cnt: int64;
+ constructor create(num: mpz_t; offset,step: longint);
+ destructor destroy; override;
+ procedure execute; override;
+ end;
+
+function acquireRandomness(bytes: int64): string; // hex-encoded
+function nextPrime(var num: mpz_t; threads: longint): boolean;
+function nextPrimeSt(var num: mpz_t; step: longint; var keepWorking, abort: boolean; var getestet: int64): boolean; // Prime found?
+function importKey(var m,e,d: mpz_t; out version: string; nam: string): byte; // bit 0: enc-Key found; bit 1: dec-Key found
+procedure symmetricEncryption(var input: mpz_t; key: tLockedString; direction: tEncryptionDirection; version: string);
+function hexdump(arr: array of byte): string; overload;
+function hexdump(s: string): string; overload;
+procedure readlnblind(out s: tLockedString);
+procedure userCallback;
+function mydatetimetostr(tm: extended): string;
+procedure readNewPassword(var pass: tLockedString; len: int64);
+function cpuUtilization: extended;
+
+const
+ cipherClasses: array[tUsedCiphers] of class of TDCP_blockcipher =
+ (tDCP_Rijndael,tDCP_Mars,tDCP_Blowfish,tDCP_Twofish,tDCP_Serpent);
+ ciphNam: array[tUsedCiphers] of string =
+ ('Rijndael','Mars','Blowfish','Twofish','Serpent');
+
+implementation
+
+var
+ _cpuLastUsed,_cpuLastIdle: int64;
+
+function acquireRandomness(bytes: int64): string;
+var
+ tf: file;
+ buff: array of byte;
+ i,j: int64;
+begin
+ write(stderr,'Zufall sammeln ...');
+ try
+ assignfile(tf,'/dev/random');
+ setlength(buff,bytes);
+ i:=0;
+ j:=0;
+ reset(tf,1);
+ while i<length(buff) do begin
+ blockread(tf,buff[i],(length(buff)-i)*sizeof(buff[0]),j);
+ i:=i+j;
+ if i<length(buff) then begin
+ write(stderr,'.');
+ sleep(100);
+ userCallback;
+ end;
+ end;
+ finally
+ closefile(tf);
+ end;
+ result:='';
+ for i:=0 to length(buff)-1 do
+ result:=result+inttohex(buff[i],2);
+ writeln(stderr,' fertig');
+end;
+
+function nextPrime(var num: mpz_t; threads: longint): boolean;
+// multi threaded
+var
+ npts: array of tNextPrimeThread;
+ i,cnt,step,
+ x,y,penalty: longint;
+ offsets: array of longint;
+ dummy: mpz_t;
+ total: int64;
+ enps,start: extended;
+begin
+ mpz_setbit(num,0);
+ result:=false;
+
+ setlength(offsets,0);
+ step:=0;
+
+ enps:=mpz_sizeinbase(num,2)*ln(2)/2;
+
+ mpz_init(dummy);
+ repeat
+ cnt:=0;
+ for i:=0 to length(offsets)-1 do begin
+ mpz_add_ui(dummy,num,offsets[i]);
+ if mpz_gcd_ui(dummy,dummy,step)=1 then inc(cnt)
+ else offsets[i]:=-1;
+ end;
+ if cnt<threads then begin // zu wenige wirklich arbeitende Threads?
+ setlength(offsets,max(threads,length(offsets)+1));
+ for i:=0 to length(offsets)-1 do
+ offsets[i]:=i*2;
+ step:=2*length(offsets);
+ end;
+ until cnt>=threads; // genug wirklich arbeitende Threads?
+ mpz_clear(dummy);
+
+ if cnt<>threads then
+ writeln(stderr,'Genau '+inttostr(threads)+' arbeitende Threads habe ich nicht hinbekommen, daher habe ich auf '+inttostr(cnt)+' Threads erhöht.');
+
+ setlength(npts,cnt);
+ cnt:=0;
+ for i:=0 to length(npts)-1 do begin
+ while (cnt<length(offsets)) and (offsets[cnt]=-1) do
+ inc(cnt);
+ if cnt>=length(offsets) then
+ raise Exception.create('Ich habe mich bei den Threads verzählt (zu viele Threads)!');
+
+ npts[i]:=tNextPrimeThread.create(num,offsets[cnt],step);
+ inc(cnt);
+ end;
+
+ while (cnt<length(offsets)) and (offsets[cnt]=-1) do
+ inc(cnt);
+
+ if cnt<>length(offsets) then
+ raise Exception.create('Ich habe mich bei den Threads verzählt (zu wenige Threads)!');
+
+ for i:=0 to length(npts)-1 do
+ npts[i].suspended:=false;
+
+ x:=whereX;
+ y:=whereY;
+ start:=now;
+ penalty:=0;
+ repeat
+ for i:=0 to length(npts)-1 do
+ result:=result or odd(npts[i].fertig);
+ if not result then begin
+ if penalty=0 then sleep(1000)
+ else sleep(100);
+ total:=0;
+ for i:=0 to length(npts)-1 do
+ total:=total+npts[i].cnt;
+
+ gotoxy(x,y);
+ x:=whereX;
+ y:=whereY;
+ write(' '+floattostrf(total/enps*100,ffFixed,10,3)+' % ETA: '+mydatetimetostr((now-start)/max(1,total)*enps)+' ');
+
+ if cpuUtilization > 0.8 then begin
+ inc(penalty);
+ if penalty>2 then begin
+ for i:=0 to length(npts)-1 do
+ npts[i].arbeite:=false;
+ writeln('Zu hohe Gesamtlast auf der CPU, ich pausiere!');
+
+ repeat
+ userCallback;
+ sleep(1000);
+ until cpuUtilization<0.4;
+
+ penalty:=0;
+ writeln('CPU-Last ist wieder gesunken, ich mache weiter!');
+ for i:=0 to length(npts)-1 do
+ npts[i].arbeite:=true;
+ end;
+ end
+ else penalty:=0;
+
+ userCallback;
+ end;
+ until result;
+
+ for i:=0 to length(npts)-1 do
+ npts[i].abbruch:=true;
+
+ repeat
+ result:=true;
+ for i:=0 to length(npts)-1 do
+ result:=result and odd(npts[i].fertig shr 1);
+ if not result then sleep(100);
+ until result;
+
+ result:=false;
+ for i:=0 to length(npts)-1 do begin
+ if (not result) and odd(npts[i].fertig) then begin
+ result:=true;
+ mpz_set(num,npts[i].myNum);
+ end;
+ npts[i].free;
+ end;
+end;
+
+function nextPrimeSt(var num: mpz_t; step: longint; var keepWorking, abort: boolean; var getestet: int64): boolean;
+// single threaded
+begin
+ step:=step+byte(odd(step));
+ mpz_setbit(num,0);
+ result:=false;
+
+ getestet:=0;
+ result:=mpz_probab_prime_p(num,25) > 0;
+ while not (abort or result) do begin
+ while not keepWorking do
+ sleep(100);
+ userCallback;
+ mpz_add_ui(num,num,step);
+ inc(getestet);
+ result:=mpz_probab_prime_p(num,25) > 0;
+ end;
+end;
+
+function importKey(var m,e,d: mpz_t; out version: string; nam: string): byte; // bit 0: enc-Key found; bit 1: dec-Key found
+var
+ f: textfile;
+ s: string;
+begin
+ assignfile(f,nam);
+ reset(f);
+ result:=0;
+ version:='';
+ while not eof(f) do begin
+ readln(f,s);
+ if pos('Modul: ',s)=1 then begin
+ delete(s,1,pos(' ',s));
+ s:=trim(s);
+ mpz_set_str(m,pchar(s),16);
+ result:=result or $04;
+ continue;
+ end;
+ if pos('d-Exponent: ',s)=1 then begin
+ delete(s,1,pos(' ',s));
+ s:=trim(s);
+ mpz_set_str(d,pchar(s),16);
+ result:=result or $02;
+ continue;
+ end;
+ if pos('e-Exponent: ',s)=1 then begin
+ delete(s,1,pos(' ',s));
+ s:=trim(s);
+ mpz_set_str(e,pchar(s),16);
+ result:=result or $01;
+ continue;
+ end;
+ if pos('Version: ',s)=1 then begin
+ delete(s,1,pos(' ',s));
+ version:=trim(s);
+ continue;
+ end;
+ writeln(stderr,'Warnung: Unbekannte Zeile in Schlüsseldatei gefunden und ignoriert.');
+ end;
+ if (result and $04) = 0 then result:=$00
+ else result:=result and $03;
+ closefile(f);
+end;
+
+procedure symmetricEncryption(var input: mpz_t; key: tLockedString; direction: tEncryptionDirection; version: string);
+var
+ ciphers: array[tUsedCiphers] of TDCP_blockcipher;
+ ciph: tUsedCiphers;
+ i: longint;
+ bs,vNum: int64;
+ inh: array[boolean] of array of byte;
+ curr: boolean;
+ mpLen: mpz_t;
+begin
+
+ if version='' then
+ vNum:=0
+ else if version='latest' then begin
+ vNum:=1;
+ version:=inttostr(vNum);
+ end
+ else
+ vNum:=strtoint(version);
+
+ if direction=edEnc then begin
+ bs:=input.size*sizeof(input.data^);
+
+ mpz_mul_2exp(input,input,sizeof(bs)*8);
+ mpz_add_ui(input,input,bs);
+ end;
+
+ mpz_init(mpLen);
+ mpz_set_ui(mpLen,1);
+
+ for ciph:=low(tUsedCiphers) to high(tUsedCiphers) do begin
+ ciphers[ciph]:=cipherClasses[ciph].Create(nil);
+ case vNum of
+ 0: ciphers[ciph].InitStr(key.teil(ciph),TDCP_haval);
+ 1: ciphers[ciph].InitStr(key.inh+ciphNam[ciph],TDCP_haval);
+ end{of case};
+ mpz_lcm_ui(mpLen,mpLen,ciphers[ciph].getBlockSize div 8);
+ end;
+
+ bs:=mpz_get_ui(mpLen);
+ mpz_clear(mpLen);
+ bs:=ceil(bs/(input.size*sizeOf(input.data^)))*input.size*sizeOf(input.data^);
+
+ for curr:=false to true do begin
+ setlength(inh[curr],bs);
+ fillchar(inh[curr][0],length(inh[curr]),$00);
+ move(input.data^,inh[curr][0],min(length(inh[curr]),input.size*sizeOf(input.data^)));
+ end;
+
+ curr:=false;
+
+ if direction=edEnc then begin
+ for ciph:=low(tUsedCiphers) to high(tUsedCiphers) do begin
+ bs:=ciphers[ciph].getBlockSize div 8;
+ for i:=0 to (length(inh[curr]) div bs)-1 do begin
+ inh[curr][i*bs]:=inh[curr][i*bs] xor (i and $ff);
+ ciphers[ciph].EncryptECB(inh[curr][i*bs],inh[not curr][i*bs]);
+ end;
+ curr:=not curr;
+ end;
+ end
+ else
+ for ciph:=high(tUsedCiphers) downto low(tUsedCiphers) do begin
+ bs:=ciphers[ciph].getBlockSize div 8;
+ for i:=0 to (length(inh[curr]) div bs)-1 do begin
+ ciphers[ciph].DecryptECB(inh[curr][i*bs],inh[not curr][i*bs]);
+ inh[not curr][i*bs]:=inh[not curr][i*bs] xor (i and $ff);
+ end;
+ curr:=not curr;
+ end;
+
+ if direction=edDec then begin
+ bs:=0;
+ for i:=sizeof(bs)-1 downto 0 do
+ bs:=(bs shl 8) or inh[curr][i];
+
+ mpz_realloc2(input,bs*8);
+ move(inh[curr][sizeof(bs)],input.data^,input.alloc*sizeof(input.data^));
+ end
+ else begin
+ mpz_realloc2(input,length(inh[curr])*8);
+ move(inh[curr][0],input.data^,input.alloc*sizeof(input.data^));
+ end;
+
+ input.size:=input.alloc;
+
+ for curr:=false to true do
+ setlength(inh[curr],0);
+
+ for ciph:=low(tUsedCiphers) to high(tUsedCiphers) do
+ ciphers[ciph].free;
+end;
+
+function hexdump(arr: array of byte): string;
+var i: longint;
+begin
+ result:='';
+ for i:=0 to length(arr)-1 do
+ result:=result + inttohex(arr[i],2);
+end;
+
+function hexdump(s: string): string;
+var i: longint;
+begin
+ result:='';
+ for i:=1 to length(s) do
+ result:=result + inttohex(ord(s[i]),2);
+end;
+
+procedure readlnblind(out s: tLockedString);
+var c: char;
+begin
+ s:=tLockedString.create;
+ c:=#0;
+ while not (c in [#13,#27]) do begin
+ c:=readkey;
+ case c of
+ #8:
+ s.delete(s.len,1);
+ #13,#27:
+ writeln;
+ else
+ s.append(c);
+ end{of case};
+ end;
+end;
+
+procedure userCallback;
+begin
+ if keypressed then
+ if readkey in [#27,'q'] then begin
+ writeln('Abbruch durch Benutzer!');
+ halt;
+ end;
+end;
+
+function mydatetimetostr(tm: extended): string;
+var
+ zeit: int64;
+begin
+ zeit:=floor(tm*24*60*60); // in Sekunden
+ result:=inttostr(zeit mod 60); // Sekunden
+ zeit:=zeit div 60;
+ if zeit=0 then exit;
+ while length(result)<2 do
+ result:='0'+result;
+ result:=inttostr(zeit mod 60)+':'+result; // Minuten
+ zeit:=zeit div 60;
+ if zeit=0 then exit;
+ while length(result)<5 do
+ result:='0'+result;
+ result:=inttostr(zeit mod 24)+':'+result; // Stunden
+ zeit:=zeit div 24;
+ if zeit=0 then exit;
+ result:=', '+result;
+ if (zeit mod 7)<>1 then result:='e'+result;
+ result:=inttostr(zeit mod 7)+' Tag'+result;
+ zeit:=zeit div 7;
+ if zeit=0 then exit;
+ result:=', '+result;
+ if zeit<>1 then result:='n'+result;
+ result:=inttostr(zeit)+' Woche'+result;
+end;
+
+procedure readNewPassword(var pass: tLockedString; len: int64);
+var
+ cPass: tLockedString;
+begin
+ cPass:=nil;
+ repeat
+ if cPass<>nil then
+ writeln('Fehler: Die Passwörter unterscheiden sich!');
+ pass.free;
+ write('Passwort zum Sichern des Schlüssels eingeben: ');
+ readlnblind(pass);
+ cPass.Free;
+ write('Wiederholen: ');
+ readlnblind(cPass);
+ if pass.inh='' then begin
+ writeln('Fehler: Leeres Passwort!');
+ pass.free;
+ cPass.free;
+ halt(1);
+ end;
+ if pass.len<len then begin
+ writeln('Fehler: Passwort zu kurz, sollte mindestens '+inttostr(len)+' Zeichen lang sein!');
+ pass.inh:='';
+ continue;
+ end;
+ until pass.isEqual(cPass) and (pass.len<>0);
+ cPass.Free;
+end;
+
+function cpuUtilization: extended;
+var
+ procstat: textfile;
+ s: string;
+ used,idle: int64;
+ i: integer;
+begin
+ result:=0;
+ s:='';
+ assignfile(procstat,'/proc/stat');
+ reset(procstat);
+ while not eof(procstat) do begin
+ readln(procstat,s);
+ if pos('cpu ',s)=1 then break;
+ end;
+ closefile(procstat);
+ if pos('cpu ',s)<>1 then exit;
+ delete(s,1,pos(' ',s));
+ s:=trim(s);
+ used:=0;
+ idle:=0;
+ for i:=0 to 3 do begin
+ used:=used+idle;
+ idle:=strtoint(copy(s,1,pos(' ',s)-1));
+ delete(s,1,pos(' ',s));
+ s:=trim(s);
+ end;
+ result:=(used-_cpuLastUsed)/max(1,used-_cpuLastUsed + idle-_cpuLastIdle);
+ _cpuLastUsed:=used;
+ _cpuLastIdle:=idle;
+end;
+
+// tLockedString ***************************************************************
+
+constructor tLockedString.create;
+begin
+ inherited create;
+ pagesize:=sysconf(_SC_PAGESIZE);
+
+ locked:=0;
+ memlen:=0;
+ _inh:=nil;
+ memstart:=nil;
+end;
+
+destructor tLockedString.destroy;
+begin
+ unlock;
+ inherited destroy;
+end;
+
+procedure tLockedString.lock;
+begin
+ if locked>0 then begin
+ if (locked and (pagesize-1)) <> 0 then // nur ganze Speicherseiten locken!
+ locked:=(locked and not (pagesize-1)) + pagesize;
+ memlen:=locked+pagesize;
+ getmem(memstart,memlen);
+ if memstart=nil then begin
+ writeln('Fehler beim Reservieren des Speichers!');
+ halt(1);
+ end;
+ _inh:=pchar(uint64(memstart) and not (pagesize-1)) + pagesize;
+ if mlock(_inh,locked)<>0 then begin
+ writeln('Fehler beim Sperren des Speichers!');
+ halt(1);
+ end;
+ end;
+end;
+
+procedure tLockedString.unlock;
+begin
+ if locked>0 then begin
+ fillchar(memstart^,memlen,$00);
+ if munlock(_inh,locked)<>0 then begin
+ writeln('Fehler beim Entsperren des Speichers!');
+ halt(1);
+ end;
+ freemem(memstart,memlen);
+ memlen:=0;
+ locked:=0;
+ end;
+end;
+
+procedure tLockedString.wInh(i: pchar);
+begin
+ if length(i)>=locked-1 then begin
+ unlock;
+ locked:=length(i)+1;
+ lock;
+ end;
+ move(i^,_inh^,length(i)+1);
+end;
+
+procedure tLockedString.assign(ls: tLockedString);
+begin
+ unlock;
+ locked:=ls.len+1;
+ lock;
+ move(ls._inh^,_inh^,ls.len+1);
+end;
+
+procedure tLockedString.delete(posi,leng: longint);
+var
+ tmp: tLockedString;
+begin
+ if len=0 then exit;
+ while posi<1 do
+ posi:=posi+len;
+ leng:=min(leng,len-posi+1);
+ if leng=0 then exit;
+
+ tmp:=tLockedString.create;
+ tmp.assign(self);
+ move((tmp._inh+posi-1+leng)^,(_inh+posi-1)^,len+2-posi-leng);
+ tmp.free;
+end;
+
+procedure tLockedString.append(s: string);
+var
+ tmp: tLockedString;
+begin
+ if length(s)=0 then exit;
+ if len=0 then begin
+ inh:=pchar(s);
+ exit;
+ end;
+
+ tmp:=tLockedString.create;
+ tmp.assign(self);
+ unlock;
+
+ locked:=tmp.len+length(s)+1;
+ lock;
+
+ move(tmp._inh^,_inh^,tmp.len); // Teil 1
+ move(s[1],(_inh+tmp.len)^,length(s)); // Teil 2
+ (_inh+tmp.len+length(s)+1)^:=#0; // Terminator
+
+ tmp.free;
+end;
+
+function tLockedString.substr(start,leng: longint): string;
+begin
+ leng:=min(leng,len-start+1);
+ if leng<=0 then begin
+ result:='';
+ exit;
+ end;
+ setlength(result,leng);
+ move((_inh+(start-1))^,result[1],length(result));
+end;
+
+function tLockedString.len: longint;
+begin
+ result:=length(_inh);
+end;
+
+function tLockedString.isEqual(s: tLockedString): boolean;
+begin
+ result:=s.len=len;
+ if result and (len<>0) then
+ result:=compareMem(s._inh,_inh,len+1);
+end;
+
+function tLockedString.teil(cph: tUsedCiphers): string;
+begin
+ result:=
+ teil(ord(cph),ord(high(tUsedCiphers))-ord(low(tUsedCiphers))+1);
+end;
+
+function tLockedString.teil(num,tot: longint): string;
+begin
+ result:=
+ substr(
+ round(1 + num/(2*tot+1)*2*len),
+ ceil(3*len/(2*tot+1))
+ );
+end;
+
+// tNextPrimeThread ************************************************************
+
+constructor tNextPrimeThread.create(num: mpz_t; offset,step: longint);
+begin
+ inherited create(true);
+ fertig:=0;
+ abbruch:=false;
+ arbeite:=true;
+ mpz_init(myNum);
+ mpz_add_ui(myNum,num,offset);
+ myStep:=step;
+ cnt:=0;
+end;
+
+destructor tNextPrimeThread.destroy;
+begin
+ mpz_clear(myNum);
+ inherited destroy;
+end;
+
+procedure tNextPrimeThread.execute;
+var
+ dummy: mpz_t;
+ hoffnungslos: boolean;
+begin
+ mpz_init(dummy);
+ hoffnungslos:=mpz_gcd_ui(dummy,myNum,myStep)>1;
+ mpz_clear(dummy);
+ if hoffnungslos then
+ writeln(stderr,'Warnung: Dieser Thread kann keine Primzahlen finden.')
+ else
+ if nextPrimeSt(myNum,myStep,arbeite,abbruch,cnt) then
+ fertig:=fertig or $01;
+ fertig:=fertig or $02;
+end;
+
+begin
+ ReturnNilIfGrowHeapFails:=true;
+ _cpuLastUsed:=0;
+ _cpuLastIdle:=0;
+end.
+