|
|
library RatCrypt;
|
|
|
|
|
|
uses
|
|
|
Classes,
|
|
|
windows,
|
|
|
plugin,
|
|
|
pluginutil,
|
|
|
CallExec,
|
|
|
SysUtils,
|
|
|
Graphics,
|
|
|
elAES,
|
|
|
Math,
|
|
|
MyOverLite,
|
|
|
Forms,
|
|
|
setpassform in 'setpassform.pas' {setpass};
|
|
|
|
|
|
{$I NoRTTI.inc}
|
|
|
{$R RatCrypt.res}
|
|
|
{$R 'icons.res' 'Icons/icons.rc'}
|
|
|
|
|
|
var
|
|
|
msg, msgcrypt, andrqPath: ansistring;
|
|
|
size, uin, flags, vApiVersion, currentUIN: Integer;
|
|
|
sSource, sDest: TStringStream;
|
|
|
Key: TAESKey256;
|
|
|
When: TDateTime;
|
|
|
|
|
|
ba: Integer;
|
|
|
hico: TIcon;
|
|
|
|
|
|
const
|
|
|
namepl: ansistring = 'RatCrypt 0.45';
|
|
|
|
|
|
function StringToHex(const value: ansistring): ansistring;
|
|
|
var
|
|
|
abyte: TBytes;
|
|
|
i: Integer;
|
|
|
begin
|
|
|
result := '';
|
|
|
abyte := TEncoding.UTF8.GetBytes(value);
|
|
|
for i := 0 to length(abyte) - 1 do
|
|
|
begin
|
|
|
result := result + IntToHex(abyte[i], 2);
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
function HexToString(const value: ansistring): ansistring;
|
|
|
var
|
|
|
i, idx: Integer;
|
|
|
abyte: TBytes;
|
|
|
begin
|
|
|
result := '';
|
|
|
SetLength(abyte, length(value) div 2);
|
|
|
i := 1;
|
|
|
idx := 0;
|
|
|
while i <= length(value) do
|
|
|
begin
|
|
|
abyte[idx] := StrToInt('$' + value[i] + value[i + 1]);
|
|
|
i := i + 2;
|
|
|
idx := idx + 1;
|
|
|
end;
|
|
|
result := TEncoding.UTF8.GetString(abyte);
|
|
|
end;
|
|
|
|
|
|
procedure OnButtonClick(iButton: Integer);
|
|
|
var MonNum: Integer;
|
|
|
begin
|
|
|
case iButton of
|
|
|
1:
|
|
|
begin
|
|
|
if not fileexists(userPath + 'RatCryptWho.ini') then
|
|
|
setpass.memo1.lines.savetofile(userPath + 'RatCryptWho.ini');
|
|
|
|
|
|
MonNum := Screen.MonitorFromWindow(GetForegroundWindow, mdNearest).MonitorNum;
|
|
|
setpass.Top := Screen.Monitors[MonNum].Top + ((Screen.Monitors[MonNum].Height div 2) - (setpass.Height div 2));
|
|
|
setpass.Left := Screen.Monitors[MonNum].Left + ((Screen.Monitors[MonNum].Width div 2) - (setpass.Width div 2));
|
|
|
setpass.show;
|
|
|
end;
|
|
|
|
|
|
0:
|
|
|
begin
|
|
|
Global := not Global;
|
|
|
|
|
|
if Global = true then
|
|
|
hico.Handle := LoadIcon(HInstance, 'RNQ_CRYPT')
|
|
|
else
|
|
|
hico.Handle := LoadIcon(HInstance, 'RNQ');
|
|
|
|
|
|
RQ_ChangeChatButton(ba, hico.Handle, namepl);
|
|
|
setpass.SaveSettings;
|
|
|
end;
|
|
|
|
|
|
2:
|
|
|
smsg(namepl + ' <20> Mikanoshi [Algorithm: AES 256 bit]', trans_about);
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
function pluginFun(data: pointer): pointer; stdcall;
|
|
|
var i: Integer; stt: TStringList;
|
|
|
begin
|
|
|
result := nil;
|
|
|
if (data = nil) or (_int_at(data) = 0) then
|
|
|
exit;
|
|
|
case _byte_at(data, 4) of
|
|
|
PM_EVENT:
|
|
|
case _byte_at(data, 5) of
|
|
|
|
|
|
PE_INITIALIZE:
|
|
|
begin
|
|
|
RQ__ParseInitString(data, callback, vApiVersion, andrqPath, userPath, currentUIN);
|
|
|
{
|
|
|
userPath := IncludeTrailingPathDelimiter(ExtractFilePath(application.ExeName)) + 'plugins\';
|
|
|
if fileexists(userPath + 'RatCryptPath.ini') then
|
|
|
begin
|
|
|
stt := TStringList.create;
|
|
|
stt.LoadFromFile(userPath + 'RatCryptPath.ini');
|
|
|
userPath := stt[0];
|
|
|
stt.Free;
|
|
|
end;
|
|
|
}
|
|
|
if userPath[length(userPath)] <> '\' then
|
|
|
userPath := userPath + '\';
|
|
|
setpass := TSetPass.create(nil);
|
|
|
hico := TIcon.create;
|
|
|
Global := false;
|
|
|
hico.Handle := LoadIcon(HInstance, 'RNQ');
|
|
|
if fileexists(userPath + 'RatCrypt.ini') then
|
|
|
begin
|
|
|
stt := TStringList.create;
|
|
|
stt.LoadFromFile(userPath + 'RatCrypt.ini');
|
|
|
if stt[0] = 'on' then
|
|
|
begin
|
|
|
Global := true;
|
|
|
hico.Handle := LoadIcon(HInstance, 'RNQ_CRYPT');
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
Global := false;
|
|
|
hico.Handle := LoadIcon(HInstance, 'RNQ');
|
|
|
end;
|
|
|
stt.Free;
|
|
|
end;
|
|
|
// smsg('RATCRYPT 7');
|
|
|
ba := RQ_CreateChatButton(@OnButtonClick, hico.Handle, namepl);
|
|
|
// smsg('RATCRYPT 8');
|
|
|
result := str2comm(char(PM_DATA) + _istring(namepl) + _int(APIversion));
|
|
|
end;
|
|
|
|
|
|
PE_FINALIZE:
|
|
|
begin
|
|
|
if ba <> 0 then
|
|
|
RQ_DeleteChatButton(ba);
|
|
|
if hico <> nil then
|
|
|
hico.Free;
|
|
|
setpass.Free;
|
|
|
end;
|
|
|
|
|
|
PE_MSG_SENT:
|
|
|
if Global = true then
|
|
|
if fileexists(userPath + 'RatCryptWho.ini') then
|
|
|
begin
|
|
|
RQ__ParseMsgSentString(data, uin, flags, msg);
|
|
|
|
|
|
for i := 0 to setpass.memo1.lines.count - 1 do
|
|
|
if setpass.memo1.lines[i] = its(uin) then
|
|
|
try
|
|
|
sSource := TStringStream.create(msg);
|
|
|
sDest := TStringStream.create('');
|
|
|
|
|
|
size := sSource.size;
|
|
|
sDest.WriteBuffer(size, SizeOf(size));
|
|
|
|
|
|
FillChar(Key, SizeOf(Key), 0);
|
|
|
if setpass.pass_check.Checked = true then
|
|
|
Move(PChar(setpass.Edit1.Text)^, Key, Min(SizeOf(Key), length(setpass.Edit1.Text)))
|
|
|
else if fileexists(setpass.Edit2.Text) or fileexists(userPath + setpass.Edit2.Text) then
|
|
|
begin
|
|
|
stt := TStringList.create;
|
|
|
if fileexists(userPath + setpass.Edit2.Text) then
|
|
|
stt.LoadFromFile(userPath + setpass.Edit2.Text)
|
|
|
else if fileexists(setpass.Edit2.Text) then
|
|
|
stt.LoadFromFile(setpass.Edit2.Text);
|
|
|
Move(PChar(stt[0])^, Key, Min(SizeOf(Key), length(stt[0])));
|
|
|
stt.Free;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
result := str2comm(char(PM_ABORT));
|
|
|
smsg(trans_keynotfound, trans_warn);
|
|
|
exit;
|
|
|
end;
|
|
|
|
|
|
EncryptAESStreamECB(sSource, 0, Key, sDest);
|
|
|
|
|
|
result := str2comm(char(PM_DATA) + _istring('#RCRPT:' + StringToHex(sDest.DataString)) + _istring(msg));
|
|
|
|
|
|
sSource.Free;
|
|
|
sDest.Free;
|
|
|
break;
|
|
|
except
|
|
|
result := str2comm(char(PM_ABORT));
|
|
|
smsg(trans_crypterr);
|
|
|
break;
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
PE_MSG_GOT:
|
|
|
begin
|
|
|
RQ__ParseMsgGotString(data, uin, flags, When, msg);
|
|
|
|
|
|
if pos('#RCRPT:', msg) = 1 then
|
|
|
try
|
|
|
msg := copy(msg, 8, length(msg));
|
|
|
sSource := TStringStream.create(HexToString(msg));
|
|
|
sDest := TStringStream.create('');
|
|
|
|
|
|
size := sSource.size;
|
|
|
sSource.ReadBuffer(size, SizeOf(size));
|
|
|
|
|
|
FillChar(Key, SizeOf(Key), 0);
|
|
|
if setpass.pass_check.Checked = true then
|
|
|
Move(PChar(setpass.Edit1.Text)^, Key, Min(SizeOf(Key), length(setpass.Edit1.Text)))
|
|
|
else if fileexists(setpass.Edit2.Text) or fileexists(userPath + setpass.Edit2.Text) then
|
|
|
begin
|
|
|
stt := TStringList.create;
|
|
|
if fileexists(userPath + setpass.Edit2.Text) then
|
|
|
stt.LoadFromFile(userPath + setpass.Edit2.Text)
|
|
|
else if fileexists(setpass.Edit2.Text) then
|
|
|
stt.LoadFromFile(setpass.Edit2.Text);
|
|
|
Move(PChar(stt[0])^, Key, Min(SizeOf(Key), length(stt[0])));
|
|
|
stt.Free;
|
|
|
end
|
|
|
else
|
|
|
begin
|
|
|
smsg(trans_keynotfound2, trans_warn);
|
|
|
exit;
|
|
|
end;
|
|
|
|
|
|
DecryptAESStreamECB(sSource, sSource.size - sSource.Position, Key, sDest);
|
|
|
|
|
|
msgcrypt := sDest.DataString;
|
|
|
while msgcrypt[length(msgcrypt)] = #00 do
|
|
|
msgcrypt := copy(msgcrypt, 1, length(msgcrypt) - 1);
|
|
|
|
|
|
// callStr(char(PM_CMD)+char(PC_ADD_MSG)+_int(uin)+_dt(now)+_istring(msgcrypt));
|
|
|
|
|
|
sSource.Free;
|
|
|
sDest.Free;
|
|
|
result := str2comm(char(PM_DATA) + _istring(msgcrypt));
|
|
|
except
|
|
|
result := str2comm(char(PM_DATA) + _istring(trans_origmsg + #13#10 + '#RCRPT:' + msg));
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
PE_PREFERENCES:
|
|
|
smsg(namepl + ' <20> Mikanoshi [Algorithm: AES 256 bit]', trans_about);
|
|
|
|
|
|
end;
|
|
|
end; // cases
|
|
|
end; // pluginFun
|
|
|
|
|
|
exports
|
|
|
pluginFun;
|
|
|
|
|
|
end.
|