program knut; { Written by David Ireland of DI Management Services Pty Ltd <http://www.di-mgt.com.au> Use at your own risk. No warranties. Requires installation of CryptoSys API <http://www.cryptosys.net/> } { Compiles under Free Pascal in Delphi mode >fpc knut Free Pascal Compiler version 3.0.0 [2015/11/16] for i386 Copyright (c) 1993-2015 by Florian Klaempfl and others Target OS: Win32 for i386 Compiling knut.pas Linking knut.exe 146 lines compiled, 1.7 sec, 76464 bytes code, 4164 bytes data OUTPUT: >knut Running knut.exe at 8/03/2016 13:54:18 API_Version=50100 Aes128/CBC/pkcs5 KY=0123456789ABCDEFF0E1D2C3B4A59687 IV=FEDCBA9876543210FEDCBA9876543210 PT=[Now is the time for all good men to] PT=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F CT=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A 36677355F5C6584228B OK=C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A 36677355F5C6584228B P1=4E6F77206973207468652074696D6520666F7220616C6C20676F6F64206D656E20746F P1=[Now is the time for all good men to] } {$APPTYPE CONSOLE} {$mode Delphi} {$ASSERTIONS ON} uses SysUtils, diCryptoSys; const CRLF = #13 + #10; type // Define our own dynamic array type for `Array of Byte` TByteArr = Array of Byte; // HELPER FUNCTIONS Function cnvFromHex(strhex : AnsiString) : TByteArr; var nbytes : Integer; begin nbytes := CNV_BytesFromHexStr(NIL, 0, strhex); // Dimension the byte array to receive the output SetLength(Result, nbytes); // Do the conversion CNV_BytesFromHexStr(Pointer(Result), nbytes, strhex); end; Function cnvToHex(bytes : TByteArr) : AnsiString; var nchars : Integer; nbytes : Integer; begin nbytes := Length(bytes); nchars := nbytes * 2; // Dimension the output SetLength(Result, nchars); // Do the conversion CNV_HexStrFromBytes(Pointer(Result), nchars, Pointer(bytes), nbytes); end; Function bytes_from_string(s : AnsiString) : TByteArr; var i : Integer; begin SetLength(Result, Length(s)); for i := 1 to Length(s) do Result[i-1] := Ord(s[i]); end; Function bytes_to_string(bytes : TByteArr) : AnsiString; var i : Integer; begin SetLength(Result, Length(bytes)); for i := 1 to Length(bytes) do Result[i] := Chr(bytes[i-1]); end; Procedure pr_hexbytes(msg : String; arrbytes : Array of Byte); // Displays an array of bytes as a hex string var i : Integer; nbytes : Integer; begin Write(msg); nbytes := Length(arrbytes); For i := 0 to (nbytes - 1) do Write(IntToHex(arrbytes[i], 2)); WriteLn; end; Procedure do_tests; var key : TByteArr; iv : TByteArr; pt : TByteArr; ct : TByteArr; p1 : TByteArr; correct : TByteArr; s : AnsiString; s1 : AnsiString; n : LongInt; begin WriteLn('Running ' + ExtractFileName(ParamStr(0)) + ' at ' + DateTimeToStr(Now)); // DO QUICK CHECK WriteLn('API_Version='+(IntToStr(API_Version()))); WriteLn(CRLF+'Aes128/CBC/pkcs5'); // CONVERT FROM HEX TO BYTE ARRAYS key := cnvFromHex('0123456789ABCDEFF0E1D2C3B4A59687'); WriteLn('KY=' + cnvToHex(key)); iv := cnvFromHex('FEDCBA9876543210FEDCBA9876543210'); WriteLn('IV=' + cnvToHex(iv)); s := 'Now is the time for all good men to'; WriteLn('PT=[' + s + ']'); pt := bytes_from_string(s); WriteLn('PT=' + cnvToHex(pt)); correct := cnvFromHex('C3153108A8DD340C0BCB1DFE8D25D2320EE0E66BD2BB4A313FB75C5638E9E17753C7E8DF5975A36677355F5C6584228B'); // ENCRYPT // 1. Dimension the output buffer -- IMPORTANT n := CIPHER_EncryptBytesPad(NIL, 0, Pointer(pt), Length(pt), Pointer(key), Pointer(iv), 'Aes128/CBC/pkcs5', 0); Assert(n > 0); SetLength(ct, n); // 2. Do the encryption n := CIPHER_EncryptBytesPad(Pointer(ct), Length(ct), Pointer(pt), Length(pt), Pointer(key), Pointer(iv), 'Aes128/CBC/pkcs5', 0); WriteLn('CT=', cnvToHex(ct)); WriteLn('OK=', cnvToHex(correct)); // DECRYPT // (Output is always the same length as the input or shorter) SetLength(p1, Length(ct)); n := CIPHER_DecryptBytesPad(Pointer(p1), Length(p1), Pointer(ct), Length(ct), Pointer(key), Pointer(iv), 'Aes128/CBC/pkcs5', 0); Assert(n > 0); //WriteLn('P1=', cnvToHex(p1)); // Shorten if necessary to remove padding SetLength(p1, n); WriteLn('P1=', cnvToHex(p1)); // Assuming it's valid ASCII text, convert to a string s1 := bytes_to_string(p1); WriteLn('P1=[' + s1 + ']'); WriteLn(CRLF+'ALL DONE.'); end; // MAIN PROCEDURE begin try do_tests; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; end.