diff options
author | Erich Eckner <git@eckner.net> | 2015-07-10 14:59:23 +0200 |
---|---|---|
committer | Erich Eckner <git@eckner.net> | 2015-07-10 14:59:23 +0200 |
commit | a86ecfdaccf8c050e4a22fdb2807d48b1d7748b6 (patch) | |
tree | 63c4e32bea88d826ec958d4d0107e600d2b3207e | |
download | rsa-a86ecfdaccf8c050e4a22fdb2807d48b1d7748b6.tar.xz |
-rw-r--r-- | .gitignore | 12 | ||||
-rw-r--r-- | rsa.lpi | 93 | ||||
-rw-r--r-- | rsa.lpr | 430 | ||||
-rw-r--r-- | rsa.lps | 220 | ||||
-rw-r--r-- | rsaunit.pas | 709 |
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* @@ -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> @@ -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. + @@ -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. + |