2009. április 30., csütörtök
How to detect if DCOM is enabled
Problem/Question/Abstract:
How to detect if DCOM is enabled
Answer:
function IsDCOMEnabled: Boolean;
var
Ts: string;
R: TRegistry;
begin
r := TRegistry.Create;
r.RootKey := HKEY_LOCAL_MACHINE;
r.OpenKey('Software\Microsoft\OLE', False);
ts := AnsiUpperCase(R.ReadString('EnableDCOM'));
r.Free;
Result := (Ts = 'Y');
end;
2009. április 29., szerda
How to send key events to any control in a process
Problem/Question/Abstract:
I want to create a software keyboard in one form. When I press a key on the sofware keyboard, I would like to send the key's char to any form in my application.
Answer:
The following method will send key events to any control in your own process. It will not work reliably for windows in other processes.
{
Procedure PostKeyEx
Parameters:
hWindow:
Target window to be send the keystroke
key:
Virtual keycode of the key to send. For printable keys this is simply the ANSI code (Ord(character)).
shift:
State of the modifier keys. This is a set, so you can set several of these keys (shift, control, alt, mouse buttons) in tandem. The TShiftState type is declared in the Classes Unit.
specialkey:
Normally this should be False. Set it to True to specify a key on the numeric keypad, for example.
If this parameter is true, bit 24 of the lparam for the posted WM_KEY* messages will be set.
Description:
This procedure sets up Windows key state array to correctly reflect the requested pattern of modifier keys and then posts a WM_KEYDOWN/WM_KEYUP message pair to the target window. Then Application.ProcessMessages is called to process the messages before the keyboard state is restored.
Error Conditions:
May fail due to lack of memory for the two key state buffers. Will raise an exception in this case.
Note:
Setting the keyboard state will not work across applications running in different memory spaces on Win32 unless AttachThreadInput is used to connect to the target thread first.
Created:
02/21/96 16:39:00 by Peter Below
}
procedure PostKeyEx(hWindow: HWnd; key: Word; const shift: TShiftState; specialkey:
Boolean);
type
TBuffers = array[0..1] of TKeyboardState;
var
pKeyBuffers: ^TBuffers;
lparam: LongInt;
begin
{check if the target window exists}
if IsWindow(hWindow) then
begin
{set local variables to default values}
pKeyBuffers := nil;
lparam := MakeLong(0, MapVirtualKey(key, 0));
{modify lparam if special key requested}
if specialkey then
lparam := lparam or $1000000;
{allocate space for the key state buffers}
New(pKeyBuffers);
try
{Fill buffer 1 with current state so we can later restore it.
Null out buffer 0 to get a "no key pressed" state.}
GetKeyboardState(pKeyBuffers^[1]);
FillChar(pKeyBuffers^[0], Sizeof(TKeyboardState), 0);
{set the requested modifier keys to "down" state in the buffer}
if ssShift in Shift then
pKeyBuffers^[0][VK_SHIFT] := $80;
if ssAlt in Shift then
begin
{Alt needs special treatment since a bit in lparam needs also be set}
pKeyBuffers^[0][VK_MENU] := $80;
lparam := lparam or $20000000;
end;
if ssCtrl in Shift then
pKeyBuffers^[0][VK_CONTROL] := $80;
if ssLeft in Shift then
pKeyBuffers^[0][VK_LBUTTON] := $80;
if ssRight in Shift then
pKeyBuffers^[0][VK_RBUTTON] := $80;
if ssMiddle in Shift then
pKeyBuffers^[0][VK_MBUTTON] := $80;
{make out new key state array the active key state map}
SetKeyboardState(pKeyBuffers^[0]);
{post the key messages}
if ssAlt in Shift then
begin
PostMessage(hWindow, WM_SYSKEYDOWN, key, lparam);
PostMessage(hWindow, WM_SYSKEYUP, key, lparam or $C0000000);
end
else
begin
PostMessage(hWindow, WM_KEYDOWN, key, lparam);
PostMessage(hWindow, WM_KEYUP, key, lparam or $C0000000);
end;
{process the messages}
Application.ProcessMessages;
{restore the old key state map}
SetKeyboardState(pKeyBuffers^[1]);
finally
{free the memory for the key state buffers}
if pKeyBuffers < > nil then
Dispose(pKeyBuffers);
end;
end;
end;
procedure TForm1.SpeedButton2Click(Sender: TObject);
var
W: HWnd;
begin
W := Memo1.Handle;
PostKeyEx(W, VK_END, [ssCtrl, ssShift], False); {select all}
PostKeyEx(W, Ord('C'), [ssCtrl], False); {copy to clipboard}
PostKeyEx(W, Ord('C'), [ssShift], False); {replace with C}
PostKeyEx(W, VK_RETURN, [], False); {new line}
PostKeyEx(W, VK_END, [], False); {go to end}
PostKeyEx(W, Ord('V'), [ssCtrl], False); {paste from keyboard}
end;
2009. április 28., kedd
Disabling the system keys from your application
Problem/Question/Abstract:
When my application is running, I'd like to prevent users from using Ctrl-Alt-Del and Alt- Tab. What's the best way to do this?
Answer:
This is pretty quick one... The best way I've seen yet is to trick Windows into thinking that a screen saver is running. When Windows thinks a screensaver is active, Ctrl-Alt-Del and Alt-Tab (Win95 only for this) are disabled. You can perform this trickery by calling a WinAPI function, SystemParametersInfo. For a more in-depth discussion about what this function does, I encourage you to refer to the online help.
In any case, SystemParametersInfo takes four parameters. Here's its C declaration from the Windows help file:
BOOL SystemParametersInfo(
UINT uiAction, // system parameter to query or set
UINT uiParam, // depends on action to be taken
PVOID pvParam, // depends on action to be taken
UINT fWinIni // user profile update flag
);
For our purposes we'll set uiAction to SPI_SCREENSAVERRUNNING, uiParam to 1 or 0 (1 to disable the keys, 0 to re-enable them), pvParam to a "dummy" pointer address, then fWinIni to 0. Pretty straight-forward. Here's what you do:
To disable the keystrokes, write this:
SystemParametersInfo(SPI_SCREENSAVERRUNNING, 1, @ptr, 0);
To enable the keystrokes, write this:
SystemParametersInfo(SPI_SCREENSAVERRUNNING, 0, @ptr, 0);
Not much to it, is there? Thanks to the folks on the Borland Forums for providing this information!
2009. április 27., hétfő
Open an application inside a TForm at a predefined position
Problem/Question/Abstract:
How do I open an executable in a determined form's area? Example: Open an executable and show it on the left forms part with a size of 400 x 300.
Answer:
This works for me. Keep in mind that some apps have their startup settings set somewhere which may override the Startup structure you pass.
procedure TForm1.Button1Click(Sender: TObject);
var
StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
begin
FillChar(StartupInfo, Sizeof(StartupInfo), #0);
StartupInfo.cb := Sizeof(StartupInfo);
StartupInfo.dwFlags := STARTF_USEPOSITION or STARTF_USESIZE;
StartupInfo.wShowWindow := SW_SHOWNORMAL;
StartupInfo.dwX := Left;
StartupInfo.dwY := Top;
StartupInfo.dwXSize := 400;
StartupInfo.dwYSize := 300;
CreateProcess(nil, 'yourapp.exe', nil, nil, false, CREATE_NEW_CONSOLE or
NORMAL_PRIORITY_CLASS, nil, nil, StartupInfo, ProcessInfo);
end;
2009. április 26., vasárnap
How to retrieve all string properties and their values from any TObject descendant
Problem/Question/Abstract:
How to retrieve all string properties and their values from any TObject descendant
Answer:
{ ... }
var
XObject: TObject;
XProps: PPropList;
XPropInfo: PPropInfo;
XTypeData: PTypeData;
XPropsStr: string;
i: integer;
{ ... }
begin
{ ... }
XObject := OneOfYourComponents;
XTypeData := TypInfo.GetTypeData(XObject.ClassInfo);
XPropsStr := '';
GetMem(XProps, XTypeData^.PropCount * sizeof(Pointer));
try
TypInfo.GetPropInfos(XObject.ClassInfo, XProps);
for i := 0 to XTypeData.PropCount - 1 do
begin
XPropInfo := XProps[i];
if Assigned(XPropInfo) then
begin
if XPropInfo.PropType^^.Kind in [tkString, tkLString, tkWString] then
XPropsStr := XPropsStr + XProps[i].Name + ' = ' +
GetStrProp(XObject, XProps[i].Name) + #$0D#$0A;
end;
end;
finally
FreeMem(XProps);
end;
ShowMessage(XPropsStr);
{ ... }
2009. április 25., szombat
Maximize the columns of a TStringGrid when the form resizes
Problem/Question/Abstract:
When a form resizes, how do I resize the columns so they will occupy all available space? E.g. if stringgrid.width=100 and I have 4 columns, how do I adjust the columns width?
Answer:
procedure TForm1.FormResize(Sender: TObject);
var
c: integer;
colWidth: integer;
lineWidths: integer;
delta: integer;
begin
Grid.Width := ClientWidth - 24; {or whatever}
lineWidths := Grid.GridLineWidth * (Grid.ColCount - 1);
colWidth := (Grid.ClientWidth div Grid.ColCount) - Grid.GridLineWidth;
delta := (Grid.ClientWidth - (colWidth * Grid.ColCount)) - lineWidths;
for c := 0 to Grid.ColCount - 1 do
begin
Grid.ColWidths[c] := colWidth;
if c = Grid.ColCount - 1 then
Grid.ColWidths[c] := Grid.ColWidths[c] + delta;
end;
end;
2009. április 24., péntek
How to respond to QueryNewPalette and PaletteChanged messages
Problem/Question/Abstract:
How to respond to QueryNewPalette and PaletteChanged messages
Answer:
Here is a simple test program I wrote for displaying a 256 color bitmap. It works properly on my system ... so far. The code was derived from a sample which is included in the WM_QUERYNEWPALETTE help description in the Microsoft Visual C++ compiler (The Win API). These examples were not included in the Delphi version of the Win API help file for some reason. Too bad because they are extremely useful.
This code passes all the tests on my system. The app starts with the bitmap displayed correctly. With another app in the foreground or with an icon (for example the MSDOS icon) dragged on top, it displays a proper "background palette". Minimizing and moving the window shows a proper palette.
In the form's Oncreate method, I LoadFromFile to a temp bitmap then StretchDraw that to the Image1 canvas. I found I needed handlers for WM_QueryNewPalette to realize the bitmap's palette - and WM_PaletteChanged to call the WinAPI UpdateColors function to map the palette to the system palette. UpdateColors avoids the horrible background palette map.
unit Paltst;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, ExtCtrls, Menus, Buttons;
type
TForm1 = class(TForm)
Image1: TImage;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
procedure QNewPalette(var Msg: TWMQueryNewPalette); message WM_QueryNewPalette;
procedure PalChanged(var Msg: TWMPaletteChanged); message WM_PaletteChanged;
public
{ Public declarations }
end;
var
Form1: TForm1;
Bmap: TBitmap;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
var
i: Word;
begin
Bmap := TBitmap.Create;
Bmap.LoadFromFile('Test.bmp');
Image1.Canvas.StretchDraw(Image1.BoundsRect, Bmap);
end;
procedure TForm1.QNewPalette(var Msg: TWMQueryNewPalette);
var
i: Word;
DC: HDC;
HPold: HPalette;
begin
DC := Form1.Canvas.Handle;
HPold := SelectPalette(DC, Bmap.Palette, False);
i := RealizePalette(DC);
SelectPalette(DC, HPold, False);
if (i > 0) then
InvalidateRect(Handle, nil, False);
Msg.Result := i;
end;
procedure TForm1.PalChanged(var Msg: TWMPaletteChanged);
var
i: Word;
DC: HDC;
HPold: HPalette;
begin
if (Msg.PalChg = Handle) then
Msg.Result := 0
else
begin
DC := Form1.Canvas.Handle;
HPold := SelectPalette(DC, Bmap.Palette, True);
i := RealizePalette(DC);
UpdateColors(DC);
SelectPalette(DC, HPold, False);
end;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Bmap.Free;
end;
end.
2009. április 23., csütörtök
Navigate a TPageControl using Ctrl-Tab and Ctrl-Shift-Tab if several pagecontrols are on a form
Problem/Question/Abstract:
I have a PageControl having 3 TabSheets. If this PageControl has a Panel as its parent, then I am able navigate between the tabsheets using Ctrl-Tab (forward) or Shift-Ctrl-Tab (backward) using the keyboard. But if the same pagecontrol has another Tabsheet of a Pagecontrol as its parent, then I am not able to navigate between the tabsheets of the child pagecontrol using the keyboard even though the focus is on the child pagecontrol.
Answer:
Handling proper Ctrl-Tab and Ctrl-Shift-Tab switching of pages if several pagecontrols are on a form:
In form declaration:
procedure CMDialogKey(var msg: TCMDialogKey); message CM_DIALOGKEY;
procedure TForm1.CMDialogKey(var msg: TCMDialogKey);
var
Control: TWinControl;
begin
with Msg do
begin
if (charcode = VK_TAB) and (GetKeyState(VK_CONTROL) < 0) then
begin
Control := ActiveControl;
while Assigned(Control) do
if Control is TPageControl then
begin
Control.Perform(CM_DIALOGKEY, charcode, keydata);
Exit;
end
else
Control := Control.Parent;
end;
end;
inherited;
end;
2009. április 22., szerda
Display WYSIWYG fonts in a list box
Problem/Question/Abstract:
You can display the available fonts in a WYSIWYG fashion.
Answer:
Start a new project, add a TListBox, in the Form�s OnCreate event code:
procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.Items := Screen.Fonts;
end;
Set the ListBox�s style property to lbOwnerDrawVariable and finally and the following code to the ListBox�s OnDrawItem and OnMeasureItem events
procedure TForm1.ListBox1MeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
var
h: integer;
begin
with Control as TListBox do
begin
Canvas.Font.Name := Items[Index];
h := Canvas.TextHeight(Items[Index]);
end;
Height := h;
end;
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
with Control as TListBox do
begin
Canvas.Font.Name := Items[Index];
Canvas.FillRect(Rect);
Canvas.TextOut(Rect.Left, Rect.Top, Items[Index]);
end;
end;
2009. április 21., kedd
Changing system date and time in Windows
Problem/Question/Abstract:
I want to assign a new time to the system time. How would I do this? I tried to get the system time through GetSystemTime() and set the new time to SetSystemTime(), but I get the wrong results.
Answer:
Solve 1:
This sets the time to the same time in year 1999:
procedure TForm1.Set1999(Sender: TObject);
var
stSystemTime: TSystemTime;
begin
Windows.GetLocalTime(stSystemTime);
stSystemTime.wYear := 1999;
Windows.SetLocalTime(stSystemTime);
end;
Solve 2:
By using the following call (example is a method of a button click) you may directly modify the date and time of Windows.
procedure TForm1.Button1Click(Sender: TObject);
var
NewTime: TSystemTime;
begin
FillChar(NewTime, sizeof(NewTime), #0);
NewTime.wYear := 2000;
NewTime.wMonth := 8;
NewTime.wDay := 28;
NewTime.wHour := 0;
NewTime.wMinute := 0;
NewTime.wSecond := 0;
NewTime.wMilliseconds := 0;
SetLocalTime(NewTime);
end;
Please note that when you do chage the system time, send a WM_TIMECHANGE message to all toplevel windows so that they can detect the time change... You should do this for all version of windows but 2000 since it does it by its self. Bellow is the code:
if IsWin2000 = False then
SendMessage(HWND_TOPMOST, WM_TIMECHANGE, 0, 0);
function IsWin2000(): Boolean;
var
OSInfo: TOSVersionInfo;
begin
Result := False;
OSInfo.dwOSVersionInfoSize := SizeOf(OsInfo);
if not GetVersionEx(OSInfo) then
begin
Exit;
end;
if OsInfo.dwPlatformID = VER_PLATFORM_WIN32_NT then
begin
if OSInfo.dwMajorVersion >= 5 then
Result := True;
end;
end;
2009. április 20., hétfő
Scroll text in title bar of a window
Problem/Question/Abstract:
How to scroll a string of text in the caption of a window, in an editbox or in the application''s title so it''s displayed in the Start-menu toolbar (even when the form is minimized).
Answer:
It's very simple to scroll a text so it gets displayed in the Start-menu toolbar the same way as Winamp scrolls a songs title.
First two global variables are needed:
var
ScrollPosition: integer = 0;
ScrollText: string = ' This is the scrolltext...';
The first integer ScrollPosition keep tracks of the current position of the scroll text, and the string ScrollText is the actual text that will scroll. A tip is to start the scroll text with the same number of spaces as the number of characters that will be displayed at the same time, then the scroll will seem to start from the right and scroll to the left instead of the first character popping up directly at the first position.
The procedure that does the actual scrolling needs to be called every time the scroll needs to be updated. An OnTimer event (TTimer) suits good for that matter.
procedure TForm1.Timer1Timer(Sender: TObject);
const
SCROLL_AREA = 10;
begin
// Gets the part of the scroll that should be displayed
Form1.Caption := Copy(ScrollText, ScrollPosition, SCROLL_AREA);
// Increase scroll position to the next character
Inc(ScrollPosition);
// Reset position when the scroll has reached it's end
if ScrollPosition >= Length(ScrollText) then
ScrollPosition := 0;
end;
The code is pretty self explaining together with it's comments. The constant SCROLL_AREA decides how many characters of the scroll should be displayed at once.
Exactly the same code may be used to scroll text in an TEdit control instead, simply replace Form1.Caption with Edit1.Text (or what the name of the control is) instead. To make the title of the window that is viewed in the Start-menu toolbar to scroll, use Application.Title.
2009. április 19., vasárnap
Working with Browser
Problem/Question/Abstract:
Execute a Javascript function in a Webbrowser/ IE Document?
Answer:
uses
MSHTML_TLB, SHDocVw, ShellAPI;
function to execute a script function
function ExecuteScript(doc: IHTMLDocument2; script: string; language: string):
Boolean;
var
win: IHTMLWindow2;
Olelanguage: Olevariant;
begin
if doc <> nil then
begin
try
win := doc.parentWindow;
if win <> nil then
begin
try
Olelanguage := language;
win.ExecScript(script, Olelanguage);
finally
win := nil;
end;
end;
finally
doc := nil;
end;
end;
end;
Examples how to login to gmx homepage
procedure FillInGMXForms(WB: ShDocVW_TLB.IWebbrowser2; IDoc1: IHTMLDocument2;
Document: Variant; AKennung, APasswort: string);
const
IEFields: array[1..4] of string = ('INPUT', 'text', 'INPUT', 'password');
var
IEFieldsCounter: Integer;
i: Integer;
m: Integer;
ovElements: OleVariant;
begin
if Pos('GMX - Homepage', Document.Title) <> 0 then
while WB.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
// count forms on document and iterate through its forms
IEFieldsCounter := 0;
for m := 0 to Document.forms.Length - 1 do
begin
ovElements := Document.forms.Item(m).elements;
// iterate through elements
for i := ovElements.Length - 1 downto 0 do
begin
try
// if input fields found, try to fill them out
if (ovElements.item(i).tagName = IEFields[1]) and
(ovElements.item(i).type = IEFields[2]) then
begin
ovElements.item(i).Value := AKennung;
Inc(IEFieldsCounter);
end;
if (ovElements.item(i).tagName = IEFields[3]) and
(ovElements.item(i).type = IEFields[4]) then
begin
ovElements.item(i).Value := APasswort;
Inc(IEFieldsCounter);
end;
except
// failed...
end;
end; { for i...}
end; { for m }
// if the fields are filled in, submit.
if IEFieldsCounter = 3 then
ExecuteScript(iDoc1, 'document.login.submit()',
'JavaScript');
end;
function LoginGMX_IE(AKennung, APasswort: string): Boolean;
var
ShellWindow: IShellWindows;
WB: ShDocVW_TLB.IWebbrowser2;
spDisp: IDispatch;
IDoc1: IHTMLDocument2;
Document: Variant;
k: Integer;
begin
ShellWindow := CoShellWindows.Create;
// get the running instance of Internet Explorer
for k := 0 to ShellWindow.Count do
begin
spDisp := ShellWindow.Item(k);
if spDisp = nil then
Continue;
// QueryInterface determines if an interface can be used with an object
spDisp.QueryInterface(iWebBrowser2, WB);
if WB <> nil then
begin
WB.Document.QueryInterface(IHTMLDocument2, iDoc1);
if iDoc1 <> nil then
begin
WB := ShellWindow.Item(k) as ShDocVW_TLB.IWebbrowser2;
Document := WB.Document;
// if GMX page...
FillInGMXForms(WB, IDoc1, Document, AKennung, APasswort);
end; { idoc <> nil }
end; { wb <> nil }
end; { for k }
end;
Navigate to the gmx homepage in the IE browser an login
procedure TForm1.Button1Click(Sender: TObject);
begin
ShellExecute(Handle,
'open',
'http://www.gmx.ch',
nil,
nil,
SW_SHOW);
Sleep(2000);
LoginGMX_IE('user@gmx.net', 'pswd');
end;
Navigate to the gmx homepage in the Webbrowser an login
procedure TForm1.Button2Click(Sender: TObject);
var
IDoc1: IHTMLDocument2;
Web: ShDocVW_TLB.IWebBrowser2;
begin
Webbrowser1.Navigate('http://www.gmx.ch');
while Webbrowser1.ReadyState <> READYSTATE_COMPLETE do
Application.ProcessMessages;
Webbrowser1.Document.QueryInterface(IHTMLDocument2, iDoc1);
Web := WebBrowser1.ControlInterface;
FillInGMXForms(Web, iDoc1, Webbrowser1.Document, 'user@gmx.net', 'pswd');
end;
2009. április 18., szombat
Abbreviating Array Properties
Problem/Question/Abstract:
Wouldn't it be much easier to enter AStringList[Index] instead of AStringList.Strings[Index]? Well you can, and you can add this functionality to your own classes.
Answer:
This may be obvious to some, but it's also something that I haven't come across until now, so I figured it might be useful to someone out there.
For many array properties found in classes in delphi, you can simplify access by abbreviating the call. This means that you can use the syntax ArrayProperty[Index] as opposed to ArrayProperty.Items[Index].
Either way is appropriate, and there is no right or wrong, however here is what I think. The advantage to using the abbreviated version make repeated calls easier to look at, especially if there are in one parameter list. The only disadvantage I can think of is that someone else reading the code might not be able to determine what you are referencing without some thought, or knowledge of the class in question.
Here's an example using a TStringList:
Unabbreviated:
for I := 0 to MyStringList.Count - 1 do
ShowMessage(MyStringList.Strings[I]);
Abbreviated:
for I := 0 to MyStringList.Count - 1 do
ShowMessage(MyStringList[I]);
Again, in that example it really doesn't save much, but in my code I have some classes I created and have to repeatedly call different sometimes. Here's an example of something I might do, and how the abbreviation cleans things up:
for I := 0 to UserList.Count - 1 do
if AUser.Read(UserList.Items[I].Company, UserList.Items[I].User) then
begin
ACompanyStr := UserList.Items[I].Company;
AUserStr := UserList.Items[I].User;
end;
Now the code in this example is pretty useless, and some would say why not use a 'with UserList.Items[I] do' statement to clean things up. However often I might have these nested within other 'with' statments, so the 'with' solution is not available.
Now look at the abbreviated code:
for I := 0 to UserList.Count - 1 do
if AUser.Read(UserList[I].Company, UserList[I].User) then
begin
ACompanyStr := UserList[I].Company;
AUserStr := UserList[I].User;
end;
It definetly reduces the amount of code, and I believe it does clean up the appearance.
What makes this all possible is the use of the 'default' directive with the corresponding array property.
This can be used for many different items in delphi already including TStringList, TListItem, etc. but there are some items that do not have default array properties and therefore you cannot access in the abbreviated fashion.
If you attempt to access something that does not have the default array property, such as the TListView component (I.E. ListView[I].Caption instead of ListView.Items[I].Caption), you will recieve an error such as "Class does not have default property".
2009. április 17., péntek
Debug a Delphi Expert instaled as a package
Problem/Question/Abstract:
Debugging an Expert can be a tedious task, unless you follow these steps.
Answer:
Ok, here are the instructions.
Open your package.
You have toModify the Project Options: In the Packages tab uncheck your package. In the Compiler tab uncheck Optimization, select the Stack_frames option, an select also the debugger options.
Compile the package.
Select Run-Parameters, select Delphi as the host application, (a package is just a DLL with a fancy extension). Click the Load Button.
Press F9, another instance of Delphi will load, so run your expert from there.
Now you can use the debugger from the first instance of Delphi to debug your expert code running in the second one.
2009. április 16., csütörtök
Drag and Drop Thread
Problem/Question/Abstract:
This demo shows how to perform a drag drop wich does not block the user interface during the copying of large files.
Answer:
{ Drag & Drop Thread
Copyright (c) 2000, 2001 by E.J.Molendijk
This class is a part of:
"Drag and Drop Component Suite" (http://www.melander.dk).
Explained:
When you create the thread, it will copy the filenames of the specified
DropFileSource. These filenames will be used by thread to perform a
drag&drop operation. The calling thread continues uninterupted.
Usage is very simple:
TDragDropThread.Create(DropFileSource1);
Drag&Drop Thread info Q139408:
http://support.microsoft.com/support/kb/articles/Q139/4/08.asp
}
unit DragDropThread;
interface
uses
Classes, DropSource, ActiveX, Windows;
type
TDragDropThread = class(TThread)
private
{ Private declarations }
FFiles: string;
protected
procedure Execute; override;
public
constructor Create(DropFileSource: TDropFileSource);
end;
implementation
{ TDragDropThread }
constructor TDragDropThread.Create(DropFileSource: TDropFileSource);
begin
// Thread will start immediately after creation
inherited Create(False);
// Copy filenames from supplied DropFileSource
FFiles := DropFileSource.Files.Text;
// This thread disappeard when it finishes
FreeOnTerminate := True;
end;
procedure TDragDropThread.Execute;
var
DropFileSource: TDropFileSource;
pt: TPoint;
hwndAttach: HWND;
dwAttachThreadID, dwCurrentThreadID: DWORD;
begin
// Get handle of window under mouse-cursor
GetCursorPos(pt);
hwndAttach := WindowFromPoint(pt);
Assert(hwndAttach <> 0, 'Unable to find window with drag-object');
// Get thread ID's
dwAttachThreadID := GetWindowThreadProcessId(hwndAttach, nil);
dwCurrentThreadID := GetCurrentThreadId();
// Attach input queues if necessary
if (dwAttachThreadID <> dwCurrentThreadID) then
AttachThreadInput(dwAttachThreadID, dwCurrentThreadID, True);
// Initialize Ole for this thread
OleInitialize(nil);
try
// create dropsource
DropFileSource := TDropFileSource.Create(nil);
try
DropFileSource.Files.Text := FFiles;
// start drag&drop
DropFileSource.Execute;
finally
// cleanup dropsource
DropFilesource.Free;
end;
finally
// cleanup Ole
OleUninitialize;
end;
// Restore input queues settings
if (dwAttachThreadID <> dwCurrentThreadID) then
AttachThreadInput(dwAttachThreadID, dwCurrentThreadID, False);
end;
end.
2009. április 15., szerda
Block mouse clicks to a specific window
Problem/Question/Abstract:
I need to create an invisible window over a webbrowser component so that I can stop mouse clicks.
Answer:
There are much better ways to block mouse clicks to a specific window. You can use a handler for the Application.OnMessage event, for example:
procedure TMainform.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppOnMessage;
end;
procedure TMainform.AppOnMessage(var Msg: TMsg; var Handled: Boolean);
begin
case Msg.Message of
WM_MOUSEFIRST..WM_MOUSELAST, WM_MOUSEWHEEL:
if Msg.hwnd = Webbrowser1.HWND then
Handled := True;
end;
end;
I need to create an invisible window over a webbrowser component so that I can stop mouse clicks.
Answer:
There are much better ways to block mouse clicks to a specific window. You can use a handler for the Application.OnMessage event, for example:
procedure TMainform.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppOnMessage;
end;
procedure TMainform.AppOnMessage(var Msg: TMsg; var Handled: Boolean);
begin
case Msg.Message of
WM_MOUSEFIRST..WM_MOUSELAST, WM_MOUSEWHEEL:
if Msg.hwnd = Webbrowser1.HWND then
Handled := True;
end;
end;
2009. április 14., kedd
Secure Compression for TStringList
Problem/Question/Abstract:
How to load and save encrypted string lists
Answer:
I combined routines from two open source projects to produce a simple way of saving a stringlist to disk in a compressed and very securely encrypted fashion (using the AES algorithm).
The two components are LockBox from Turbopower - available at
http://sourceforge.net/projects/tplockbox/ http://sourceforge.net/projects/tplockbox/
and UCL Compression Library API for Borland Delphi from
http://www.zeitungsjunge.de/delphi/ucl/index.htm http://www.zeitungsjunge.de/delphi/ucl/index.htm
The unit EncCompress is listed below. It defines a simple class TCompEnc which lets you load a text file into the stringlist. To save a plain text string list, first compress it using the UCLCompressStream, then feed this into the lockbox encryption component and save that to disk. Loading the encrypted file back in is just a matter of reversing the process, load the file, decrypt it then decompress it.
I've provided a simple test program - just drop a couple of buttons onto a form and hook up the click event to these routines. Make sure that the text for the key is the same in both!! You'll need a test file 'test.txt', and after clicking both buttons you should find that the 'test2.txt' that is output is identical to the original.
I appreciate I've done two things which aren't very good- one use an internal member directly (enc.flist) and used a tMemoryStream to save and load files from disk instead of a TFileStream (before anyone points these out!)
Note: the AES (Rijndael) is symmetric so the same key encrypts and decrypts.
// Sample event handler code
procedure TForm1.Button1Click(Sender: TObject);
var
enc: TCompEnc;
list: tstringlist;
begin
Enc := TCompEnc.Create;
list := tstringlist.create;
list.LoadFromFile('test.txt');
enc.flist.Text := list.text;
enc.KeyText := 'hgjhgkjghkjh654328878';
enc.SaveToFile('test.dat');
enc.free;
list.free;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
enc: TCompEnc;
begin
Enc := TCompEnc.Create;
Enc.KeyText := 'hgjhgkjghkjh654328878';
Enc.LoadFromfile('test.dat');
Enc.Flist.SaveToFile('test2.txt');
Enc.free;
end;
// The unit
unit EncCompress;
interface
uses
Windows, SysUtils, Classes, diuclstreams, LbCipher, LbClass;
type
TCompEnc = class
FList: TStringList;
FKeyText: string;
private
function GetList: TStringlist;
procedure SetKeyText(const Value: string);
public
constructor Create;
destructor Destroy; override;
procedure LoadFromFile(Filename: string);
procedure SaveToFile(Filename: string);
property List: TStringlist read GetList;
property KeyText: string write SetKeyText;
end;
implementation
uses math;
const
COMPRESSION_LEVEL = 3;
BUFFER_SIZE = $4000;
{ TCompEnc }
constructor TCompEnc.Create;
begin
inherited;
Flist := TStringList.Create;
end;
destructor TCompEnc.Destroy;
begin
FList.Free;
inherited;
end;
function TCompEnc.GetList: TStringlist;
begin
Result := Flist;
end;
// Step 1 Compress Flist Strings into stream
// Compress stream
// Save stream to file.
procedure TCompEnc.SaveToFile(Filename: string);
var
Str: TStringStream;
CompStream: TMemoryStream;
FileStream: TMemoryStream;
MyCipher: TLbRijndael;
begin
MyCipher := TLbRijnDael.Create(nil);
MyCipher.GenerateKey(FKeyText);
Str := tStringStream.Create(Flist.Text);
Str.Position := 0;
CompStream := TMemoryStream.create;
UclCompressStream(Str, CompStream, 3, BUFFER_SIZE);
Str.Free;
CompStream.Position := 0;
try
// Prepare key...
Filestream := tmemoryStream.Create;
MyCipher.EncryptStream(CompStream, FileStream);
FileStream.Position := 0;
FileStream.SaveToFile(Filename);
FileStream.Free;
finally
CompStream.Free;
end;
end;
// Loads File.
// 1st step, decrypt from AES to just Compressed
// 2nd step, Decompress into flist
procedure TCompEnc.LoadFromFile(Filename: string);
var
Source, Dest: TMemoryStream;
MyCipher: TLbRijnDael;
begin
// Decryption
Source := TMemoryStream.Create;
Source.LoadFromFile(Filename);
Source.Position := 0;
Dest := TMemoryStream.Create;
MyCipher := TLbRijnDael.Create(nil);
MyCipher.GenerateKey(FKeyText);
try
MyCipher.DecryptStream(Source, Dest);
MyCipher.Free;
Dest.Position := 0;
Source.Position := 0;
if UclDecompressStream(Dest, Source, BUFFER_SIZE) then
begin
Flist.Clear;
Source.Position := 0;
Flist.LoadFromStream(Source);
end;
finally
Dest.Free;
end;
Source.Free;
end;
procedure TCompEnc.SetKeyText(const Value: string);
begin
FKeyText := Value;
end;
end.
How to load and save encrypted string lists
Answer:
I combined routines from two open source projects to produce a simple way of saving a stringlist to disk in a compressed and very securely encrypted fashion (using the AES algorithm).
The two components are LockBox from Turbopower - available at
http://sourceforge.net/projects/tplockbox/ http://sourceforge.net/projects/tplockbox/
and UCL Compression Library API for Borland Delphi from
http://www.zeitungsjunge.de/delphi/ucl/index.htm http://www.zeitungsjunge.de/delphi/ucl/index.htm
The unit EncCompress is listed below. It defines a simple class TCompEnc which lets you load a text file into the stringlist. To save a plain text string list, first compress it using the UCLCompressStream, then feed this into the lockbox encryption component and save that to disk. Loading the encrypted file back in is just a matter of reversing the process, load the file, decrypt it then decompress it.
I've provided a simple test program - just drop a couple of buttons onto a form and hook up the click event to these routines. Make sure that the text for the key is the same in both!! You'll need a test file 'test.txt', and after clicking both buttons you should find that the 'test2.txt' that is output is identical to the original.
I appreciate I've done two things which aren't very good- one use an internal member directly (enc.flist) and used a tMemoryStream to save and load files from disk instead of a TFileStream (before anyone points these out!)
Note: the AES (Rijndael) is symmetric so the same key encrypts and decrypts.
// Sample event handler code
procedure TForm1.Button1Click(Sender: TObject);
var
enc: TCompEnc;
list: tstringlist;
begin
Enc := TCompEnc.Create;
list := tstringlist.create;
list.LoadFromFile('test.txt');
enc.flist.Text := list.text;
enc.KeyText := 'hgjhgkjghkjh654328878';
enc.SaveToFile('test.dat');
enc.free;
list.free;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
enc: TCompEnc;
begin
Enc := TCompEnc.Create;
Enc.KeyText := 'hgjhgkjghkjh654328878';
Enc.LoadFromfile('test.dat');
Enc.Flist.SaveToFile('test2.txt');
Enc.free;
end;
// The unit
unit EncCompress;
interface
uses
Windows, SysUtils, Classes, diuclstreams, LbCipher, LbClass;
type
TCompEnc = class
FList: TStringList;
FKeyText: string;
private
function GetList: TStringlist;
procedure SetKeyText(const Value: string);
public
constructor Create;
destructor Destroy; override;
procedure LoadFromFile(Filename: string);
procedure SaveToFile(Filename: string);
property List: TStringlist read GetList;
property KeyText: string write SetKeyText;
end;
implementation
uses math;
const
COMPRESSION_LEVEL = 3;
BUFFER_SIZE = $4000;
{ TCompEnc }
constructor TCompEnc.Create;
begin
inherited;
Flist := TStringList.Create;
end;
destructor TCompEnc.Destroy;
begin
FList.Free;
inherited;
end;
function TCompEnc.GetList: TStringlist;
begin
Result := Flist;
end;
// Step 1 Compress Flist Strings into stream
// Compress stream
// Save stream to file.
procedure TCompEnc.SaveToFile(Filename: string);
var
Str: TStringStream;
CompStream: TMemoryStream;
FileStream: TMemoryStream;
MyCipher: TLbRijndael;
begin
MyCipher := TLbRijnDael.Create(nil);
MyCipher.GenerateKey(FKeyText);
Str := tStringStream.Create(Flist.Text);
Str.Position := 0;
CompStream := TMemoryStream.create;
UclCompressStream(Str, CompStream, 3, BUFFER_SIZE);
Str.Free;
CompStream.Position := 0;
try
// Prepare key...
Filestream := tmemoryStream.Create;
MyCipher.EncryptStream(CompStream, FileStream);
FileStream.Position := 0;
FileStream.SaveToFile(Filename);
FileStream.Free;
finally
CompStream.Free;
end;
end;
// Loads File.
// 1st step, decrypt from AES to just Compressed
// 2nd step, Decompress into flist
procedure TCompEnc.LoadFromFile(Filename: string);
var
Source, Dest: TMemoryStream;
MyCipher: TLbRijnDael;
begin
// Decryption
Source := TMemoryStream.Create;
Source.LoadFromFile(Filename);
Source.Position := 0;
Dest := TMemoryStream.Create;
MyCipher := TLbRijnDael.Create(nil);
MyCipher.GenerateKey(FKeyText);
try
MyCipher.DecryptStream(Source, Dest);
MyCipher.Free;
Dest.Position := 0;
Source.Position := 0;
if UclDecompressStream(Dest, Source, BUFFER_SIZE) then
begin
Flist.Clear;
Source.Position := 0;
Flist.LoadFromStream(Source);
end;
finally
Dest.Free;
end;
Source.Free;
end;
procedure TCompEnc.SetKeyText(const Value: string);
begin
FKeyText := Value;
end;
end.
2009. április 13., hétfő
Easy Parsing an XML File
Problem/Question/Abstract:
In modern times, a configuration file has to be an XML standard so you want to parse that file to get the elements from corresponding nodes.
Answer:
First you have to import the Type library. This will create a wrapper class for that component and all you have to do is to name it in uses in your unit.
I used msxml.dll(Version 2.0) to install the XML parsing components in the IDE through the Import Type Library option.
See article for more details: Importing XML DOM Parser in Delphi
Second we produce a simple XML file like a configuration file:
(Name the file myconfig.xml)
<?xml version="1.0"?>
<databases>
<database db="InterBase">
<connection>
<name>TrueSoft</name>
<path>superPath</path>
<user>MaxMin</user>
</connection>
</database>
<database db="myMax">
<connection>
<name>maXml</name>
<server>kylix02</server>
<user>carpeDiem</user>
</connection>
</database>
</databases>
Third we build the procedure that parses 3 elements and assign it to strings:
myname, mypath, myuser: string[255];
The accID and idNr are just to make the procedure more flexible for permissions and node navigation. The whole procedure goes like this:
Find the file myconfig.xml
Create the interface pointer xmlDoc
Load the XML file
Check the error handling with xmlDoc.parseError
Select the node
Check if it has childs
Get the nodelist and assign the elements to strings
procedure TForm1.parseXML;
var
SRec1: TSearchRec;
accID: boolean;
idNr: byte;
myXMLpath: string;
xmlDoc: IXMLDomDocument2;
xmlnode: IXMLDomNode;
xmlnodelist: IXMLDomNodeList;
myname, mypath, myuser: string[255];
begin
accID := true;
idNr := 1;
myXMLpath := extractFilePath(Application.ExeName);
if FindFirst(myXMLpath + 'myconfig.xml', faAnyFile, SRec1) = 0 then
begin
xmlDoc := CoDomDocument30.Create;
xmlDoc.validateOnParse := True;
xmlDoc.async := False;
xmlDoc.load(myXMLpath + 'myconfig.xml');
if xmlDoc.parseError.errorCode = 0 then
begin
if accID then
begin
xmlDoc.setProperty('SelectionLanguage', 'XPath');
xmlnode := xmlDoc.selectSingleNode('//databases/database
[@db = '+''''+' InterBase '+''''+ ']');
if xmlnode.hasChildNodes then
begin
if (idNR <= xmlnode.childNodes.length) and (idNR > 0) then
begin
xmlnodelist := xmlnode.childNodes.item[(idNR - 1)].selectNodes
('name');
if xmlnodelist.length <> 0 then
myname := xmlnode.childNodes.item[(idNR - 1)].selectNodes('name').item
[0].text;
xmlnodelist := xmlnode.childNodes.item[(idNR - 1)].selectNodes
('path');
if xmlnodelist.length <> 0 then
mypath := xmlnode.childNodes.item[(idNR - 1)].selectNodes('path').item
[0].text;
xmlnodelist := xmlnode.childNodes.item[(idNR - 1)].selectNodes
('user');
if xmlnodelist.length <> 0 then
myuser := xmlnode.childNodes.item[(idNR - 1)].selectNodes('user').item
[0].text;
end;
end
else
showmessage('no XML Childs');
end
else
showmessage('no permission');
end
else
begin
showmessage('load XML error');
xmlDoc := nil;
FindClose(SRec1)
end;
end
else
showmessage('no XML file');
end;
In modern times, a configuration file has to be an XML standard so you want to parse that file to get the elements from corresponding nodes.
Answer:
First you have to import the Type library. This will create a wrapper class for that component and all you have to do is to name it in uses in your unit.
I used msxml.dll(Version 2.0) to install the XML parsing components in the IDE through the Import Type Library option.
See article for more details: Importing XML DOM Parser in Delphi
Second we produce a simple XML file like a configuration file:
(Name the file myconfig.xml)
<?xml version="1.0"?>
<databases>
<database db="InterBase">
<connection>
<name>TrueSoft</name>
<path>superPath</path>
<user>MaxMin</user>
</connection>
</database>
<database db="myMax">
<connection>
<name>maXml</name>
<server>kylix02</server>
<user>carpeDiem</user>
</connection>
</database>
</databases>
Third we build the procedure that parses 3 elements and assign it to strings:
myname, mypath, myuser: string[255];
The accID and idNr are just to make the procedure more flexible for permissions and node navigation. The whole procedure goes like this:
Find the file myconfig.xml
Create the interface pointer xmlDoc
Load the XML file
Check the error handling with xmlDoc.parseError
Select the node
Check if it has childs
Get the nodelist and assign the elements to strings
procedure TForm1.parseXML;
var
SRec1: TSearchRec;
accID: boolean;
idNr: byte;
myXMLpath: string;
xmlDoc: IXMLDomDocument2;
xmlnode: IXMLDomNode;
xmlnodelist: IXMLDomNodeList;
myname, mypath, myuser: string[255];
begin
accID := true;
idNr := 1;
myXMLpath := extractFilePath(Application.ExeName);
if FindFirst(myXMLpath + 'myconfig.xml', faAnyFile, SRec1) = 0 then
begin
xmlDoc := CoDomDocument30.Create;
xmlDoc.validateOnParse := True;
xmlDoc.async := False;
xmlDoc.load(myXMLpath + 'myconfig.xml');
if xmlDoc.parseError.errorCode = 0 then
begin
if accID then
begin
xmlDoc.setProperty('SelectionLanguage', 'XPath');
xmlnode := xmlDoc.selectSingleNode('//databases/database
[@db = '+''''+' InterBase '+''''+ ']');
if xmlnode.hasChildNodes then
begin
if (idNR <= xmlnode.childNodes.length) and (idNR > 0) then
begin
xmlnodelist := xmlnode.childNodes.item[(idNR - 1)].selectNodes
('name');
if xmlnodelist.length <> 0 then
myname := xmlnode.childNodes.item[(idNR - 1)].selectNodes('name').item
[0].text;
xmlnodelist := xmlnode.childNodes.item[(idNR - 1)].selectNodes
('path');
if xmlnodelist.length <> 0 then
mypath := xmlnode.childNodes.item[(idNR - 1)].selectNodes('path').item
[0].text;
xmlnodelist := xmlnode.childNodes.item[(idNR - 1)].selectNodes
('user');
if xmlnodelist.length <> 0 then
myuser := xmlnode.childNodes.item[(idNR - 1)].selectNodes('user').item
[0].text;
end;
end
else
showmessage('no XML Childs');
end
else
showmessage('no permission');
end
else
begin
showmessage('load XML error');
xmlDoc := nil;
FindClose(SRec1)
end;
end
else
showmessage('no XML file');
end;
2009. április 12., vasárnap
Insert Zero converted number to text
Problem/Question/Abstract:
When I convert number(0012) to text I take a result just number (12). How can i take a result of number with zeros?
Answer:
Solve 1:
function StrZero(AValue, ALength: integer): string;
begin
Result := FormatFloat(StringOfChar('0', ALength), AValue);
end;
Solve 2:
function FormatWithZero(const AValue, ALen: Integer): string;
begin
Result := Format('%.' + IntToStr(ALen) + 'd', [AValue]);
end;
When I convert number(0012) to text I take a result just number (12). How can i take a result of number with zeros?
Answer:
Solve 1:
function StrZero(AValue, ALength: integer): string;
begin
Result := FormatFloat(StringOfChar('0', ALength), AValue);
end;
Solve 2:
function FormatWithZero(const AValue, ALen: Integer): string;
begin
Result := Format('%.' + IntToStr(ALen) + 'd', [AValue]);
end;
2009. április 11., szombat
Bravion - Strong Encryption Algorithm
Problem/Question/Abstract:
Is there more to encryption than XORing output from Random(256) with a chars from a string? Yes there's allot more to it.
Answer:
ABOUT
The name Bravion is pronnounced brave-ion. It is an alegory for molecules undergoing chemical reactions. A molecule is separeted into its ions, which then regroup with ions from a reactant to form new ions. In this algorithm, the ions change properties as well: protons, neutrons and electrons are reconfigured by the reactant and make the resulting molecules unpredictable without knowing the original reactant. Indeed it takes a brave ion to undergo such abuse :)
The routines here aren't very straight forward, even for one who has studied ciphers. I will try to keep it in lamens terms to the best of my ability. Bravion uses a 256bit key and a 128bit block size. It is an iterated (multiple rounds) substitution/permutation network. It is fast, but not nearly the fastest I've seen. I encrypt around 3MB/sec on my system.
GLOSSARY - read carefully
block size:
Size in bits of the data to encrypt (fixed in all block ciphers)
plaintext:
Data that has not yet been encrypted.
ciphertext:
Data that has been encrypted.
key:
Data used to modify plaintext into an incomprehensible sate.
entropy:
Unpredicatble data.
permutation:
Transformation of data by displacements (of individual or grouped bits) or transformation of data by mathematical functions. Dependent permutations require another source of data, and once permutated, both data are required to reverse the permutation.
dependency:
Data required to inverse a permutation.
key size:
Size in bits of the data used as a key (this can be variable in *some* ciphers, but is limited to the dependency imposed by the block size)
xor:
Bitwise exclusive OR. xor has an important property: if A xor B = C, then C xor A = B, C xor B = A xor works wonders for permutations.
mul:
Multiplication modulo 2^32 where a factor of 0 is interpreted as 2^32+1.
add:
Addition modulo 2^32.
sub:
Subtraction modulo 2^32.
shr:
Bit-shift to the right covering the ENTIRE block of data rather than individual integers.
shl:
Same as shr, but the bit shift is to the left.
substitution:
Exchanging one group of bits for another. The result of a substitution depends on the bits that are being substituted. This process is always reversable, using irreversable substitution to change data is considered (by myself) a permutation.
S-BOX:
An array of values that are used to replace on block of data for another such as SBOX:array[0..255]of byte would be used to replace a byte for another:
B: byte;
B := SBOX[B];
To reverse the process S-BOXs can be structured such that SBOX[SBOX[B]]=B or (preferably) a compliment of the X-BOX can be created such that SBOX_1[SBOX_0[B]]=B An S-BOX's array must be of suitable size to accept any input data as an index (for a byte: 0..255, for a word: 0..65535). S-BOXs are very efficient substitution
mechanisms.
feistel network:
Data is divided into 2 halfs, one half is permutated (and/or substituted) and the second half is a product (usualy an xor) of the permuted first half and itself. To reverse the process the inverse of the product is obtained for to restore the second half (in the case of an xor, another xor does the trick) and the first half is then restored with the inserve of the permutation applied to it.
round:
An intteration of a set of functions. Almost all ciphers implement rounds. Some use as little as 8, others use as many as 32. A general rule of thumb is the more rounds, the harder it is to break the cipher (unless the rounds are very simple). The number of rounds is usualy a little bigger than the minimum needed to maintain a safe cihper. It is a compromise between security and speed.
round keys:
Data that contains entropy from the key used in sequencial order determined by the current round.
component:
A group of operations (permutations, substitutions etc..)
attacker:
Someone trying to decrypt ciphertext without the key.
satistical analysis:
Using probability theory to aid in *guessing* possible plaintext from ciphertext.
brute force:
Decrypting ciphertext with every possible key until the plaintext is found. If an attacker is unable to break a cipher, the only option is brute force (holding a gun to whomever knows the key's head is not considered brute force, it's considered social engineering)
ALGORITHM
The encryption process can be broken down into 5 components.
BEFORE ITTERATING THROUGH THE ROUNDS
[1]
B[0] := B[0] xor RK[PK[16], 0]; //PK holds the path keys
B[1] := B[1] xor RK[PK[17], 1]; //that determine the round
B[2] := B[2] xor RK[PK[18], 2]; //keys to use
B[3] := B[3] xor RK[PK[19], 3];
A key-dependent permutation by XOR with round keys. Which round keys are used depends on the original key. A set of path keys is extrapolated from the key. Which round keys are used is unknown to an attacker. This is done so that in the event that portions of the round keys have been recovered by an attacker, knowledge of the original key is inherently required. The original key cannot be found by solving all the round keys due to the initialization mechanism (discussed later). This is done to the plaintext before entering the first round and after finishing the last round. This dissolves linearity of repetited components (even though there should be none, I have taken no chances with Bravion. I have not seen this sort of permutation in any other algorithm, but I am confident that this component seriously impairs an attacker's chances at successful statistical analysis.
ROUND DESCRIPTION
This part is repeated 16 times.
[2]
CarryBit := (B[0] and 2147483648) shr 31;
B[0] := (B[0] shl 1) or ((B[1] and 2147483648) shr 31);
B[1] := (B[1] shl 1) or ((B[2] and 2147483648) shr 31);
B[2] := (B[2] shl 1) or ((B[3] and 2147483648) shr 31);
B[3] := (B[3] shl 1) or CarryBit;
the data put through a shl and the last bit of the block is put into the first bit. In most ciphers data is only re-ordered in bytes, word, or longwords, and this leads to statistical analysis of these groups of bits. Since each bit is shifted 1 bit, every byte/word/longword recieves 1 bit from the previous. After itterating through 16 rounds, each byte has been permuted with each bit twice. Their order does not change however, so the same statistical analysis can be accomplished. The solution to this problem lies in [4]. The reverse is a shr and the first bit of the block is put into the last bit.
[3]
B[3] := B[3] xor (B[2] - RK[i, 3]);
B[2] := B[2] xor Mul(B[1], RK[i, 2]);
B[1] := B[1] xor (B[0] + RK[i, 1]);
B[0] := B[0] xor RK[i, 0];
Taking out all the components designed to reinforce Bravion except [5], the heart of Bravion lies here. The Theory employed here lies in 3 algebraic [is that how it's spelt?] groups, add, mul, xor each having an etropy the same size as its inputs (in this case 32bits). Using a fixed parameter (the round key) and going through each possible value with the second parameter will never result in the same output with any of these 3 groups. The second important property of this component is that all but one longword of the block are dependent of the others. To solve B[1] you must solve B[0], to solve B[2] you have to have solved B[2] with B[0] and so on. Only B[0] is independent of the other longwords of the block. xor is used, because of the inefficiency (in speed) of calculating the inverses of these algebraic groups.
[4]
for i := 0 to 15 do
T[i] := B[P0[PK[i], 0]]
Move(T, B, 16);
//T,B:array[0..15]of byte
This is what I called a re-ordering matrix. Things get a little akward in this component. Have a look at the square matrix below:
P0: array[0..15, 0..15] of longword = (
($A, $3, $B, $C, $5, $E, $9, $F, $0, $7, $4, $6, $1, $D, $2, $8),
($9, $5, $F, $3, $1, $0, $A, $4, $7, $B, $E, $8, $2, $6, $D, $C),
($6, $D, $A, $4, $3, $5, $2, $8, $B, $F, $9, $C, $0, $E, $7, $1),
($E, $7, $0, $D, $8, $B, $1, $3, $9, $6, $C, $4, $A, $2, $F, $5),
($C, $A, $2, $5, $F, $D, $7, $9, $4, $E, $6, $B, $8, $3, $1, $0),
($5, $9, $3, $8, $D, $6, $4, $C, $1, $0, $7, $2, $E, $B, $A, $F),
($0, $6, $4, $A, $7, $3, $B, $E, $2, $8, $5, $1, $D, $F, $C, $9),
($D, $F, $9, $0, $6, $2, $3, $1, $E, $C, $A, $5, $B, $8, $4, $7),
($1, $0, $C, $2, $9, $7, $6, $D, $3, $5, $8, $E, $F, $A, $B, $4),
($3, $8, $5, $7, $2, $C, $E, $B, $A, $9, $D, $F, $4, $1, $0, $6),
($F, $B, $D, $1, $C, $8, $0, $6, $5, $2, $3, $7, $9, $4, $E, $A),
($8, $E, $1, $9, $4, $F, $C, $5, $6, $D, $2, $A, $7, $0, $3, $B),
($4, $C, $7, $6, $E, $1, $5, $2, $F, $A, $B, $0, $3, $9, $8, $D),
($7, $2, $6, $B, $0, $4, $D, $A, $8, $1, $F, $3, $5, $C, $9, $E),
($2, $1, $8, $E, $B, $A, $F, $7, $D, $4, $0, $9, $C, $5, $6, $3),
($B, $4, $E, $F, $A, $9, $8, $0, $C, $3, $1, $D, $6, $7, $5, $2));
Pay attention to the values in each rown and each column. In every row, values from 0 to 15 are assigned once, and in every column, values from 0 to 15 are assigned once. Each row represents an order to put the bytes of the block in. To demonstrate I will use the following block of plaintext:
B = 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
Using the first row for this demonstration value can be assigned to a temporary block through indexing:
T[0] := B[P0[0]]; //T[0]:=B[$A];
T[1] := B[P0[1]]; //T[1]:=B[$3];
T[2] := B[P0[2]]; //T[2]:=B[$B];
{...and so on... }
T[15] := B[P0[15]]; //T[15]:=B[$8];
T = 26, 19, 27, 28, 21, 30, 25, 31, 16, 23, 20, 22, 17, 29, 18, 24
T now contains all bytes of B, but in the new order. T is then copied into B and B has been re-ordered. There are 16 rows in all. A path key determines which row to use, hence which order to put B in. To reverse the permutation I have created a re-ordering matrix that is the inverse of this one such that T[0]=B[P0[0]], B[0]=T[P1[0]. There are 16! (=~2.09x10^13=~2^44) ways to re-order 16 bytes. This subsitution occurs 16 times, and since no 2 rows will put any byte in the same position (look at the columns), the number of possible orders is increased by a factor of 16 each time, for a total of 16^16. This means that we cover all the possible orders 4.2 million times in excess! This is only the theoretical boundary, the true boundary is still 16!, but we at least know that the resulting ciphertext could be in ANY of these 16! arrangements. The re-ordering matrix by itself helps, but does not do much against statistical analysis because the bits are still in 8bit groups. Combined with the re-ordering matrix, the 1bit shift, scatters bits independently from each-other in 16! orders. I have read papers stating that idealy, blocks should be permuted as one block and not sub-blocks, but that because of the data size required to achieve such a large permutation would be beyond the reach of our technology. To put things into context, an S-BOX of 8bits in 8bits out is 255bytes, 16bits-in 16bits-out is 131072bytes, 128bits-in 128bits-out would be 5.4x10^39bytes! Unfortunatly, this structure only allows for 2^44 different block-sized permutations, but it's still a great advantage.
[5]
for i := 0 to 15 B[i] := S0[B[i], j];
//B:array[0..15]of byte
This component substitutes each byte in B for another. There are 16 of these S-BOXs and an inversed S-BOX for each. One S-BOX is used for each round. I've added these S-BOXs as a precaution. I used my random number generator NoiseSpunge (article name "Cryptographic Random Numbers") to generate completly random S-BOXs. The result is the outputs are drastic permutations on 8bit groups.
INITIALIZATION
Initialization is done in 3 steps.
[1]
The key is divided into 32 bit groups. Each group serves as as seed to a pseudo random number generator (PRNG). This PRNG has a period of 2^32 implying that no 2 seeds will generate the same sequence and that it will no show signs of a pattern before ~4billion numbers have been output. Each of the 8 seeds are used to generate 256bits which are stored as the round keys.
[2]
Path keys are extrapolated directly from the key by means of this function:
for i := 0 to 15 do //SET 4BIT PATH KEYS
begin
PK[i] := (Key[i] xor Key[i + 16]) and $F;
j := 16 + (i mod 8);
PK[j] := PK[j] xor (Key[i] xor Key[i + 16]) and $F0) shr 4;
end; //Key is interpreted as array[0..31]of byte
[3]
The key is encrypted with the current round keys and the resulting ciphertext is used to replace 2 sets of round keys. This is repeated until each set of round keys has been overwritten 128 times. This may seem like obsessive paranoya, but that would be incorrect. This is a precaution against brute force. If initialization requires encrypting 256 blocks, then for every key an attacker wants to test will take the a little longer than it takes to decrypt 256 blocks! Of course to the end user this doesn't even put a dent in his processor usage, but to an attacker trying to test 2^256 keys, it will lengthen his search by a factor of 256. This is like adding 8bits of key data to his search. I haven't seen this form of initialization used as a brute force deterent before, but I'm certain I'm not the first to think about it.
I strongly recomend you read this article "256bit keys for strong encryption" as well use the unit included to produce the 256bit keys.
Below is the entire unit. Credit is as always well appreciated!
//BRAVION (C)Copyright DrMungkee 2001
unit Bravion;
interface
type
TBravionBlock8 = array[0..15] of byte;
TBravionBlock32 = array[0..3] of longword;
TBravionKey8 = array[0..31] of byte;
TBravionKey32 = array[0..7] of longword;
TBravionRoundKey32 = array[0..15] of TBravionBlock32;
TBravionPathKey8 = array[0..23] of longword;
TBravionContext = record
RK: TBravionRoundKey32;
PK: TBravionPathKey8;
end;
procedure BravionInit(var Context: TBravionContext; var Key: TBravionKey32);
procedure BravionDecrypt(var Context: TBravionContext; var B: TBravionBlock32);
procedure BravionEncrypt(var Context: TBravionContext; var B: TBravionBlock32);
implementation
const
//SUBSTITUTION BOXES FOR EACH ROUND
S0: array[0..15, 0..255] of longword = ((
$68, $9D, $A8, $7C, $0D, $E1, $C1, $21, $BC, $97, $84, $A2, $DE, $EE, $45, $BD,
$17, $D8, $32, $D5, $A7, $1A, $64, $23, $1B, $B8, $07, $A1, $3B, $6E, $DF, $8D,
$24, $50, $F4, $73, $C4, $59, $B7, $38, $D3, $47, $10, $E7, $93, $DD, $0A, $3C,
$36, $AA, $9A, $B1, $75, $8E, $5B, $9B, $49, $33, $C8, $A4, $1C, $06, $20, $46,
$88, $FA, $FC, $CC, $2E, $AD, $05, $1D, $86, $EF, $04, $3F, $6D, $0F, $D2, $5C,
$DB, $5F, $0C, $71, $E3, $87, $A3, $8F, $AC, $9E, $0B, $AB, $EA, $5E, $AF, $16,
$44, $E6, $39, $FB, $2A, $43, $3A, $F9, $48, $7E, $11, $08, $4C, $CB, $ED, $8B,
$95, $C0, $01, $29, $4E, $B6, $63, $5D, $A9, $52, $56, $C5, $BB, $12, $81, $91,
$F7, $7F, $4F, $3E, $2C, $F1, $EB, $54, $B5, $00, $6C, $8A, $26, $FF, $1E, $CA,
$83, $9F, $D7, $EC, $77, $85, $B3, $F2, $CF, $28, $6B, $BF, $02, $96, $B0, $27,
$F8, $F6, $DC, $D6, $7B, $65, $78, $60, $70, $82, $B9, $98, $BA, $62, $30, $61,
$19, $B2, $09, $E9, $18, $79, $22, $14, $D9, $D1, $B4, $15, $E5, $F5, $92, $51,
$80, $6A, $53, $89, $D4, $E0, $0E, $31, $76, $55, $4D, $9C, $94, $E4, $A0, $FE,
$CD, $F3, $4A, $2F, $03, $1F, $69, $D0, $72, $F0, $AE, $8C, $E2, $41, $5A, $7D,
$13, $74, $35, $42, $A6, $90, $25, $C7, $58, $2B, $6F, $C2, $66, $99, $E8, $3D,
$C6, $C9, $57, $CE, $37, $67, $7A, $BE, $40, $2D, $34, $4B, $A5, $C3, $DA, $FD), (
$78, $8D, $66, $CD, $1A, $9C, $0A, $FB, $D8, $3B, $9E, $6B, $73, $54, $45, $75,
$15, $4C, $B5, $B1, $1B, $E0, $A3, $17, $2A, $57, $F0, $82, $07, $C5, $0C, $27,
$88, $12, $A5, $1F, $8F, $D2, $18, $7B, $D3, $D9, $56, $F9, $05, $5C, $06, $68,
$41, $6F, $94, $60, $C6, $C3, $6E, $E2, $D6, $11, $34, $19, $3D, $E5, $E1, $3E,
$47, $B2, $DB, $F4, $B6, $CF, $F5, $10, $4B, $FA, $AB, $7F, $1C, $37, $46, $EE,
$D7, $A6, $E9, $53, $FD, $CE, $EA, $8C, $84, $C7, $6C, $85, $9A, $D5, $28, $DC,
$2B, $FF, $32, $EB, $77, $F2, $24, $4E, $9D, $03, $20, $81, $59, $DE, $C4, $6A,
$A7, $89, $AE, $2E, $3A, $40, $86, $F8, $E4, $D1, $0B, $E8, $E7, $90, $D0, $08,
$02, $B0, $4F, $B3, $C0, $92, $1D, $97, $7D, $E6, $99, $21, $9B, $83, $70, $AC,
$C1, $80, $5E, $23, $5B, $4A, $65, $A8, $63, $61, $6D, $95, $16, $F1, $C2, $52,
$96, $7C, $FE, $3F, $BD, $0D, $B4, $44, $ED, $42, $A0, $2C, $35, $22, $04, $0E,
$D4, $51, $A2, $EC, $43, $AF, $B9, $EF, $39, $49, $2F, $69, $7E, $F3, $BF, $71,
$67, $25, $8B, $8A, $01, $2D, $76, $79, $5F, $E3, $87, $3C, $31, $5A, $36, $1E,
$9F, $98, $58, $CA, $A9, $BB, $DD, $AD, $A1, $50, $09, $33, $A4, $CB, $0F, $B8,
$13, $14, $26, $29, $30, $38, $62, $FC, $72, $64, $DF, $00, $F7, $C8, $8E, $4D,
$AA, $5D, $CC, $C9, $55, $74, $48, $DA, $91, $7A, $B7, $BC, $F6, $93, $BA, $BE), (
$74, $8B, $4E, $20, $AC, $E8, $7A, $EF, $E2, $D6, $80, $BE, $A7, $05, $AA, $55,
$C6, $DE, $1A, $5E, $1D, $30, $DA, $4B, $3D, $6D, $49, $4D, $5C, $9F, $77, $D1,
$0E, $B3, $A5, $28, $0A, $F6, $E0, $83, $63, $7D, $3A, $E7, $E1, $C4, $7C, $27,
$53, $54, $AD, $D3, $87, $F9, $FE, $A9, $1B, $F8, $99, $79, $43, $A1, $04, $46,
$B2, $B4, $67, $CD, $F5, $14, $64, $BA, $16, $4F, $AE, $6A, $5B, $02, $DD, $32,
$BF, $A4, $4C, $36, $2F, $10, $A6, $FA, $01, $8D, $ED, $FF, $7F, $93, $9A, $6F,
$1C, $A3, $92, $B0, $97, $2B, $AF, $6B, $2D, $41, $FB, $EB, $78, $22, $C1, $91,
$51, $15, $F1, $BC, $42, $6E, $70, $CB, $71, $C0, $25, $86, $8A, $18, $85, $98,
$39, $F4, $E5, $00, $D5, $0F, $17, $45, $C3, $5F, $58, $2E, $C5, $7B, $B9, $40,
$1F, $A0, $9C, $3E, $F2, $21, $31, $0B, $9B, $EA, $72, $5D, $76, $13, $3B, $52,
$C8, $61, $09, $D2, $96, $75, $11, $94, $CF, $D0, $29, $06, $CC, $DF, $CE, $33,
$62, $B5, $2C, $1E, $81, $88, $90, $A2, $26, $19, $84, $E3, $D8, $08, $3F, $F3,
$8F, $AB, $B1, $BD, $50, $60, $23, $FC, $3C, $65, $EC, $07, $FD, $A8, $03, $E9,
$DC, $95, $CA, $47, $35, $69, $0D, $38, $DB, $E4, $D4, $C9, $9D, $F0, $5A, $37,
$B8, $6C, $C7, $4A, $68, $82, $66, $24, $7E, $89, $0C, $12, $2A, $34, $44, $48,
$56, $57, $59, $73, $8C, $B6, $E6, $D7, $8E, $EE, $F7, $C2, $D9, $9E, $B7, $BB), (
$DE, $9A, $C5, $FB, $93, $3E, $4E, $99, $68, $CC, $2E, $34, $07, $4F, $D1, $AB,
$36, $50, $73, $19, $57, $F5, $16, $F8, $64, $D7, $37, $CA, $48, $62, $A9, $25,
$3C, $3F, $0C, $C3, $A0, $DF, $D3, $C0, $3D, $66, $B2, $52, $94, $5E, $0E, $4D,
$F0, $69, $8D, $AD, $EF, $4C, $29, $A1, $7C, $02, $23, $5D, $9E, $AC, $03, $97,
$B5, $D6, $6B, $BA, $DC, $83, $C6, $AF, $F6, $9F, $F2, $09, $75, $76, $54, $15,
$00, $DA, $8F, $71, $7B, $6F, $3A, $CE, $C1, $F1, $0F, $67, $B8, $C8, $ED, $45,
$32, $1A, $2B, $6E, $B1, $BE, $85, $C7, $28, $BB, $C2, $82, $5F, $FD, $B0, $5B,
$D5, $44, $61, $63, $7A, $0D, $1C, $E3, $F7, $A6, $8A, $98, $31, $7D, $11, $80,
$A7, $EB, $A8, $22, $51, $E2, $F4, $47, $74, $A3, $14, $FF, $E6, $33, $42, $DD,
$D8, $92, $01, $1D, $9C, $90, $EA, $BD, $8B, $B9, $E9, $24, $65, $7F, $D2, $6A,
$81, $30, $9B, $B7, $E4, $60, $B3, $4A, $8C, $18, $B6, $53, $5A, $41, $B4, $3B,
$D0, $F3, $2D, $87, $27, $26, $2A, $9D, $A4, $D4, $CF, $BC, $17, $72, $43, $46,
$2F, $08, $91, $E0, $1F, $13, $88, $6C, $89, $8E, $38, $A2, $40, $C4, $AE, $FA,
$FE, $E7, $EC, $78, $04, $84, $39, $E5, $77, $E8, $BF, $F9, $55, $59, $12, $21,
$10, $86, $1B, $C9, $05, $A5, $FC, $49, $EE, $CB, $E1, $79, $DB, $96, $5C, $CD,
$D9, $06, $0A, $0B, $1E, $20, $2C, $35, $4B, $56, $58, $6D, $70, $7E, $95, $AA), (
$AE, $02, $85, $29, $A7, $FB, $64, $1C, $77, $78, $69, $F4, $D7, $27, $0F, $41,
$54, $17, $A0, $03, $BB, $72, $E8, $3E, $C6, $3C, $65, $7D, $5E, $DD, $F7, $6B,
$E1, $E9, $2A, $EC, $B0, $34, $35, $73, $BA, $6D, $32, $7A, $50, $2E, $8A, $3D,
$12, $E6, $A6, $4A, $14, $8F, $31, $E2, $5D, $21, $CA, $8C, $48, $63, $8B, $92,
$87, $BC, $16, $61, $E3, $5B, $08, $A5, $E7, $DA, $93, $3B, $94, $13, $0D, $9E,
$07, $CE, $96, $38, $BE, $4F, $60, $66, $B3, $81, $F0, $B2, $36, $FE, $04, $FD,
$C4, $0A, $75, $BF, $A4, $2C, $1D, $83, $42, $C1, $BD, $49, $C9, $B5, $9C, $79,
$A1, $D8, $1B, $47, $D4, $74, $19, $24, $01, $51, $53, $EA, $ED, $1F, $67, $1E,
$71, $D0, $6A, $2F, $62, $3A, $11, $AF, $B1, $57, $26, $43, $9A, $CB, $1A, $70,
$C7, $7B, $39, $2B, $AB, $F2, $A9, $0B, $CC, $B9, $4B, $10, $DE, $E4, $FC, $D2,
$AC, $CD, $EE, $00, $20, $AD, $68, $56, $D3, $AA, $6F, $15, $30, $7C, $28, $E5,
$95, $25, $55, $5F, $0C, $D9, $C0, $A2, $59, $91, $C5, $82, $CF, $9B, $37, $A3,
$F9, $F5, $C2, $22, $A8, $23, $4D, $B7, $FA, $40, $C3, $FF, $D5, $0E, $05, $97,
$5C, $99, $18, $33, $D6, $F1, $B4, $DC, $B6, $D1, $09, $86, $8E, $F3, $52, $06,
$2D, $7E, $EB, $C8, $7F, $3F, $44, $45, $46, $4C, $4E, $58, $88, $DF, $80, $84,
$F8, $90, $9D, $9F, $F6, $8D, $B8, $89, $98, $EF, $5A, $DB, $E0, $6C, $6E, $76), (
$5E, $63, $73, $A1, $FE, $6A, $8E, $C1, $5C, $D8, $1F, $D7, $B1, $97, $FB, $91,
$78, $EB, $1C, $FA, $2C, $D5, $95, $B0, $40, $48, $89, $CE, $3C, $34, $43, $BF,
$4A, $32, $9C, $5B, $71, $AF, $FD, $D2, $29, $18, $C0, $20, $72, $2B, $45, $0E,
$C8, $55, $83, $15, $E5, $A7, $DB, $A5, $8D, $E7, $4F, $7D, $C3, $00, $D3, $85,
$B5, $B4, $C2, $D9, $04, $88, $B8, $AE, $80, $C4, $99, $BB, $61, $13, $0C, $60,
$6F, $9D, $AD, $56, $AA, $F1, $46, $8B, $F2, $8C, $F5, $F7, $51, $E4, $E6, $2F,
$37, $12, $82, $67, $CA, $DF, $A6, $B3, $0F, $AB, $53, $44, $7F, $E9, $10, $1A,
$7A, $9B, $92, $26, $81, $03, $DD, $C5, $11, $DA, $65, $BD, $4C, $42, $86, $E0,
$31, $50, $84, $1D, $B2, $B6, $27, $14, $CF, $49, $D1, $30, $23, $52, $9E, $7C,
$7E, $4B, $BA, $38, $BC, $3F, $EE, $6E, $02, $16, $74, $CB, $2A, $96, $E1, $E3,
$35, $58, $06, $3D, $09, $3E, $E2, $93, $E8, $9A, $8F, $D4, $94, $F4, $47, $CD,
$33, $3A, $A4, $05, $21, $66, $87, $22, $39, $70, $69, $1E, $F9, $75, $24, $79,
$1B, $2E, $5A, $A2, $C6, $C7, $6B, $A8, $54, $D6, $5F, $F6, $EA, $08, $57, $FF,
$28, $6D, $DC, $EF, $41, $BE, $0D, $FC, $7B, $DE, $76, $A9, $CC, $62, $01, $A3,
$EC, $25, $59, $3B, $F8, $07, $0A, $0B, $17, $19, $2D, $36, $A0, $ED, $4E, $B7,
$C9, $5D, $9F, $68, $AC, $64, $F3, $6C, $98, $4D, $D0, $8A, $77, $90, $F0, $B9), (
$4D, $B2, $3C, $E6, $96, $B9, $9D, $C3, $A3, $9E, $FE, $1B, $76, $ED, $46, $31,
$60, $C8, $3E, $98, $FF, $D0, $E2, $F8, $7D, $B8, $99, $FD, $64, $68, $BB, $40,
$8B, $25, $2A, $DE, $4F, $E5, $88, $DB, $2B, $44, $32, $EB, $15, $C5, $5E, $F1,
$3D, $01, $A4, $11, $BA, $5B, $8F, $0A, $37, $7F, $E0, $23, $7A, $2D, $EE, $1E,
$A6, $29, $F7, $F0, $35, $4C, $63, $8A, $93, $92, $34, $B4, $4A, $89, $C4, $F6,
$33, $9C, $FA, $0B, $38, $EA, $2F, $AD, $80, $E1, $1F, $BD, $91, $16, $5C, $9A,
$12, $0D, $26, $82, $6C, $DF, $19, $1A, $54, $45, $F3, $D8, $A1, $3A, $65, $86,
$77, $02, $B1, $74, $97, $BC, $6E, $CF, $F4, $7C, $B0, $8D, $50, $48, $FC, $41,
$09, $81, $95, $6A, $D5, $59, $0E, $E3, $05, $C0, $78, $51, $A8, $87, $84, $D6,
$C9, $E8, $C2, $14, $21, $49, $7E, $0C, $EC, $66, $13, $07, $C1, $10, $9B, $CD,
$C7, $E9, $94, $5F, $B7, $B3, $AB, $3B, $FB, $06, $0F, $F9, $D1, $39, $53, $08,
$6F, $CE, $D2, $61, $E7, $A0, $79, $55, $52, $30, $47, $B5, $04, $58, $75, $F5,
$DD, $73, $71, $67, $BE, $43, $D4, $D9, $1D, $AC, $20, $DA, $A5, $70, $6B, $BF,
$AF, $CC, $3F, $D3, $9F, $24, $DC, $28, $03, $17, $18, $1C, $22, $27, $85, $2E,
$83, $56, $C6, $A9, $2C, $5A, $62, $72, $36, $00, $69, $8E, $CB, $42, $4E, $AE,
$D7, $4B, $57, $A7, $A2, $EF, $E4, $CA, $5D, $6D, $F2, $7B, $8C, $90, $AA, $B6), (
$0C, $56, $BF, $EE, $4F, $AB, $7D, $3E, $73, $98, $A8, $85, $05, $F4, $95, $3D,
$C8, $D3, $67, $CA, $D2, $8C, $0D, $75, $47, $65, $CB, $63, $A2, $8F, $24, $C0,
$18, $5A, $3B, $FA, $16, $77, $31, $A5, $71, $34, $E4, $66, $42, $FC, $EF, $E3,
$DA, $D6, $92, $F1, $79, $EC, $C7, $4B, $99, $2D, $74, $12, $CD, $A9, $1B, $FF,
$B2, $7F, $8A, $1F, $F3, $D0, $B1, $09, $8B, $59, $22, $DB, $D5, $84, $91, $57,
$FE, $68, $C1, $C4, $6B, $87, $F0, $39, $17, $B7, $B0, $E8, $27, $1E, $9F, $2C,
$BE, $1D, $E0, $7B, $E2, $94, $69, $20, $03, $64, $02, $4D, $ED, $7E, $AF, $19,
$5D, $3C, $07, $6E, $36, $CC, $0E, $01, $51, $FD, $3F, $F5, $14, $DF, $0A, $93,
$60, $40, $CF, $26, $53, $81, $2B, $B3, $43, $A6, $C6, $B4, $DD, $52, $A4, $61,
$F6, $08, $28, $76, $7A, $46, $50, $7C, $C3, $A7, $9A, $13, $11, $4E, $04, $4A,
$4C, $33, $6A, $A1, $2E, $83, $BA, $B8, $49, $44, $6F, $E1, $29, $C5, $88, $E9,
$58, $90, $1A, $F7, $8D, $D8, $41, $15, $AC, $37, $F8, $E7, $89, $DC, $BC, $5B,
$E6, $8E, $D7, $23, $1C, $9B, $48, $38, $97, $B6, $55, $2F, $E5, $5F, $B9, $80,
$EA, $C9, $78, $6C, $30, $D1, $82, $AE, $D4, $9E, $00, $C2, $6D, $B5, $86, $DE,
$9D, $45, $54, $AA, $D9, $BD, $5C, $96, $FB, $35, $0F, $CE, $9C, $10, $72, $0B,
$70, $A3, $62, $A0, $25, $EB, $06, $21, $2A, $32, $3A, $5E, $AD, $BB, $F2, $F9), (
$9F, $7E, $36, $84, $96, $8F, $B9, $F9, $32, $71, $93, $A7, $CB, $FA, $8E, $BA,
$D3, $34, $7A, $6A, $E3, $B8, $90, $A5, $52, $A2, $48, $67, $CA, $02, $97, $E7,
$F6, $40, $7C, $BF, $9A, $CD, $DB, $27, $5B, $1B, $63, $AC, $0A, $F3, $B6, $31,
$C7, $80, $53, $4E, $ED, $C0, $CF, $19, $E1, $AA, $41, $E0, $07, $94, $57, $DD,
$9E, $EF, $1E, $25, $74, $FF, $30, $33, $EB, $D5, $FD, $06, $99, $B4, $EE, $98,
$1A, $47, $C1, $7D, $2C, $10, $51, $F0, $5D, $20, $38, $72, $EA, $43, $4D, $23,
$FE, $87, $DA, $0E, $15, $14, $BB, $01, $6C, $8A, $85, $56, $82, $05, $BE, $16,
$76, $2B, $EC, $D2, $44, $21, $61, $C8, $83, $49, $70, $F7, $F2, $AB, $37, $AF,
$9C, $60, $E8, $E5, $7B, $4F, $AE, $39, $04, $CE, $3A, $03, $D1, $54, $7F, $50,
$FB, $5E, $64, $24, $D7, $18, $86, $0D, $4B, $73, $A6, $3C, $69, $E6, $E4, $92,
$E9, $AD, $F4, $28, $6F, $91, $0B, $D8, $2D, $9B, $62, $45, $2A, $6E, $6D, $8C,
$59, $5C, $D9, $F8, $17, $66, $77, $A8, $8B, $DF, $78, $DE, $B3, $42, $79, $4C,
$A3, $89, $D0, $55, $1F, $A4, $C6, $00, $75, $A9, $09, $0C, $81, $B5, $3D, $B7,
$B2, $DC, $6B, $D6, $26, $9D, $3E, $95, $D4, $35, $3B, $E2, $65, $08, $4A, $13,
$1C, $2E, $FC, $0F, $F5, $88, $C9, $BC, $12, $F1, $22, $3F, $B1, $68, $C5, $B0,
$11, $1D, $29, $2F, $46, $58, $5A, $5F, $8D, $A0, $A1, $BD, $C3, $C4, $C2, $CC), (
$EF, $8D, $10, $2A, $79, $42, $8C, $85, $D9, $83, $24, $12, $E9, $9F, $38, $67,
$B2, $5C, $1A, $28, $36, $16, $B7, $11, $A5, $D2, $2E, $06, $1C, $FD, $E5, $41,
$4F, $F4, $20, $AF, $3F, $3B, $05, $35, $9C, $A1, $DA, $3E, $7A, $CD, $F2, $B1,
$FA, $7B, $E3, $F5, $5D, $FE, $ED, $1E, $26, $40, $F9, $BF, $46, $BE, $22, $4A,
$EE, $5F, $6E, $77, $DE, $E8, $D0, $7D, $F6, $31, $2B, $B9, $99, $F3, $9D, $93,
$A3, $A2, $7C, $68, $0A, $07, $6A, $C5, $03, $4C, $27, $C8, $3C, $0B, $4D, $56,
$54, $CF, $73, $72, $49, $A8, $B5, $BC, $F1, $C4, $53, $69, $14, $9B, $47, $C0,
$E0, $C2, $43, $13, $A6, $0C, $84, $E2, $29, $A7, $63, $D5, $2C, $74, $19, $0F,
$CE, $1F, $0D, $DF, $C1, $97, $BB, $65, $C3, $61, $01, $7F, $6F, $3D, $5B, $FC,
$87, $CA, $08, $B8, $09, $CC, $A9, $25, $86, $6D, $AE, $9A, $8A, $15, $66, $EA,
$C7, $37, $58, $BD, $DD, $DC, $60, $91, $B3, $95, $B4, $33, $EC, $D7, $A0, $64,
$2D, $98, $EB, $AD, $4B, $FB, $3A, $44, $71, $F8, $52, $A4, $9E, $E7, $89, $7E,
$39, $B0, $D3, $94, $8F, $45, $E6, $B6, $CB, $0E, $92, $18, $5E, $30, $57, $AA,
$02, $55, $D4, $48, $82, $6B, $E1, $D6, $8B, $21, $78, $75, $32, $90, $76, $70,
$6C, $DB, $C6, $88, $04, $17, $1B, $1D, $23, $2F, $34, $4E, $50, $FF, $8E, $AB,
$D8, $5A, $59, $AC, $00, $C9, $51, $BA, $F7, $D1, $62, $81, $80, $E4, $96, $F0), (
$88, $DF, $B7, $A7, $8A, $CE, $44, $6C, $4F, $4D, $FD, $92, $4A, $56, $A4, $4B,
$58, $D5, $FC, $E8, $F8, $F4, $3A, $43, $EF, $3E, $01, $AC, $36, $2E, $F2, $28,
$09, $C3, $67, $D3, $A1, $29, $DE, $50, $79, $14, $78, $97, $26, $9C, $24, $AD,
$15, $E9, $6B, $7B, $96, $87, $2D, $30, $9B, $8D, $89, $21, $4E, $20, $C8, $5A,
$6E, $71, $06, $33, $74, $E2, $9F, $85, $BD, $EB, $34, $DB, $BE, $B1, $A0, $1B,
$93, $CF, $1A, $E0, $5D, $59, $52, $46, $2C, $2B, $37, $CB, $FB, $38, $95, $9A,
$BC, $32, $AF, $8B, $DA, $11, $68, $B2, $5E, $23, $D8, $22, $7C, $91, $E4, $C2,
$41, $EE, $ED, $17, $05, $3D, $1C, $08, $83, $80, $4C, $D2, $5B, $9D, $3B, $02,
$C4, $C1, $7E, $F3, $BA, $12, $51, $72, $FE, $E5, $62, $70, $60, $EA, $35, $99,
$8C, $65, $BF, $45, $6D, $8E, $DD, $A9, $CA, $F0, $98, $53, $66, $D4, $AE, $B3,
$10, $5C, $F7, $0E, $18, $A8, $0F, $B0, $EC, $76, $AA, $A6, $F5, $3F, $D6, $F6,
$E7, $55, $82, $C9, $AB, $B6, $D0, $04, $C5, $7F, $86, $77, $07, $0C, $5F, $16,
$81, $63, $C7, $40, $31, $54, $B5, $49, $90, $FF, $27, $75, $7A, $CD, $48, $13,
$1D, $03, $D9, $D1, $E6, $0A, $84, $69, $C6, $B9, $B8, $C0, $A3, $B4, $94, $A2,
$D7, $F9, $9E, $6A, $1F, $1E, $0D, $DC, $E3, $CC, $3C, $0B, $6F, $2A, $00, $7D,
$39, $42, $BB, $19, $73, $61, $25, $2F, $47, $57, $64, $8F, $A5, $E1, $F1, $FA), (
$61, $C1, $70, $D5, $26, $07, $09, $EB, $8B, $5F, $28, $E5, $64, $91, $46, $32,
$E0, $72, $9A, $11, $C0, $45, $66, $99, $1D, $8D, $40, $62, $55, $EE, $BB, $5C,
$94, $E6, $1F, $00, $A2, $76, $1B, $34, $78, $0F, $2C, $F6, $97, $4D, $3F, $21,
$6E, $BA, $83, $8F, $B0, $9B, $9E, $2E, $F0, $C4, $FF, $71, $A4, $35, $D8, $69,
$88, $4C, $DB, $1A, $BD, $30, $C7, $47, $80, $90, $17, $A5, $50, $0A, $C3, $57,
$18, $03, $49, $37, $D4, $F8, $CE, $20, $CB, $65, $85, $02, $4A, $DA, $14, $24,
$75, $7A, $48, $A1, $CC, $98, $73, $FD, $C2, $FA, $E7, $68, $AB, $B3, $0C, $D2,
$FC, $53, $5A, $81, $2D, $63, $D3, $33, $DE, $95, $BC, $F2, $44, $4B, $B7, $5D,
$AE, $EC, $B4, $1E, $9C, $DC, $7E, $9D, $8A, $25, $B1, $A8, $22, $D9, $B8, $D0,
$82, $BF, $67, $6A, $01, $0D, $C9, $6B, $AA, $CA, $AC, $A9, $DD, $3C, $8E, $3B,
$F5, $F9, $C8, $23, $C5, $6F, $3A, $08, $51, $E4, $C6, $D6, $84, $87, $A6, $0E,
$FB, $A0, $0B, $E2, $8C, $1C, $15, $E1, $60, $B9, $10, $E8, $74, $5B, $9F, $ED,
$2B, $B2, $29, $7F, $E9, $F7, $36, $F4, $3D, $A3, $D1, $58, $38, $93, $04, $6D,
$B5, $AF, $05, $27, $31, $CF, $E3, $7B, $4F, $5E, $2F, $B6, $52, $7D, $42, $39,
$06, $12, $13, $59, $D7, $16, $CD, $3E, $4E, $BE, $92, $A7, $F3, $77, $EA, $79,
$89, $43, $AD, $86, $DF, $19, $41, $FE, $6C, $7C, $2A, $96, $54, $56, $EF, $F1), (
$99, $09, $EE, $E3, $4B, $6E, $04, $D0, $F6, $76, $8F, $EA, $A7, $2F, $EB, $D8,
$A9, $83, $96, $C8, $F7, $64, $B3, $54, $28, $9B, $B2, $9E, $41, $DF, $CD, $06,
$33, $65, $1F, $80, $4C, $E0, $0C, $B6, $39, $90, $7C, $50, $3C, $B8, $73, $91,
$92, $A2, $C5, $51, $C7, $1A, $4F, $21, $08, $A8, $36, $8B, $6A, $82, $86, $7E,
$59, $95, $D6, $B5, $FC, $37, $02, $B1, $16, $6C, $B0, $C9, $55, $B9, $DE, $F5,
$61, $98, $D4, $63, $C6, $FE, $BA, $C2, $24, $4A, $97, $5F, $67, $ED, $01, $2C,
$46, $9F, $3D, $A0, $23, $58, $62, $13, $2B, $34, $D2, $8E, $D1, $00, $70, $68,
$15, $2E, $31, $45, $A4, $EC, $81, $F4, $F3, $A3, $1C, $75, $07, $F0, $DA, $27,
$CB, $CE, $0F, $1B, $BB, $5B, $F2, $CF, $77, $D9, $18, $7B, $29, $EF, $FB, $D5,
$BE, $3F, $5E, $52, $8D, $26, $A1, $0E, $A5, $1D, $93, $43, $B7, $20, $F1, $38,
$57, $5C, $94, $A6, $79, $E9, $7D, $40, $F9, $0B, $DC, $25, $FD, $BC, $49, $BD,
$44, $AA, $6B, $12, $22, $4D, $0A, $53, $6D, $2D, $7A, $F8, $42, $C3, $4E, $7F,
$60, $E8, $19, $AF, $D7, $71, $78, $1E, $AD, $CA, $6F, $AC, $11, $0D, $8C, $C1,
$5A, $E7, $E2, $CC, $17, $30, $74, $3A, $BF, $3E, $88, $D3, $84, $66, $B4, $9A,
$87, $03, $05, $10, $14, $2A, $32, $69, $9C, $5D, $9D, $85, $E6, $AB, $48, $E1,
$FA, $3B, $72, $AE, $DD, $35, $89, $E5, $8A, $47, $C0, $56, $FF, $C4, $DB, $E4), (
$81, $13, $59, $92, $52, $E4, $BF, $02, $B7, $19, $FD, $87, $53, $2E, $F2, $80,
$CF, $12, $4F, $0A, $9B, $63, $9A, $E3, $68, $CB, $36, $EC, $C8, $2D, $34, $D3,
$31, $56, $F4, $62, $A4, $D4, $71, $ED, $DB, $B0, $B3, $8C, $5A, $D8, $2C, $8D,
$90, $B6, $91, $1C, $7D, $E7, $C5, $65, $F0, $21, $FA, $17, $57, $64, $B2, $75,
$38, $6D, $10, $16, $C9, $E5, $A2, $6A, $0B, $09, $94, $54, $C0, $BE, $42, $95,
$1A, $44, $66, $6B, $30, $73, $7C, $50, $99, $9D, $9E, $A9, $FB, $C4, $E2, $AD,
$6E, $A3, $9C, $55, $EE, $72, $84, $8A, $46, $D2, $28, $A6, $6F, $AE, $74, $F3,
$48, $BB, $35, $1F, $D7, $CC, $AC, $D1, $DD, $5D, $A7, $AA, $76, $3D, $8E, $D0,
$24, $2F, $EB, $DC, $41, $8F, $97, $0F, $3A, $DF, $B9, $DE, $D9, $BD, $7E, $47,
$5B, $14, $40, $FC, $4D, $58, $26, $C3, $29, $11, $4A, $43, $77, $EF, $33, $3B,
$A5, $3E, $88, $1E, $B5, $7F, $4E, $E0, $61, $F8, $DA, $E6, $7A, $03, $A0, $C1,
$BA, $78, $9F, $EA, $E8, $AB, $69, $07, $F9, $E9, $82, $93, $51, $D6, $F1, $FF,
$39, $89, $E1, $1D, $A1, $C7, $F7, $37, $CD, $96, $6C, $67, $D5, $B4, $BC, $60,
$B1, $70, $3F, $27, $85, $83, $7B, $C6, $20, $0C, $B8, $CE, $86, $F6, $0E, $AF,
$5F, $01, $04, $15, $23, $0D, $32, $F5, $22, $00, $18, $4B, $A8, $98, $FE, $2B,
$45, $8B, $5C, $5E, $79, $06, $25, $1B, $05, $CA, $49, $2A, $08, $3C, $C2, $4C), (
$41, $EB, $7F, $0F, $02, $6F, $C4, $47, $D9, $04, $37, $4C, $EF, $A3, $BC, $B6,
$17, $5B, $E4, $11, $1C, $18, $96, $6C, $AF, $58, $87, $50, $0A, $59, $E9, $3E,
$49, $90, $DF, $07, $F1, $D7, $CD, $AE, $82, $2A, $34, $C8, $E0, $7C, $19, $C0,
$9C, $D1, $BE, $31, $E7, $D6, $51, $AA, $EE, $F3, $28, $27, $8F, $A8, $05, $21,
$B7, $78, $E8, $33, $A6, $4D, $DE, $7D, $16, $2B, $9F, $67, $CF, $65, $3B, $BB,
$25, $C3, $6E, $72, $6A, $DD, $C2, $06, $C1, $10, $AD, $EC, $CE, $5F, $F6, $00,
$03, $EA, $29, $FF, $83, $A9, $92, $A7, $53, $71, $7E, $61, $35, $43, $5D, $B8,
$D4, $A4, $A2, $F2, $2D, $30, $DC, $1E, $5C, $88, $57, $24, $E2, $7A, $E1, $48,
$4A, $98, $38, $CA, $5E, $13, $62, $A0, $D5, $F9, $C7, $8B, $54, $80, $BA, $81,
$66, $A5, $F5, $1A, $CB, $6D, $D0, $E3, $F7, $C5, $09, $C6, $23, $20, $55, $94,
$B5, $74, $2C, $26, $1B, $01, $BF, $14, $93, $56, $42, $40, $D3, $B9, $39, $FE,
$8D, $E5, $12, $3A, $3F, $AB, $0B, $ED, $FC, $44, $85, $5A, $DB, $DA, $FB, $7B,
$B1, $63, $9D, $0C, $B3, $8E, $46, $45, $F8, $68, $BD, $77, $FA, $9B, $69, $75,
$76, $36, $99, $79, $FD, $91, $70, $3D, $08, $22, $95, $B0, $F4, $B4, $0E, $64,
$89, $F0, $C9, $2F, $97, $52, $86, $D8, $CC, $4E, $60, $8A, $8C, $4F, $B2, $4B,
$84, $2E, $AC, $A1, $32, $E6, $0D, $9A, $3C, $1D, $15, $1F, $6B, $73, $9E, $D2), (
$BE, $B5, $90, $5C, $C9, $3A, $23, $DF, $78, $00, $F1, $E7, $B8, $ED, $FB, $B3,
$1F, $F6, $6C, $12, $88, $32, $E8, $1C, $C8, $07, $5A, $C2, $25, $65, $B7, $CE,
$47, $CD, $70, $4B, $FC, $53, $DB, $93, $EF, $AB, $6A, $92, $39, $02, $56, $81,
$5E, $51, $1D, $30, $35, $7C, $5F, $A9, $BF, $29, $0A, $76, $DA, $DC, $67, $46,
$96, $19, $10, $0C, $9F, $C1, $43, $3F, $57, $74, $F3, $44, $79, $F7, $BA, $E4,
$6D, $F9, $4A, $34, $8D, $D5, $D8, $2A, $63, $05, $0B, $0E, $2D, $CC, $01, $18,
$D4, $EA, $E9, $31, $94, $15, $AA, $F8, $E1, $C3, $E6, $59, $91, $69, $48, $6E,
$20, $4D, $55, $45, $8A, $11, $66, $16, $F5, $1E, $03, $B1, $21, $9A, $38, $8B,
$D6, $CB, $F2, $D2, $B4, $4E, $3E, $D3, $2E, $EE, $24, $FE, $C5, $77, $33, $E2,
$54, $2C, $C6, $41, $BD, $17, $A0, $13, $D0, $40, $F0, $50, $A3, $EC, $CF, $FF,
$99, $DD, $D1, $09, $61, $AD, $1A, $AF, $89, $CA, $EB, $A5, $84, $8E, $3C, $3B,
$A4, $B0, $82, $8F, $83, $A1, $1B, $E5, $9C, $C0, $7A, $95, $3D, $52, $26, $9B,
$C4, $42, $7F, $F4, $9E, $08, $AC, $72, $D9, $0D, $AE, $FD, $FA, $49, $A7, $D7,
$B6, $62, $36, $68, $4F, $0F, $C7, $2F, $22, $BB, $9D, $04, $BC, $B2, $A8, $27,
$E3, $14, $A6, $7B, $06, $64, $28, $6B, $80, $A2, $97, $87, $73, $7D, $75, $8C,
$60, $85, $7E, $5D, $5B, $58, $37, $2B, $E0, $6F, $4C, $71, $86, $98, $B9, $DE));
//SUBSTITUTION BOXES' INVERSE FOR EACH ROUND
S1: array[0..15, 0..255] of longword = ((
$89, $72, $9C, $D4, $4A, $46, $3D, $1A, $6B, $B2, $2E, $5A, $52, $04, $C6, $4D,
$2A, $6A, $7D, $E0, $B7, $BB, $5F, $10, $B4, $B0, $15, $18, $3C, $47, $8E, $D5,
$3E, $07, $B6, $17, $20, $E6, $8C, $9F, $99, $73, $64, $E9, $84, $F9, $44, $D3,
$AE, $C7, $12, $39, $FA, $E2, $30, $F4, $27, $62, $66, $1C, $2F, $EF, $83, $4B,
$F8, $DD, $E3, $65, $60, $0E, $3F, $29, $68, $38, $D2, $FB, $6C, $CA, $74, $82,
$21, $BF, $79, $C2, $87, $C9, $7A, $F2, $E8, $25, $DE, $36, $4F, $77, $5D, $51,
$A7, $AF, $AD, $76, $16, $A5, $EC, $F5, $00, $D6, $C1, $9A, $8A, $4C, $1D, $EA,
$A8, $53, $D8, $23, $E1, $34, $C8, $94, $A6, $B5, $F6, $A4, $03, $DF, $69, $81,
$C0, $7E, $A9, $90, $0A, $95, $48, $55, $40, $C3, $8B, $6F, $DB, $1F, $35, $57,
$E5, $7F, $BE, $2C, $CC, $70, $9D, $09, $AB, $ED, $32, $37, $CB, $01, $59, $91,
$CE, $1B, $0B, $56, $3B, $FC, $E4, $14, $02, $78, $31, $5B, $58, $45, $DA, $5E,
$9E, $33, $B1, $96, $BA, $88, $75, $26, $19, $AA, $AC, $7C, $08, $0F, $F7, $9B,
$71, $06, $EB, $FD, $24, $7B, $F0, $E7, $3A, $F1, $8F, $6D, $43, $D0, $F3, $98,
$D7, $B9, $4E, $28, $C4, $13, $A3, $92, $11, $B8, $FE, $50, $A2, $2D, $0C, $1E,
$C5, $05, $DC, $54, $CD, $BC, $61, $2B, $EE, $B3, $5C, $86, $93, $6E, $0D, $49,
$D9, $85, $97, $D1, $22, $BD, $A1, $80, $A0, $67, $41, $63, $42, $FF, $CF, $8D), (
$EB, $C4, $80, $69, $AE, $2C, $2E, $1C, $7F, $DA, $06, $7A, $1E, $A5, $AF, $DE,
$47, $39, $21, $E0, $E1, $10, $9C, $17, $26, $3B, $04, $14, $4C, $86, $CF, $23,
$6A, $8B, $AD, $93, $66, $C1, $E2, $1F, $5E, $E3, $18, $60, $AB, $C5, $73, $BA,
$E4, $CC, $62, $DB, $3A, $AC, $CE, $4D, $E5, $B8, $74, $09, $CB, $3C, $3F, $A3,
$75, $30, $A9, $B4, $A7, $0E, $4E, $40, $F6, $B9, $95, $48, $11, $EF, $67, $82,
$D9, $B1, $9F, $53, $0D, $F4, $2A, $19, $D2, $6C, $CD, $94, $2D, $F1, $92, $C8,
$33, $99, $E6, $98, $E9, $96, $02, $C0, $2F, $BB, $6F, $0B, $5A, $9A, $36, $31,
$8E, $BF, $E8, $0C, $F5, $0F, $C6, $64, $00, $C7, $F9, $27, $A1, $88, $BC, $4B,
$91, $6B, $1B, $8D, $58, $5B, $76, $CA, $20, $71, $C3, $C2, $57, $01, $EE, $24,
$7D, $F8, $85, $FD, $32, $9B, $A0, $87, $D1, $8A, $5C, $8C, $05, $68, $0A, $D0,
$AA, $D8, $B2, $16, $DC, $22, $51, $70, $97, $D4, $F0, $4A, $8F, $D7, $72, $B5,
$81, $13, $41, $83, $A6, $12, $44, $FA, $DF, $B6, $FE, $D5, $FB, $A4, $FF, $BE,
$84, $90, $9E, $35, $6E, $1D, $34, $59, $ED, $F3, $D3, $DD, $F2, $03, $55, $45,
$7E, $79, $25, $28, $B0, $5D, $38, $50, $08, $29, $F7, $42, $5F, $D6, $6D, $EA,
$15, $3E, $37, $C9, $78, $3D, $89, $7C, $7B, $52, $56, $63, $B3, $A8, $4F, $B7,
$1A, $9D, $65, $BD, $43, $46, $FC, $EC, $77, $2B, $49, $07, $E7, $54, $A2, $61), (
$83, $58, $4D, $CE, $3E, $0D, $AB, $CB, $BD, $A2, $24, $97, $EA, $D6, $20, $85,
$55, $A6, $EB, $9D, $45, $71, $48, $86, $7D, $B9, $12, $38, $60, $14, $B3, $90,
$03, $95, $6D, $C6, $E7, $7A, $B8, $2F, $23, $AA, $EC, $65, $B2, $68, $8B, $54,
$15, $96, $4F, $AF, $ED, $D4, $53, $DF, $D7, $80, $2A, $9E, $C8, $18, $93, $BE,
$8F, $69, $74, $3C, $EE, $87, $3F, $D3, $EF, $1A, $E3, $17, $52, $1B, $02, $49,
$C4, $70, $9F, $30, $31, $0F, $F0, $F1, $8A, $F2, $DE, $4C, $1C, $9B, $13, $89,
$C5, $A1, $B0, $28, $46, $C9, $E6, $42, $E4, $D5, $4B, $67, $E1, $19, $75, $5F,
$76, $78, $9A, $F3, $00, $A5, $9C, $1E, $6C, $3B, $06, $8D, $2E, $29, $E8, $5C,
$0A, $B4, $E5, $27, $BA, $7E, $7B, $34, $B5, $E9, $7C, $01, $F4, $59, $F8, $C0,
$B6, $6F, $62, $5D, $A7, $D1, $A4, $64, $7F, $3A, $5E, $98, $92, $DC, $FD, $1D,
$91, $3D, $B7, $61, $51, $22, $56, $0C, $CD, $37, $0E, $C1, $04, $32, $4A, $66,
$63, $C2, $40, $21, $41, $B1, $F5, $FE, $E0, $8E, $47, $FF, $73, $C3, $0B, $50,
$79, $6E, $FB, $88, $2D, $8C, $10, $E2, $A0, $DB, $D2, $77, $AC, $43, $AE, $A8,
$A9, $1F, $A3, $33, $DA, $84, $09, $F7, $BC, $FC, $16, $D8, $D0, $4E, $11, $AD,
$26, $2C, $08, $BB, $D9, $82, $F6, $2B, $05, $CF, $99, $6B, $CA, $5A, $F9, $07,
$DD, $72, $94, $BF, $81, $44, $25, $FA, $39, $35, $57, $6A, $C7, $CC, $36, $5B), (
$50, $92, $39, $3E, $D4, $E4, $F1, $0C, $C1, $4B, $F2, $F3, $22, $75, $2E, $5A,
$E0, $7E, $DE, $C5, $8A, $4F, $16, $BC, $A9, $13, $61, $E2, $76, $93, $F4, $C4,
$F5, $DF, $83, $3A, $9B, $1F, $B5, $B4, $68, $36, $B6, $62, $F6, $B2, $0A, $C0,
$A1, $7C, $60, $8D, $0B, $F7, $10, $1A, $CA, $D6, $56, $AF, $20, $28, $05, $21,
$CC, $AD, $8E, $BE, $71, $5F, $BF, $87, $1C, $E7, $A7, $F8, $35, $2F, $06, $0D,
$11, $84, $2B, $AB, $4E, $DC, $F9, $14, $FA, $DD, $AC, $6F, $EE, $3B, $2D, $6C,
$A5, $72, $1D, $73, $18, $9C, $29, $5B, $08, $31, $9F, $42, $C7, $FB, $63, $55,
$FC, $53, $BD, $12, $88, $4C, $4D, $D8, $D3, $EB, $74, $54, $38, $7D, $FD, $9D,
$7F, $A0, $6B, $45, $D5, $66, $E1, $B3, $C6, $C8, $7A, $98, $A8, $32, $C9, $52,
$95, $C2, $91, $04, $2C, $FE, $ED, $3F, $7B, $07, $01, $A2, $94, $B7, $3C, $49,
$24, $37, $CB, $89, $B8, $E5, $79, $80, $82, $1E, $FF, $0F, $3D, $33, $CE, $47,
$6E, $64, $2A, $A6, $AE, $40, $AA, $A3, $5C, $99, $43, $69, $BB, $97, $65, $DA,
$27, $58, $6A, $23, $CD, $02, $46, $67, $5D, $E3, $1B, $E9, $09, $EF, $57, $BA,
$B0, $0E, $9E, $26, $B9, $70, $41, $19, $90, $F0, $51, $EC, $44, $8F, $00, $25,
$C3, $EA, $85, $77, $A4, $D7, $8C, $D1, $D9, $9A, $96, $81, $D2, $5E, $E8, $34,
$30, $59, $4A, $B1, $86, $15, $48, $78, $17, $DB, $CF, $03, $E6, $6D, $D0, $8B), (
$A3, $78, $01, $13, $5E, $CE, $DF, $50, $46, $DA, $61, $97, $B4, $4E, $CD, $0E,
$9B, $86, $30, $4D, $34, $AB, $42, $11, $D2, $76, $8E, $72, $07, $66, $7F, $7D,
$A4, $39, $C3, $C5, $77, $B1, $8A, $0D, $AE, $03, $22, $93, $65, $E0, $2D, $83,
$AC, $36, $2A, $D3, $25, $26, $5C, $BE, $53, $92, $85, $4B, $19, $2F, $17, $E5,
$C9, $0F, $68, $8B, $E6, $E7, $E8, $73, $3C, $6B, $33, $9A, $E9, $C6, $EA, $55,
$2C, $79, $DE, $7A, $10, $B2, $A7, $89, $EB, $B8, $FA, $45, $D0, $38, $1C, $B3,
$56, $43, $84, $3D, $06, $1A, $57, $7E, $A6, $0A, $82, $1F, $FD, $29, $FE, $AA,
$8F, $80, $15, $27, $75, $62, $FF, $08, $09, $6F, $2B, $91, $AD, $1B, $E1, $E4,
$EE, $59, $BB, $67, $EF, $02, $DB, $40, $EC, $F7, $2E, $3E, $3B, $F5, $DC, $35,
$F1, $B9, $3F, $4A, $4C, $B0, $52, $CF, $F8, $D1, $8C, $BD, $6E, $F2, $4F, $F3,
$12, $70, $B7, $BF, $64, $47, $32, $04, $C4, $96, $A9, $94, $A0, $A5, $00, $87,
$24, $88, $5B, $58, $D6, $6D, $D8, $C7, $F6, $99, $28, $14, $41, $6A, $54, $63,
$B6, $69, $C2, $CA, $60, $BA, $18, $90, $E3, $6C, $3A, $8D, $98, $A1, $51, $BC,
$81, $D9, $9F, $A8, $74, $CC, $D4, $0C, $71, $B5, $49, $FB, $D7, $1D, $9C, $ED,
$FC, $20, $37, $44, $9D, $AF, $31, $48, $16, $21, $7B, $E2, $23, $7C, $A2, $F9,
$5A, $D5, $95, $DD, $0B, $C1, $F4, $1E, $F0, $C0, $C8, $05, $9E, $5F, $5D, $CB), (
$3D, $DE, $98, $75, $44, $B3, $A2, $E5, $CD, $A4, $E6, $E7, $4E, $D6, $2F, $68,
$6E, $78, $61, $4D, $87, $33, $99, $E8, $29, $E9, $6F, $C0, $12, $83, $BB, $0A,
$2B, $B4, $B7, $8C, $BE, $E1, $73, $86, $D0, $28, $9C, $2D, $14, $EA, $C1, $5F,
$8B, $80, $21, $B0, $1D, $A0, $EB, $60, $93, $B8, $B1, $E3, $1C, $A3, $A5, $95,
$18, $D4, $7D, $1E, $6B, $2E, $56, $AE, $19, $89, $20, $91, $7C, $F9, $EE, $3A,
$81, $5C, $8D, $6A, $C8, $31, $53, $CE, $A1, $E2, $C2, $23, $08, $F1, $00, $CA,
$4F, $4C, $DD, $01, $F5, $7A, $B5, $63, $F3, $BA, $05, $C6, $F7, $D1, $97, $50,
$B9, $24, $2C, $02, $9A, $BD, $DA, $FC, $10, $BF, $70, $D8, $8F, $3B, $90, $6C,
$48, $74, $62, $32, $82, $3F, $7E, $B6, $45, $1A, $FB, $57, $59, $38, $06, $AA,
$FD, $0F, $72, $A7, $AC, $16, $9D, $0D, $F8, $4A, $A9, $71, $22, $51, $8E, $F2,
$EC, $03, $C3, $DF, $B2, $37, $66, $35, $C7, $DB, $54, $69, $F4, $52, $47, $25,
$17, $0C, $84, $67, $41, $40, $85, $EF, $46, $FF, $92, $4B, $94, $7B, $D5, $1F,
$2A, $07, $42, $3C, $49, $77, $C4, $C5, $30, $F0, $64, $9B, $DC, $AF, $1B, $88,
$FA, $8A, $27, $3E, $AB, $15, $C9, $0B, $09, $43, $79, $36, $D2, $76, $D9, $65,
$7F, $9E, $A6, $9F, $5D, $34, $5E, $39, $A8, $6D, $CC, $11, $E0, $ED, $96, $D3,
$FE, $55, $58, $F6, $AD, $5A, $CB, $5B, $E4, $BC, $13, $0E, $D7, $26, $04, $CF), (
$E9, $31, $71, $D8, $BC, $88, $A9, $9B, $AF, $80, $37, $53, $97, $61, $86, $AA,
$9D, $33, $60, $9A, $93, $2C, $5D, $D9, $DA, $66, $67, $0B, $DB, $C8, $3F, $5A,
$CA, $94, $DC, $3B, $D5, $21, $62, $DD, $D7, $41, $22, $28, $E4, $3D, $DF, $56,
$B9, $0F, $2A, $50, $4A, $44, $E8, $38, $54, $AD, $6D, $A7, $02, $30, $12, $D2,
$1F, $7F, $ED, $C5, $29, $69, $0E, $BA, $7D, $95, $4C, $F1, $45, $00, $EE, $24,
$7C, $8B, $B8, $AE, $68, $B7, $E1, $F2, $BD, $85, $E5, $35, $5E, $F8, $2E, $A3,
$10, $B3, $E6, $46, $1C, $6E, $99, $C3, $1D, $EA, $83, $CE, $64, $F9, $76, $B0,
$CD, $C2, $E7, $C1, $73, $BE, $0C, $70, $8A, $B6, $3C, $FB, $79, $18, $96, $39,
$58, $81, $63, $E0, $8E, $DE, $6F, $8D, $26, $4D, $47, $20, $FC, $7B, $EB, $36,
$FD, $5C, $49, $48, $A2, $82, $04, $74, $13, $1A, $5F, $9E, $51, $06, $09, $D4,
$B5, $6C, $F4, $08, $32, $CC, $40, $F3, $8C, $E3, $FE, $A6, $C9, $57, $EF, $D0,
$7A, $72, $01, $A5, $4B, $BB, $FF, $A4, $19, $05, $34, $1E, $75, $5B, $C4, $CF,
$89, $9C, $92, $07, $4E, $2D, $E2, $A0, $11, $90, $F7, $EC, $D1, $9F, $B1, $77,
$15, $AC, $B2, $D3, $C6, $84, $8F, $F0, $6B, $C7, $CB, $27, $D6, $C0, $23, $65,
$3A, $59, $16, $87, $F6, $25, $03, $B4, $91, $A1, $55, $2B, $98, $0D, $3E, $F5,
$43, $2F, $FA, $6A, $78, $BF, $4F, $42, $17, $AB, $52, $A8, $7E, $1B, $0A, $14), (
$DA, $77, $6A, $68, $9E, $0C, $F6, $72, $91, $47, $7E, $EF, $00, $16, $76, $EA,
$ED, $9C, $3B, $9B, $7C, $B7, $24, $58, $20, $6F, $B2, $3E, $C4, $61, $5D, $43,
$67, $F7, $4A, $C3, $1E, $F4, $83, $5C, $92, $AC, $F8, $86, $5F, $39, $A4, $CB,
$D4, $26, $F9, $A1, $29, $E9, $74, $B9, $C7, $57, $FA, $22, $71, $0F, $07, $7A,
$81, $B6, $2C, $88, $A9, $E1, $95, $18, $C6, $A8, $9F, $37, $A0, $6B, $9D, $04,
$96, $78, $8D, $84, $E2, $CA, $01, $4F, $B0, $49, $21, $BF, $E6, $70, $FB, $CD,
$80, $8F, $F2, $1B, $69, $19, $2B, $12, $51, $66, $A2, $54, $D3, $DC, $73, $AA,
$F0, $28, $EE, $08, $3A, $17, $93, $25, $D2, $34, $94, $63, $97, $06, $6D, $41,
$CF, $85, $D6, $A5, $4D, $0B, $DE, $55, $AE, $BC, $42, $48, $15, $B4, $C1, $1D,
$B1, $4E, $32, $7F, $65, $0E, $E7, $C8, $09, $38, $9A, $C5, $EC, $E0, $D9, $5E,
$F3, $A3, $1C, $F1, $8E, $27, $89, $99, $0A, $3D, $E3, $05, $B8, $FC, $D7, $6E,
$5A, $46, $40, $87, $8B, $DD, $C9, $59, $A7, $CE, $A6, $FD, $BE, $E5, $60, $02,
$1F, $52, $DB, $98, $53, $AD, $8A, $36, $10, $D1, $13, $1A, $75, $3C, $EB, $82,
$45, $D5, $14, $11, $D8, $4C, $31, $C2, $B5, $E4, $30, $4B, $BD, $8C, $DF, $7D,
$62, $AB, $64, $2F, $2A, $CC, $C0, $BB, $5B, $AF, $D0, $F5, $35, $6C, $03, $2E,
$56, $33, $FE, $44, $0D, $7B, $90, $B3, $BA, $FF, $23, $E8, $2D, $79, $50, $3F), (
$C7, $67, $1D, $8B, $88, $6D, $4B, $3C, $DD, $CA, $2C, $A6, $CB, $97, $63, $E3,
$55, $F0, $E8, $DF, $65, $64, $6F, $B4, $95, $37, $50, $29, $E0, $F1, $42, $C4,
$59, $75, $EA, $5F, $93, $43, $D4, $27, $A3, $F2, $AC, $71, $54, $A8, $E1, $F3,
$46, $2F, $08, $47, $11, $D9, $02, $7E, $5A, $87, $8A, $DA, $9B, $CE, $D6, $EB,
$21, $3A, $BD, $5D, $74, $AB, $F4, $51, $1A, $79, $DE, $98, $BF, $5E, $33, $85,
$8F, $56, $18, $32, $8D, $C3, $6B, $3E, $F5, $B0, $F6, $28, $B1, $58, $91, $F7,
$81, $76, $AA, $2A, $92, $DC, $B5, $1B, $ED, $9C, $13, $D2, $68, $AE, $AD, $A4,
$7A, $09, $5B, $99, $44, $C8, $70, $B6, $BA, $BE, $12, $84, $22, $53, $01, $8E,
$31, $CC, $6C, $78, $03, $6A, $96, $61, $E5, $C1, $69, $B8, $AF, $F8, $0E, $05,
$16, $A5, $9F, $0A, $3D, $D7, $04, $1E, $4F, $4C, $24, $A9, $80, $D5, $40, $00,
$F9, $FA, $19, $C0, $C5, $17, $9A, $0B, $B7, $C9, $39, $7D, $2B, $A1, $86, $7F,
$EF, $EC, $D0, $BC, $4D, $CD, $2E, $CF, $15, $06, $0F, $66, $E7, $FB, $6E, $23,
$35, $52, $FE, $FC, $FD, $EE, $C6, $30, $77, $E6, $1C, $0C, $FF, $25, $89, $36,
$C2, $8C, $73, $10, $D8, $49, $D3, $94, $A7, $B2, $62, $26, $D1, $3F, $BB, $B9,
$3B, $38, $DB, $14, $9E, $83, $9D, $1F, $82, $A0, $5C, $48, $72, $34, $4E, $41,
$57, $E9, $7C, $2D, $A2, $E4, $20, $7B, $B3, $07, $0D, $90, $E2, $4A, $60, $45), (
$F4, $8A, $D0, $58, $E4, $26, $1B, $55, $92, $94, $54, $5D, $75, $82, $C9, $7F,
$02, $17, $0B, $73, $6C, $9D, $15, $E5, $CB, $7E, $12, $E6, $1C, $E7, $37, $81,
$22, $D9, $3E, $E8, $0A, $97, $38, $5A, $13, $78, $03, $4A, $7C, $B0, $1A, $E9,
$CD, $49, $DC, $AB, $EA, $27, $14, $A1, $0E, $C0, $B6, $25, $5C, $8D, $2B, $24,
$39, $1F, $05, $72, $B7, $C5, $3C, $6E, $D3, $64, $3F, $B4, $59, $5E, $EB, $20,
$EC, $F6, $BA, $6A, $60, $D1, $5F, $CE, $A2, $F2, $F1, $8E, $11, $34, $CC, $41,
$A6, $89, $FA, $7A, $AF, $87, $9E, $0F, $53, $6B, $56, $D5, $E0, $99, $42, $8C,
$DF, $B8, $63, $62, $7D, $DB, $DE, $43, $DA, $04, $2C, $31, $52, $47, $BF, $8B,
$FC, $FB, $D4, $09, $76, $07, $98, $90, $E3, $BE, $9C, $D8, $06, $01, $EE, $C4,
$DD, $A7, $CA, $4F, $C3, $A9, $FE, $85, $B1, $4C, $9B, $6D, $28, $4E, $BC, $0D,
$AE, $29, $51, $50, $BB, $18, $74, $79, $65, $96, $CF, $EF, $F3, $B3, $9A, $23,
$C1, $2F, $10, $A8, $AA, $66, $C7, $16, $93, $4B, $F7, $86, $67, $A3, $3D, $3B,
$6F, $84, $71, $88, $69, $57, $E2, $A0, $5B, $F5, $91, $C8, $95, $2D, $80, $61,
$46, $F9, $19, $C2, $D2, $7B, $D7, $AD, $F0, $08, $2A, $E1, $A5, $A4, $44, $83,
$70, $D6, $77, $32, $FD, $1E, $C6, $BD, $45, $0C, $9F, $B2, $AC, $36, $40, $00,
$FF, $68, $2E, $4D, $21, $33, $48, $F8, $B9, $3A, $30, $B5, $8F, $1D, $35, $ED), (
$EE, $1A, $7F, $D1, $B7, $74, $42, $BC, $77, $20, $D5, $EB, $BD, $E6, $A3, $A6,
$A0, $65, $85, $CF, $29, $30, $BF, $73, $A4, $F3, $52, $4F, $76, $D0, $E5, $E4,
$3D, $3B, $6B, $69, $2E, $F6, $2C, $CA, $1F, $25, $ED, $59, $58, $36, $1D, $F7,
$37, $C4, $61, $43, $4A, $8E, $1C, $5A, $5D, $F0, $16, $7E, $EA, $75, $19, $AD,
$C3, $70, $F1, $17, $06, $93, $57, $F8, $CE, $C7, $0C, $0F, $7A, $09, $3C, $08,
$27, $86, $56, $9B, $C5, $B1, $0D, $F9, $10, $55, $3F, $7C, $A1, $54, $68, $BE,
$8C, $F5, $8A, $C1, $FA, $91, $9C, $22, $66, $D7, $E3, $32, $07, $94, $40, $EC,
$8B, $41, $87, $F4, $44, $CB, $A9, $BB, $2A, $28, $CC, $33, $6C, $EF, $82, $B9,
$79, $C0, $B2, $78, $D6, $47, $BA, $35, $00, $3A, $04, $63, $90, $39, $95, $FB,
$C8, $6D, $0B, $50, $DE, $5E, $34, $2B, $9A, $8F, $5F, $38, $2D, $7D, $E2, $46,
$4E, $24, $DF, $DC, $0E, $FC, $AB, $03, $A5, $97, $AA, $B4, $1B, $2F, $9E, $62,
$A7, $4D, $67, $9F, $DD, $C6, $B5, $02, $DA, $D9, $84, $F2, $60, $48, $4C, $92,
$DB, $81, $6F, $21, $80, $B8, $D8, $C2, $3E, $B3, $98, $5B, $E9, $CD, $05, $51,
$B6, $D3, $7B, $23, $9D, $11, $AE, $E0, $6A, $D2, $64, $4B, $E7, $96, $26, $01,
$53, $FD, $45, $E8, $6E, $89, $D4, $B0, $13, $31, $8D, $49, $A8, $72, $71, $18,
$99, $FE, $1E, $83, $15, $AC, $AF, $A2, $14, $E1, $FF, $5C, $12, $0A, $88, $C9), (
$23, $94, $5B, $51, $CE, $D2, $E0, $05, $A7, $06, $4D, $B2, $6E, $95, $AF, $29,
$BA, $13, $E1, $E2, $5E, $B6, $E5, $4A, $50, $F5, $43, $26, $B5, $18, $83, $22,
$57, $2F, $8C, $A3, $5F, $89, $04, $D3, $0A, $C2, $FA, $C0, $2A, $74, $37, $DA,
$45, $D4, $0F, $77, $27, $3D, $C6, $53, $CC, $DF, $A6, $9F, $9D, $C8, $E7, $2E,
$1A, $F6, $DE, $F1, $7C, $15, $0E, $47, $62, $52, $5C, $7D, $41, $2D, $E8, $D8,
$4C, $A8, $DC, $71, $FC, $1C, $FD, $4F, $CB, $E3, $72, $BD, $1F, $7F, $D9, $09,
$B8, $00, $1B, $75, $0C, $59, $16, $92, $6B, $3F, $93, $97, $F8, $CF, $30, $A5,
$02, $3B, $11, $66, $BC, $60, $25, $ED, $28, $EF, $61, $D7, $F9, $DD, $86, $C3,
$48, $73, $90, $32, $AC, $5A, $F3, $AD, $40, $F0, $88, $08, $B4, $19, $9E, $33,
$49, $0D, $EA, $CD, $20, $79, $FB, $2C, $65, $17, $12, $35, $84, $87, $36, $BE,
$B1, $63, $24, $C9, $3C, $4B, $AE, $EB, $8B, $9B, $98, $6C, $9A, $F2, $80, $D1,
$34, $8A, $C1, $6D, $82, $D0, $DB, $7E, $8E, $B9, $31, $1E, $7A, $44, $E9, $91,
$14, $01, $68, $4E, $39, $A4, $AA, $46, $A2, $96, $99, $58, $64, $E6, $56, $D5,
$8F, $CA, $6F, $76, $54, $03, $AB, $E4, $3E, $8D, $5D, $42, $85, $9C, $78, $F4,
$10, $B7, $B3, $D6, $A9, $0B, $21, $6A, $BB, $C4, $EE, $07, $81, $BF, $1D, $FE,
$38, $FF, $7B, $EC, $C7, $A0, $2B, $C5, $55, $A1, $69, $B0, $70, $67, $F7, $3A), (
$6D, $5E, $46, $E1, $06, $E2, $1F, $7C, $38, $01, $B6, $A9, $26, $CD, $97, $82,
$E3, $CC, $B3, $67, $E4, $70, $48, $D4, $8A, $C2, $35, $83, $7A, $99, $C7, $22,
$9D, $37, $B4, $64, $58, $AB, $95, $7F, $18, $8C, $E5, $68, $5F, $B9, $71, $0D,
$D5, $72, $E6, $20, $69, $F5, $3A, $45, $9F, $28, $D7, $F1, $2C, $62, $D9, $91,
$A7, $1C, $BC, $9B, $B0, $73, $60, $F9, $EE, $AE, $59, $04, $24, $B5, $BE, $36,
$2B, $33, $93, $B7, $17, $4C, $FB, $A0, $65, $40, $D0, $85, $A1, $E9, $92, $5B,
$C0, $50, $66, $53, $15, $21, $DD, $5C, $6F, $E7, $3C, $B2, $49, $B8, $05, $CA,
$6E, $C5, $F2, $2E, $D6, $7B, $09, $88, $C6, $A4, $BA, $8B, $2A, $A6, $3F, $BF,
$23, $76, $3D, $11, $DC, $EB, $3E, $E0, $DA, $F6, $F8, $3B, $CE, $94, $6B, $0A,
$29, $2F, $30, $9A, $A2, $41, $12, $5A, $51, $00, $DF, $19, $E8, $EA, $1B, $61,
$63, $96, $31, $79, $74, $98, $A3, $0C, $39, $10, $B1, $ED, $CB, $C8, $F3, $C3,
$4A, $47, $1A, $16, $DE, $43, $27, $9C, $2D, $4D, $56, $84, $AD, $AF, $90, $D8,
$FA, $CF, $57, $BD, $FD, $32, $54, $34, $13, $4B, $C9, $80, $D3, $1E, $81, $87,
$07, $6C, $6A, $DB, $52, $8F, $42, $C4, $0F, $89, $7E, $FE, $AA, $F4, $4E, $1D,
$25, $EF, $D2, $03, $FF, $F7, $EC, $D1, $C1, $A5, $0B, $0E, $75, $5D, $02, $8D,
$7D, $9E, $86, $78, $77, $4F, $08, $14, $BB, $A8, $F0, $8E, $44, $AC, $55, $FC), (
$E9, $E1, $07, $AD, $E2, $F8, $F5, $B7, $FC, $49, $13, $48, $D9, $E5, $DE, $87,
$42, $99, $11, $01, $91, $E3, $43, $3B, $EA, $09, $50, $F7, $33, $C3, $A3, $73,
$D8, $39, $E8, $E4, $80, $F6, $96, $D3, $6A, $98, $FB, $EF, $2E, $1D, $0D, $81,
$54, $20, $E6, $9E, $1E, $72, $1A, $C7, $40, $C0, $88, $9F, $FD, $7D, $A1, $D2,
$92, $84, $4E, $9B, $51, $F0, $68, $8F, $70, $FA, $9A, $EB, $FF, $94, $A6, $12,
$57, $BC, $04, $0C, $4B, $63, $21, $3C, $95, $02, $2C, $90, $F2, $79, $F3, $E0,
$CF, $A8, $23, $15, $3D, $37, $52, $CB, $18, $B6, $47, $53, $CA, $41, $60, $6C,
$D1, $26, $65, $55, $6E, $3F, $7C, $9C, $B1, $F4, $AC, $D6, $56, $34, $8E, $A5,
$0F, $00, $BA, $D5, $66, $D4, $DC, $0B, $A2, $C1, $67, $F1, $2B, $2F, $7E, $85,
$30, $32, $03, $BB, $4A, $4F, $C9, $86, $ED, $58, $16, $14, $62, $59, $5A, $B2,
$AE, $C4, $46, $61, $24, $A0, $6B, $7A, $EC, $5B, $7B, $B5, $76, $5F, $6D, $DF,
$29, $D0, $3E, $2A, $CD, $A4, $31, $08, $DA, $8A, $B0, $71, $CE, $8D, $4D, $06,
$4C, $AF, $FE, $97, $5D, $36, $D7, $C5, $1C, $44, $F9, $19, $75, $C8, $DB, $10,
$7F, $77, $69, $1F, $25, $CC, $BD, $74, $2D, $8C, $AA, $28, $83, $78, $8B, $89,
$A7, $C2, $5E, $17, $05, $45, $AB, $35, $B4, $B9, $B3, $82, $1B, $27, $64, $9D,
$38, $BE, $0E, $6F, $22, $E7, $DD, $C6, $A9, $B8, $3A, $5C, $93, $0A, $EE, $BF), (
$5F, $A5, $04, $60, $09, $3E, $57, $23, $D8, $9A, $1C, $B6, $C3, $F6, $DE, $03,
$59, $13, $B2, $85, $A7, $FA, $48, $10, $15, $2E, $93, $A4, $14, $F9, $77, $FB,
$9D, $3F, $D9, $9C, $7B, $50, $A3, $3B, $3A, $62, $29, $49, $A2, $74, $F1, $E3,
$75, $33, $F4, $43, $2A, $6C, $D1, $0A, $82, $AE, $B3, $4E, $F8, $D7, $1F, $B4,
$AB, $00, $AA, $6D, $B9, $C7, $C6, $07, $7F, $20, $80, $EF, $0B, $45, $E9, $ED,
$1B, $36, $E5, $68, $8C, $9E, $A9, $7A, $19, $1D, $BB, $11, $78, $6E, $84, $5D,
$EA, $6B, $86, $C1, $DF, $4D, $90, $4B, $C9, $CE, $54, $FC, $17, $95, $52, $05,
$D6, $69, $53, $FD, $A1, $CF, $D0, $CB, $41, $D3, $7D, $BF, $2D, $47, $6A, $02,
$8D, $8F, $28, $64, $F0, $BA, $E6, $1A, $79, $E0, $EB, $8B, $EC, $B0, $C5, $3C,
$21, $D5, $66, $A8, $9F, $DA, $16, $E4, $81, $D2, $F7, $CD, $30, $C2, $FE, $4A,
$87, $F3, $72, $0D, $71, $91, $44, $67, $3D, $65, $37, $B5, $F2, $5A, $27, $18,
$DB, $C0, $EE, $C4, $DD, $A0, $0F, $40, $6F, $AD, $8E, $4F, $0E, $CA, $32, $A6,
$2F, $58, $56, $51, $06, $99, $9B, $8A, $2B, $E2, $83, $94, $E8, $26, $5C, $4C,
$96, $31, $FF, $AC, $70, $88, $35, $25, $E7, $08, $BD, $BC, $76, $55, $46, $22,
$2C, $7E, $7C, $97, $12, $B1, $F5, $34, $42, $1E, $61, $01, $5B, $B7, $38, $0C,
$E1, $24, $73, $39, $DC, $92, $5E, $98, $C8, $89, $CC, $BE, $B8, $D4, $AF, $63), (
$09, $5E, $2D, $7A, $DB, $59, $E4, $19, $C5, $A3, $3A, $5A, $43, $C9, $5B, $D5,
$42, $75, $13, $97, $E1, $65, $77, $95, $5F, $41, $A6, $B6, $17, $32, $79, $10,
$70, $7C, $D8, $06, $8A, $1C, $BE, $DF, $E6, $39, $57, $F7, $91, $5C, $88, $D7,
$33, $63, $15, $8E, $53, $34, $D2, $F6, $7E, $2C, $05, $AF, $AE, $BC, $86, $47,
$99, $93, $C1, $46, $4B, $73, $3F, $20, $6E, $CD, $52, $23, $FA, $71, $85, $D4,
$9B, $31, $BD, $25, $90, $72, $2E, $48, $F5, $6B, $1A, $F4, $03, $F3, $30, $36,
$F0, $A4, $D1, $58, $E5, $1D, $76, $3E, $D3, $6D, $2A, $E7, $12, $50, $6F, $F9,
$22, $FB, $C7, $EC, $49, $EE, $3B, $8D, $08, $4C, $BA, $E3, $35, $ED, $F2, $C2,
$E8, $2F, $B2, $B4, $AC, $F1, $FC, $EB, $14, $A8, $74, $7F, $EF, $54, $AD, $B3,
$02, $6C, $2B, $27, $64, $BB, $40, $EA, $FD, $A0, $7D, $BF, $B8, $DA, $C4, $44,
$96, $B5, $E9, $9C, $B0, $AB, $E2, $CE, $DE, $37, $66, $29, $C6, $A5, $CA, $A7,
$B1, $7B, $DD, $0F, $84, $01, $D0, $1E, $0C, $FE, $4E, $D9, $DC, $94, $00, $38,
$B9, $45, $1B, $69, $C0, $8C, $92, $D6, $18, $04, $A9, $81, $5D, $21, $1F, $9E,
$98, $A2, $83, $87, $60, $55, $80, $CF, $56, $C8, $3C, $26, $3D, $A1, $FF, $07,
$F8, $68, $8F, $E0, $4F, $B7, $6A, $0B, $16, $62, $61, $AA, $9D, $0D, $89, $28,
$9A, $0A, $82, $4A, $C3, $78, $11, $4D, $67, $51, $CC, $0E, $24, $CB, $8B, $9F));
//RE-ORDERING MATRIX
P0: array[0..15, 0..15] of longword = (
($A, $3, $B, $C, $5, $E, $9, $F, $0, $7, $4, $6, $1, $D, $2, $8),
($9, $5, $F, $3, $1, $0, $A, $4, $7, $B, $E, $8, $2, $6, $D, $C),
($6, $D, $A, $4, $3, $5, $2, $8, $B, $F, $9, $C, $0, $E, $7, $1),
($E, $7, $0, $D, $8, $B, $1, $3, $9, $6, $C, $4, $A, $2, $F, $5),
($C, $A, $2, $5, $F, $D, $7, $9, $4, $E, $6, $B, $8, $3, $1, $0),
($5, $9, $3, $8, $D, $6, $4, $C, $1, $0, $7, $2, $E, $B, $A, $F),
($0, $6, $4, $A, $7, $3, $B, $E, $2, $8, $5, $1, $D, $F, $C, $9),
($D, $F, $9, $0, $6, $2, $3, $1, $E, $C, $A, $5, $B, $8, $4, $7),
($1, $0, $C, $2, $9, $7, $6, $D, $3, $5, $8, $E, $F, $A, $B, $4),
($3, $8, $5, $7, $2, $C, $E, $B, $A, $9, $D, $F, $4, $1, $0, $6),
($F, $B, $D, $1, $C, $8, $0, $6, $5, $2, $3, $7, $9, $4, $E, $A),
($8, $E, $1, $9, $4, $F, $C, $5, $6, $D, $2, $A, $7, $0, $3, $B),
($4, $C, $7, $6, $E, $1, $5, $2, $F, $A, $B, $0, $3, $9, $8, $D),
($7, $2, $6, $B, $0, $4, $D, $A, $8, $1, $F, $3, $5, $C, $9, $E),
($2, $1, $8, $E, $B, $A, $F, $7, $D, $4, $0, $9, $C, $5, $6, $3),
($B, $4, $E, $F, $A, $9, $8, $0, $C, $3, $1, $D, $6, $7, $5, $2));
//RE-ORDERING MATRIX INVERSE
P1: array[0..15, 0..15] of longword = (
($8, $C, $E, $1, $A, $4, $B, $9, $F, $6, $0, $2, $3, $D, $5, $7),
($5, $4, $C, $3, $7, $1, $D, $8, $B, $0, $6, $9, $F, $E, $A, $2),
($C, $F, $6, $4, $3, $5, $0, $E, $7, $A, $2, $8, $B, $1, $D, $9),
($2, $6, $D, $7, $B, $F, $9, $1, $4, $8, $C, $5, $A, $3, $0, $E),
($F, $E, $2, $D, $8, $3, $A, $6, $C, $7, $1, $B, $0, $5, $9, $4),
($9, $8, $B, $2, $6, $0, $5, $A, $3, $1, $E, $D, $7, $4, $C, $F),
($0, $B, $8, $5, $2, $A, $1, $4, $9, $F, $3, $6, $E, $C, $7, $D),
($3, $7, $5, $6, $E, $B, $4, $F, $D, $2, $A, $C, $9, $0, $8, $1),
($1, $0, $3, $8, $F, $9, $6, $5, $A, $4, $D, $E, $2, $7, $B, $C),
($E, $D, $4, $0, $C, $2, $F, $3, $1, $9, $8, $7, $5, $A, $6, $B),
($6, $3, $9, $A, $D, $8, $7, $B, $5, $C, $F, $1, $4, $2, $E, $0),
($D, $2, $A, $E, $4, $7, $8, $C, $0, $3, $B, $F, $6, $9, $1, $5),
($B, $5, $7, $C, $0, $6, $3, $2, $E, $D, $9, $A, $1, $F, $4, $8),
($4, $9, $1, $B, $5, $C, $2, $0, $8, $E, $7, $3, $D, $6, $F, $A),
($A, $1, $0, $F, $9, $D, $E, $7, $2, $B, $5, $4, $C, $8, $3, $6),
($7, $A, $F, $9, $1, $E, $C, $D, $6, $5, $4, $0, $8, $B, $2, $3));
function Mul(const Factor1, Factor2: longword): longword;
var
Product: Int64;
Lhalf, Rhalf: longword;
begin
Product := Factor1 * Factor2;
if Product = 0 then
Result := 1 - Factor1 - Factor2
else
begin
Lhalf := Product shr 32;
Rhalf := Product and $FFFFFFFF;
Result := Rhalf - Lhalf;
if Rhalf < Lhalf then
Inc(Result);
end;
end;
procedure BravionEncrypt(var Context: TBravionContext; var B: TBravionBlock32);
var
Temp: array[0..15] of longword;
pB: ^TBravionBlock8;
CarryBit: longword;
i: integer;
begin
pB := @B;
with Context do
begin
//ALGORITHM PERMUTATION
B[0] := B[0] xor RK[PK[16], 0];
B[1] := B[1] xor RK[PK[17], 1];
B[2] := B[2] xor RK[PK[18], 2];
B[3] := B[3] xor RK[PK[19], 3];
for i := 0 to 15 do //16 ROUNDS
begin
//IRRATIONALIZE 8BIT GROUPS
CarryBit := (B[0] and 2147483648) shr 31;
B[0] := (B[0] shl 1) or ((B[1] and 2147483648) shr 31);
B[1] := (B[1] shl 1) or ((B[2] and 2147483648) shr 31);
B[2] := (B[2] shl 1) or ((B[3] and 2147483648) shr 31);
B[3] := (B[3] shl 1) or CarryBit;
//PERMUTATION
B[3] := B[3] xor (B[2] - RK[i, 3]);
B[2] := B[2] xor Mul(B[1], RK[i, 2]);
B[1] := B[1] xor (B[0] + RK[i, 1]);
B[0] := B[0] xor RK[i, 0];
//SUBSTITUTION
{if anyone can optimize the following 20 lines please post it as a comment.
Bellow may seem slow, but it's MUCH faster than using Temp as a byte array
and Move(Temp,B,16). This is probably because the compiler is optimized for 32bit integers. An assembly version would be VERY fast.}
Temp[0] := S0[i, pB^[P0[PK[i], 0]]];
Temp[1] := S0[i, pB^[P0[PK[i], 1]]];
Temp[2] := S0[i, pB^[P0[PK[i], 2]]];
Temp[3] := S0[i, pB^[P0[PK[i], 3]]];
Temp[4] := S0[i, pB^[P0[PK[i], 4]]];
Temp[5] := S0[i, pB^[P0[PK[i], 5]]];
Temp[6] := S0[i, pB^[P0[PK[i], 6]]];
Temp[7] := S0[i, pB^[P0[PK[i], 7]]];
Temp[8] := S0[i, pB^[P0[PK[i], 8]]];
Temp[9] := S0[i, pB^[P0[PK[i], 9]]];
Temp[10] := S0[i, pB^[P0[PK[i], 10]]];
Temp[11] := S0[i, pB^[P0[PK[i], 11]]];
Temp[12] := S0[i, pB^[P0[PK[i], 12]]];
Temp[13] := S0[i, pB^[P0[PK[i], 13]]];
Temp[14] := S0[i, pB^[P0[PK[i], 14]]];
Temp[15] := S0[i, pB^[P0[PK[i], 15]]];
B[0] := (Temp[3] shl 24) or (Temp[2] shl 16) or (Temp[1] shl 8) or Temp[0];
B[1] := (Temp[7] shl 24) or (Temp[6] shl 16) or (Temp[5] shl 8) or Temp[4];
B[2] := (Temp[11] shl 24) or (Temp[10] shl 16) or (Temp[9] shl 8) or Temp[8];
B[3] := (Temp[15] shl 24) or (Temp[14] shl 16) or (Temp[13] shl 8) or Temp[12];
end;
//ALGORITHM PERMUTATION
B[0] := B[0] xor RK[PK[20], 0];
B[1] := B[1] xor RK[PK[21], 1];
B[2] := B[2] xor RK[PK[22], 2];
B[3] := B[3] xor RK[PK[23], 3];
end;
end;
procedure BravionDecrypt(var Context: TBravionContext; var B: TBravionBlock32);
var
Temp: array[0..15] of longword;
pB: ^TBravionBlock8;
CarryBit: longword;
i: integer;
begin
pB := @B;
with Context do
begin
B[3] := B[3] xor RK[PK[23], 3];
B[2] := B[2] xor RK[PK[22], 2];
B[1] := B[1] xor RK[PK[21], 1];
B[0] := B[0] xor RK[PK[20], 0];
for i := 15 downto 0 do
begin
Temp[0] := S1[i, pB^[P1[PK[i], 0]]];
Temp[1] := S1[i, pB^[P1[PK[i], 1]]];
Temp[2] := S1[i, pB^[P1[PK[i], 2]]];
Temp[3] := S1[i, pB^[P1[PK[i], 3]]];
Temp[4] := S1[i, pB^[P1[PK[i], 4]]];
Temp[5] := S1[i, pB^[P1[PK[i], 5]]];
Temp[6] := S1[i, pB^[P1[PK[i], 6]]];
Temp[7] := S1[i, pB^[P1[PK[i], 7]]];
Temp[8] := S1[i, pB^[P1[PK[i], 8]]];
Temp[9] := S1[i, pB^[P1[PK[i], 9]]];
Temp[10] := S1[i, pB^[P1[PK[i], 10]]];
Temp[11] := S1[i, pB^[P1[PK[i], 11]]];
Temp[12] := S1[i, pB^[P1[PK[i], 12]]];
Temp[13] := S1[i, pB^[P1[PK[i], 13]]];
Temp[14] := S1[i, pB^[P1[PK[i], 14]]];
Temp[15] := S1[i, pB^[P1[PK[i], 15]]];
B[0] := (Temp[3] shl 24) or (Temp[2] shl 16) or (Temp[1] shl 8) or Temp[0];
B[1] := (Temp[7] shl 24) or (Temp[6] shl 16) or (Temp[5] shl 8) or Temp[4];
B[2] := (Temp[11] shl 24) or (Temp[10] shl 16) or (Temp[9] shl 8) or Temp[8];
B[3] := (Temp[15] shl 24) or (Temp[14] shl 16) or (Temp[13] shl 8) or Temp[12];
B[0] := B[0] xor RK[i, 0];
B[1] := B[1] xor (B[0] + RK[i, 1]);
B[2] := B[2] xor Mul(B[1], RK[i, 2]);
B[3] := B[3] xor (B[2] - RK[i, 3]);
CarryBit := (B[3] and 1) shl 31;
B[3] := (B[3] shr 1) or ((B[2] and 1) shl 31);
B[2] := (B[2] shr 1) or ((B[1] and 1) shl 31);
B[1] := (B[1] shr 1) or ((B[0] and 1) shl 31);
B[0] := (B[0] shr 1) or CarryBit;
end;
B[3] := B[3] xor RK[PK[19], 3];
B[2] := B[2] xor RK[PK[18], 2];
B[1] := B[1] xor RK[PK[17], 1];
B[0] := B[0] xor RK[PK[16], 0];
end;
end;
procedure BravionInit(var Context: TBravionContext; var Key: TBravionKey32);
const
M1 = longword(259200);
M2 = longword(134456);
M3 = longword(243000);
I1 = longword(7141);
I2 = longword(8121);
I3 = longword(4561);
C1 = longword(54773);
C2 = longword(28411);
C3 = longword(51349);
var
X1, X2, X3: longword;
R: array[1..97] of real;
Temp: TBravionBlock32;
i, j, k: integer;
begin
with Context do
begin
FillChar(PK, Sizeof(TBravionPathKey8), 0);
FillChar(RK, Sizeof(TBravionRoundKey32), 0);
i := 0;
repeat //KEY EXPANSION
{I'm actualy using a PRNG with 2^32 period for the expansion}
X1 := (Key[i] + C1) mod M1;
X1 := (X1 * I1 + C1) mod M1;
X2 := X1 mod M2;
X1 := (X1 * I1 + C1) mod M1;
X3 := X1 mod M3;
for j := 1 to 97 do
begin
X1 := (X1 * I1 + C1) mod M1;
X2 := (X2 * I2 + C2) mod M2;
R[j] := (X1 + X2 / M2) / M1;
end;
for j := 0 to 3 do
begin
X1 := (X1 * I1 + C1) mod M1;
X2 := (X2 * I2 + C2) mod M2;
X3 := (X3 * I3 + C3) mod M3;
k := 1 + (97 * X3) div M3;
RK[i * 2, j] := trunc($FFFFFFFF * R[k]);
R[k] := (X1 + X2 / M2) / M1;
X1 := (X1 * I1 + C1) mod M1;
X2 := (X2 * I2 + C2) mod M2;
X3 := (X3 * I3 + C3) mod M3;
k := 1 + (97 * X3) div M3;
RK[(i * 2) + 1, j] := trunc($FFFFFFFF * r[k]);
R[k] := (X1 + X2 / M2) / M1;
end;
Inc(i, 1);
until i = 8;
for i := 0 to 15 do //SET 4BIT PATH KEYS
begin
PK[i] := (TBravionKey8(Key)[i] xor TBravionKey8(Key)[i + 16]) and $F;
j := 16 + (i and 7);
PK[j] := PK[j] xor ((TBravionKey8(Key)[i] xor TBravionKey8(Key)[i + 16]) and $F0)
shr 4;
end;
end;
for i := 0 to 127 do //PERMUTE ROUND KEYS
begin
j := 0;
repeat
Move(Key[0], Temp, Sizeof(TBravionBlock32));
BravionEncrypt(Context, Temp);
Move(Temp, Context.RK[j], Sizeof(TBravionBlock32));
Move(Key[4], Temp, Sizeof(TBravionBlock32));
BravionEncrypt(Context, Temp);
Move(Temp, Context.RK[j + 1], Sizeof(TBravionBlock32));
Inc(j, 2);
until j = 16;
end;
end;
end.
Using the encryption is very simple:
procedure TForm1.Button1Click(Sender: TObject);
var
k: TBravionKey32;
b: TBravionBlock32;
c: TBravionContext;
s: string;
i: longword;
begin
randomize;
for i := 0 to 7 do
k[i] := Random(MaxInt);
for i := 0 to 3 do
b[i] := Random(MaxInt);
BravionInit(c, k);
s := 'Key: {';
for i := 0 to 15 do
s := s + inttohex(TBravionKey8(k)[i], 2);
memo1.lines.add(s + ',');
s := ' ';
for i := 16 to 31 do
s := s + inttohex(TBravionKey8(k)[i], 2);
memo1.lines.add(s + '}');
s := 'Plaintext: {';
for i := 0 to 15 do
s := s + inttohex(TBravionBlock8(b)[i], 2);
memo1.lines.add(s + '}');
BravionEncrypt(c, b);
s := 'Ciphertext: {';
for i := 0 to 15 do
s := s + inttohex(TBravionBlock8(b)[i], 2);
memo1.lines.add(s + '}');
BravionDecrypt(c, b);
s := 'Plaintext: {';
for i := 0 to 15 do
s := s + inttohex(TBravionBlock8(b)[i], 2);
memo1.lines.add(s + '}');
memo1.lines.add('');
end;
this example requires a form, button and memo. it's pretty self explanatory.
Feliratkozás:
Bejegyzések (Atom)