Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| unit feces; | |
| //friends endorsing cheat engine system | |
| {$mode objfpc}{$H+} | |
| interface | |
| uses | |
| Classes, SysUtils, bcrypt, DOM, xmlutils, XmlRead, XMLWrite, dialogs, windows, | |
| graphics, math; | |
| function canSignTables: boolean; | |
| procedure signTable(cheattable: TDOMElement); | |
| procedure signTableFile(f: string); | |
| function isProperlySigned(cheattable: TDOMElement; out specialstring: string; out imagepos: integer; out image: tpicture): boolean; | |
| implementation | |
| uses cefuncproc, CustomBase85, registry, formsettingsunit; | |
| resourcestring | |
| rsFailedToGetSignatureSize = 'Failed to get the signature size'; | |
| rsFailedToFinishTheHash = 'Failed to finish the hash'; | |
| rsFailedToGetHashlength = 'Failed to get hashlength'; | |
| rsFailedHashingTable = 'Failed hashing table'; | |
| rsFailedCreatingHash = 'Failed creating hash'; | |
| rsFailedGettingTheObjectLength = 'Failed getting the object length'; | |
| rsFailedCreatingHasAlgorithmProvider = 'Failed creating has algorithm ' | |
| +'provider'; | |
| rsFailedToLoadPrivateKey = 'Failed to load private key'; | |
| rsIsPasswordCorrect='Is the password correct?'; | |
| rsCouldNotOpenTheAlgorithmProvider = 'Could not open the algorithm provider'; | |
| rsBcryptCouldNotBeUsed = 'bcrypt could not be used'; | |
| rsSelectYourCheatEngineSignatureFile = 'Select your cheat engine signature ' | |
| +'file'; | |
| rsCheatEngineSignatureFiles = 'Cheat engine signature files'; | |
| rsThisTableHasBeenModified = 'This table has been modified. To load this ' | |
| +'table, remove the signature part with an editor (And check the file for ' | |
| +'suspicious things while you''re at it)'; | |
| rsFailedToFinishTheHash2 = 'Failed to finish the hash 2'; | |
| rsFailedToGetHashlength2 = 'Failed to get hashlength 2'; | |
| rsFailedHashingTable2 = 'Failed hashing table 2'; | |
| rsFailedCreatingHash2 = 'Failed creating hash 2'; | |
| rsInvalidPublicKey = 'The provided public key is invalid(Not signed by the ' | |
| +'Cheat Engine guy). Remove the signature section to load this table'; | |
| rsFailedCreatingHasAlgorithmProvider2 = 'Failed creating has algorithm ' | |
| +'provider'; | |
| rsFailedToLoadTheTablePublicKey = 'Failed to load the table public key'; | |
| rsFailedToLoadCheatEnginePublicKey = 'Failed to load cheat engine public key'; | |
| rsNoSignedHash = 'This table''s signature does not contain a SignedHash ' | |
| +'element'; | |
| rsNoPublicKey = | |
| 'This table''s signature does not contain a PublicKey element'; | |
| var | |
| cheatenginepublictablekey: BCRYPT_KEY_HANDLE=0; | |
| publictablekey: array [0..139] of byte =($45, $43, $53, $35, $42, $00, $00, | |
| $00, $01, $A3, $7A, $45, $2A, $66, $60, $85, $C7, $50, $9D, $8C, $3F, $34, | |
| $57, $D3, $FF, $50, $E3, $32, $CA, $4C, $4D, $61, $9B, $00, $19, $7E, $61, | |
| $6B, $1F, $52, $50, $7E, $01, $94, $8B, $F0, $A4, $91, $49, $FC, $58, $32, | |
| $D8, $43, $60, $F7, $F1, $46, $F5, $CB, $A0, $AB, $0B, $26, $D4, $1D, $9D, | |
| $BE, $40, $C8, $12, $30, $CA, $15, $01, $30, $A9, $4D, $03, $6E, $4E, $4A, | |
| $5E, $85, $CF, $85, $5D, $D7, $24, $47, $36, $A6, $25, $2B, $B0, $48, $7E, | |
| $95, $8F, $F2, $9A, $FF, $B3, $C9, $C9, $97, $85, $FB, $59, $4F, $8A, $D4, | |
| $FF, $A4, $80, $A4, $AE, $92, $B8, $48, $64, $74, $05, $7C, $97, $90, $A3, | |
| $7E, $0E, $72, $76, $5B, $B4, $D8, $18, $E5, $A6, $A2, $E3, $47); | |
| threadvar pathtosigfile: pchar; | |
| threadvar passwordhash: pbyte; | |
| var passwordhashlength: integer; | |
| //useless protection but hey, why not | |
| type TCanSign=(csUnknown, csYes, csNo); | |
| var | |
| EncodePointer:function(p: pointer):pointer; stdcall; | |
| DecodePointer:function(p: pointer):pointer; stdcall; | |
| _cansignstate: TCanSign=csUnknown; | |
| var rv: dword=0; | |
| function EncodePointerNI(p: pointer):pointer; stdcall; //not implemented (unpatched XP) | |
| begin | |
| if rv=0 then | |
| rv:=1+random($fffffffd); | |
| result:=pointer(ptruint(p) xor rv); | |
| end; | |
| function DecodePointerNI(p: pointer):pointer; stdcall; | |
| begin | |
| if rv=0 then exit; | |
| result:=pointer(ptruint(p) xor rv); | |
| end; | |
| procedure getXmlfileWithoutSignature(cheattable: TDOMElement; output: tstream); | |
| var | |
| signature: TDOMNode; | |
| begin | |
| signature:=CheatTable.FindNode('Signature'); | |
| if signature<>nil then | |
| begin | |
| CheatTable.DetachChild(signature); | |
| signature.free; | |
| end; | |
| if cheattable<>nil then | |
| begin | |
| //showmessage(cheattable.TextContent); | |
| WriteXML(cheattable,output); | |
| // output.WriteAnsiString(cheattable.TextContent); | |
| end; | |
| end; | |
| function isProperlySigned(cheattable: TDOMElement; out specialstring: string; out imagepos: integer; out image: TPicture): boolean; | |
| var | |
| signature: TDOMNode; | |
| publicKey: TDOMNode; | |
| signedhash: TDOMNode; | |
| size: integer; | |
| tablepublickey: BCRYPT_KEY_HANDLE=0; | |
| hAlgoritm: BCRYPT_ALG_HANDLE=0; | |
| hashAlgoritm: BCRYPT_ALG_HANDLE=0; | |
| hHash: BCRYPT_HASH_HANDLE=0; | |
| publickeysize: integer; | |
| publickeyblock: pointer=nil; | |
| publicdata: tmemorystream=nil; | |
| keysize: integer; | |
| signaturesize: integer; | |
| sig: pointer; | |
| objectlength: dword; | |
| bHashObject: pointer=nil; | |
| hashlength: integer; | |
| hashbuffer: pointer=nil; | |
| customstring: string; | |
| s: ntstatus; | |
| x: dword; | |
| ps: pchar; | |
| str: string; | |
| cheattablecontents: TMemorystream=nil; | |
| tablesignature: pointer=nil; | |
| tablesignaturesize: integer; | |
| sigversion: word; | |
| imagebuf: pointer; | |
| imagestream: TMemorystream; | |
| begin | |
| if not initialize_bCrypt then | |
| exit(false); | |
| signature:=CheatTable.FindNode('Signature'); | |
| if signature=nil then exit(false); | |
| signedhash:=signature.FindNode('SignedHash'); | |
| if signedhash=nil then | |
| raise exception.create(rsNoSignedHash); | |
| tablesignaturesize:=strtoint(TDOMElement(signedhash).Attributes.GetNamedItem('HashSize').TextContent); | |
| try | |
| getmem(tablesignature, tablesignaturesize); | |
| str:=signedhash.TextContent; | |
| x:=Base85ToBin(pchar(str), tablesignature); | |
| if x<>tablesignaturesize then | |
| raise exception.create('a thing happened'); | |
| //get the public key from the signature | |
| publicKey:=signature.FindNode('PublicKey'); | |
| if publickey=nil then | |
| raise exception.create(rsNoPublicKey); | |
| publickeysize:=strtoint(TDOMElement(publickey).Attributes.GetNamedItem('Size').TextContent); | |
| getmem(publickeyblock, publickeysize); | |
| str:=publickey.TextContent; | |
| x:=Base85ToBin(pchar(str), publickeyblock); | |
| publicdata:=tmemorystream.create; | |
| publicdata.WriteBuffer(publickeyblock^, publickeysize); | |
| publicdata.position:=0; | |
| publicdata.Seek(0, soFromBeginning); | |
| customstring:=publicdata.ReadAnsiString; | |
| specialstring:=customstring; | |
| keysize:=publicdata.ReadWord; | |
| sigversion:=publicdata.ReadWord; | |
| s:=BCryptOpenAlgorithmProvider(hAlgoritm, 'ECDSA_P521', nil, 0); | |
| if not succeeded(s) then raise exception.create( | |
| rsCouldNotOpenTheAlgorithmProvider); | |
| if cheatenginepublictablekey=0 then | |
| begin | |
| s:=BCryptImportKeyPair(hAlgoritm, 0, BCRYPT_ECCPUBLIC_BLOB, cheatenginepublictablekey, @publictablekey[0], 140, 0); | |
| if not succeeded(s) then raise exception.create( | |
| rsFailedToLoadCheatEnginePublicKey); | |
| end; | |
| //load the public key of this table while we're at it | |
| s:=BCryptImportKeyPair(hAlgoritm, 0, BCRYPT_ECCPUBLIC_BLOB, tablepublickey, pointer(ptruint(publicdata.Memory)+publicdata.position), keysize, 0); | |
| if not succeeded(s) then raise exception.create( | |
| rsFailedToLoadTheTablePublicKey); | |
| publicdata.Position:=publicdata.Position+keysize; | |
| imagepos:=-1; | |
| image:=nil; | |
| if sigversion>=1 then | |
| begin | |
| imagepos:=publicdata.ReadByte; | |
| if imagepos<>0 then | |
| begin | |
| x:=publicdata.readdword; //image size | |
| imagestream:=tmemorystream.create; | |
| getmem(imagebuf, x); | |
| try | |
| publicdata.ReadBuffer(imagebuf^, x); | |
| imagestream.writebuffer(imagebuf^,x); | |
| imagestream.position:=0; | |
| image:=TPicture.Create; | |
| image.LoadFromStream(imagestream); | |
| finally | |
| imagestream.free; | |
| freemem(imagebuf); | |
| end; | |
| end; | |
| end; | |
| publickeysize:=publicdata.position; //reuse this | |
| signaturesize:=publicdata.ReadDWord; | |
| sig:=pointer(ptruint(publicdata.memory)+publicdata.position); | |
| //check the signature of the public key with publictablekey | |
| //create a hash of the data in publicdata.memory to publicdata.memory+publickeysize | |
| s:=BCryptOpenAlgorithmProvider(hashAlgoritm, 'SHA512', nil, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedCreatingHasAlgorithmProvider2); | |
| objectlength:=0; | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_OBJECT_LENGTH, @objectlength, sizeof(DWORD), size, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedGettingTheObjectLength); | |
| getmem(bHashObject, objectlength); | |
| zeromemory(bHashObject, objectlength); | |
| hHash:=0; | |
| s:=BCryptCreateHash(hashAlgoritm, hHash, bHashObject, objectlength, nil, 0, 0); | |
| if not Succeeded(s) then raise exception.create(rsFailedCreatingHash); | |
| s:=BCryptHashData(hHash, publicdata.Memory, publickeysize, 0); | |
| if not Succeeded(s) then raise exception.create(rsFailedHashingTable); | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_HASH_LENGTH, @hashlength, sizeof(DWORD), size, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToGetHashlength); | |
| getmem(hashbuffer, hashlength); | |
| s:=BCryptFinishHash(hHash, hashbuffer, hashlength, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToFinishTheHash); | |
| //now verify this hash with the signature and the ce public key | |
| s:=BCryptVerifySignature(cheatenginepublictablekey,nil,hashbuffer,hashlength,sig, signaturesize,0); | |
| if not succeeded(s) then raise exception.create(rsInvalidPublicKey); | |
| //still here so the public key is valid | |
| BCryptDestroyHash(hHash); | |
| hHash:=0; | |
| freemem(hashbuffer); | |
| hashbuffer:=nil; | |
| //now hash the table(without signature section) and verify that with the 'SignedHash' | |
| cheattablecontents:=TMemoryStream.create; | |
| getXmlfileWithoutSignature(cheattable, cheattablecontents); | |
| s:=BCryptCreateHash(hashAlgoritm, hHash, bHashObject, objectlength, nil, 0, 0); | |
| if not Succeeded(s) then raise exception.create(rsFailedCreatingHash2); | |
| s:=BCryptHashData(hHash, cheattablecontents.Memory, cheattablecontents.size, 0); | |
| if not Succeeded(s) then raise exception.create(rsFailedHashingTable2); | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_HASH_LENGTH, @hashlength, sizeof(DWORD), size, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToGetHashlength2); | |
| getmem(hashbuffer, hashlength); | |
| s:=BCryptFinishHash(hHash, hashbuffer, hashlength, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToFinishTheHash2); | |
| s:=BCryptVerifySignature(tablepublickey,nil,hashbuffer,hashlength,tablesignature, tablesignaturesize,0); | |
| if not succeeded(s) then raise exception.create(rsThisTableHasBeenModified); | |
| result:=true; | |
| finally | |
| if tablesignature<>nil then | |
| freemem(tablesignature); | |
| if publickeyblock<>nil then | |
| freemem(publickeyblock); | |
| if publicdata<>nil then | |
| freeandnil(publicdata); | |
| if hAlgoritm<>0 then | |
| BCryptCloseAlgorithmProvider(hAlgoritm,0); | |
| if hashAlgoritm<>0 then | |
| BCryptCloseAlgorithmProvider(hashAlgoritm,0); | |
| if hHash<>0 then | |
| BCryptDestroyHash(hHash); | |
| if cheattablecontents<>nil then | |
| freeandnil(cheattablecontents); | |
| if hashbuffer<>nil then | |
| freemem(hashbuffer); | |
| if tablepublickey<>0 then | |
| BCryptDestroyKey(tablepublickey); | |
| end; | |
| //check the signatureless version of the cheat table with this public key | |
| end; | |
| function canSignTables: boolean; | |
| var reg: tregistry; | |
| begin | |
| if _cansignstate=csUnknown then | |
| begin | |
| result:=FileExists(GetCEdir+'cansign.txt') or FileExists(GetCEDir+'mysignature.cesig'); | |
| if result then | |
| _cansignstate:=csYes | |
| else | |
| _cansignstate:=csNo; | |
| exit; | |
| end; | |
| result:=_cansignstate=csYes; | |
| end; | |
| procedure signTableFile(f: string); | |
| var | |
| d: TXMLDocument; | |
| e: TDOMElement; | |
| begin | |
| ReadXMLFile(d, f); | |
| e:=TDOMElement(d.FindNode('CheatTable')); | |
| signtable(e); | |
| WriteXMLFile(d,f); | |
| end; | |
| procedure generateHash(password: pointer; passwordsize: integer; var hash: pointer; var hashsize: integer); | |
| var | |
| s: ntstatus; | |
| hashAlgoritm: BCRYPT_ALG_HANDLE; | |
| hhash: BCRYPT_HASH_HANDLE; | |
| objectlength: dword; | |
| bHashObject: pointer; | |
| size: ulong; | |
| i,j: integer; | |
| secondaryvalue: byte; | |
| begin | |
| hash:=nil; | |
| hashsize:=0; | |
| if passwordsize=0 then exit; | |
| s:=BCryptOpenAlgorithmProvider(hashAlgoritm, 'SHA512', nil, 0); | |
| if succeeded(s) then | |
| begin | |
| objectlength:=0; | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_OBJECT_LENGTH, @objectlength, sizeof(DWORD), size, 0); | |
| if succeeded(s) then | |
| begin | |
| getmem(bHashObject, objectlength); | |
| zeromemory(bHashObject, objectlength); | |
| hHash:=0; | |
| s:=BCryptCreateHash(hashAlgoritm, hHash, bHashObject, objectlength, nil, 0, 0); | |
| if succeeded(s) then | |
| begin | |
| s:=BCryptHashData(hHash, password, passwordsize, 0); | |
| if succeeded(s) then | |
| begin | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_HASH_LENGTH, @hashsize, sizeof(DWORD), size, 0); | |
| if succeeded(s) then | |
| begin | |
| getmem(hash, hashsize); | |
| s:=BCryptFinishHash(hHash, hash, hashsize, 0); | |
| end; | |
| end; | |
| BCryptDestroyHash(hashAlgoritm); | |
| end; | |
| freemem(bHashObject); | |
| BCryptCloseAlgorithmProvider(hashAlgoritm,0); | |
| end; | |
| end; | |
| end; | |
| procedure getPasswordHash(password: string; out pwhash: pointer; out pwhashlength: integer; wantedsize: integer); | |
| var | |
| hash: array of byte; | |
| initialHash: pbyte; | |
| initialhashsize: integer; | |
| partialhash: pbyte; | |
| partialhashsize: integer; | |
| hashpos: integer; | |
| copysize: integer; | |
| i,j: integer; | |
| begin | |
| pwhash:=nil; | |
| if password='' then exit; | |
| setlength(hash,wantedsize); | |
| //generate hashes until it's the size of the buffer | |
| hashpos:=0; | |
| generateHash(@password[1],length(password),initialhash,initialhashsize); | |
| j:=1; | |
| for i:=0 to initialhashsize-1 do | |
| begin | |
| initialhash[i]:=initialhash[i] xor ord(password[j]); | |
| inc(j); | |
| if j>length(password) then j:=1; | |
| end; | |
| generateHash(initialhash,initialhashsize,partialhash,partialhashsize); | |
| freemem(initialhash); | |
| copysize:=ifthen(partialhashsize>wantedsize, wantedsize, partialhashsize); | |
| copymemory(@hash[0],partialhash, copysize); | |
| freemem(partialhash); | |
| inc(hashpos, copysize); | |
| while hashpos<wantedsize do | |
| begin | |
| generateHash(@hash[hashpos-copysize],copysize,partialhash, partialhashsize); | |
| copysize:=ifthen(partialhashsize+hashpos>wantedsize, wantedsize-hashpos, partialhashsize); | |
| copymemory(@hash[hashpos],partialhash, copysize); | |
| freemem(partialhash); | |
| inc(hashpos,copysize); | |
| end; | |
| getmem(pwhash, wantedsize); | |
| copymemory(pwhash, @hash[0],wantedsize); | |
| setlength(hash,0); | |
| end; | |
| procedure passwordDecode(buffer: pbyte; buffersize: integer; pwhash: pbyte); | |
| var | |
| i: integer; | |
| begin | |
| for i:=0 to buffersize-1 do | |
| buffer[i]:=buffer[i] xor pwhash[i]; | |
| end; | |
| procedure signTable(cheattable: TDOMElement); | |
| var | |
| f: tfilestream; | |
| od: TOpenDialog; | |
| s: ntstatus; | |
| hAlgoritm: BCRYPT_ALG_HANDLE=0; | |
| hashAlgoritm: BCRYPT_ALG_HANDLE=0; | |
| hkey: BCRYPT_KEY_HANDLE=0; | |
| hHash: BCRYPT_HASH_HANDLE=0; | |
| m: tmemorystream=nil; | |
| publicdata: tmemorystream=nil; | |
| cheattablecontents: TMemorystream=nil; | |
| x: dword; | |
| publicsectionsize: integer; | |
| size: dword; | |
| objectlength: dword; | |
| bHashObject: pointer=nil; | |
| hashlength: integer; | |
| hashbuffer: pointer=nil; | |
| signsize,signsize2: integer; | |
| signedbuffer: pointer=nil; | |
| signature: TDOMNode; | |
| signedhash: TDOMNode; | |
| publickey: TDOMNode; | |
| doc: TDOMDocument; | |
| xx: TDOMNode; | |
| tempstr: pchar=nil; | |
| sigversion: word; | |
| password: string; | |
| pwhash: pbyte; | |
| pwhashlength: integer; | |
| begin | |
| if not initialize_bCrypt then | |
| raise exception.create(rsBcryptCouldNotBeUsed); | |
| doc:=cheattable.OwnerDocument; | |
| //get the private key from the signature file | |
| if FileExists(GetCEDir+'mysignature.cesig') then | |
| pathtosigfile:=encodepointer(strnew(pchar(GetCEDir+'mysignature.cesig'))); | |
| if (pathtosigfile=nil) or (not FileExists(pchar(decodepointer(pathtosigfile)))) then | |
| begin | |
| od:=TOpenDialog.Create(nil); | |
| try | |
| od.Title:=rsSelectYourCheatEngineSignatureFile; | |
| od.Filter:=rsCheatEngineSignatureFiles+'|*.CESIG'; | |
| od.Options:=od.Options+[ofFileMustExist, ofDontAddToRecent]; | |
| if od.execute then | |
| pathtosigfile:=encodepointer(strnew(pchar(od.FileName))) | |
| else | |
| exit; | |
| finally | |
| od.free; | |
| end; | |
| end; | |
| try | |
| s:=BCryptOpenAlgorithmProvider(hAlgoritm, 'ECDSA_P521', nil, 0); | |
| if not succeeded(s) then raise exception.create(rsCouldNotOpenTheAlgorithmProvider); | |
| m:=tmemorystream.create(); | |
| m.LoadFromFile(pchar(decodepointer(pathtosigfile))); | |
| x:=m.ReadDWord; //customstring length | |
| m.position:=m.position+x; //string | |
| x:=m.ReadWord; //public key size (140) | |
| sigversion:=m.ReadWord; //version | |
| password:=''; | |
| pwhash:=nil; | |
| if sigversion>=2 then | |
| begin | |
| if (passwordhash=nil) or formsettings.cbAlwaysAskForPassword.checked then | |
| begin | |
| if passwordhash<>nil then | |
| begin | |
| freemem(decodepointer(passwordhash)); | |
| passwordhash:=nil; | |
| end; | |
| if InputQuery('CE Signature', 'Enter your password', true, password)=false then exit; | |
| getPasswordHash(password, pwhash, pwhashlength, m.size-m.position); | |
| end | |
| else | |
| begin | |
| pwhash:=decodepointer(passwordhash); | |
| pwhashlength:=passwordhashlength; | |
| end; | |
| passwordhash:=nil; //in case it's wrong/changed | |
| if pwhash<>nil then | |
| passwordDecode(pointer(ptruint(m.memory)+m.position), m.size-m.position, pwhash); | |
| end; | |
| try | |
| m.position:=m.position+x; //public key | |
| if sigversion>=1 then | |
| begin | |
| x:=m.ReadByte; | |
| if x<>0 then | |
| begin | |
| x:=m.readdword; //image size | |
| m.position:=m.position+x //skip the image | |
| end; | |
| end; | |
| x:=m.ReadDWord; //signature size | |
| m.position:=m.position+x; //signature describing the custom string+image and public key | |
| publicsectionsize:=m.position; | |
| x:=m.readdword; //private key size | |
| s:=BCryptImportKeyPair(hAlgoritm, 0, BCRYPT_ECCPRIVATE_BLOB, hKey, pointer(ptruint(m.memory)+m.position), x, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToLoadPrivateKey); | |
| publicdata:=tmemorystream.create; | |
| m.position:=0; | |
| publicdata.CopyFrom(m,publicsectionsize); | |
| FillMemory(m.memory,m.size,$ce); | |
| freeandnil(m); | |
| //get the hashless version of this table | |
| cheattablecontents:=TMemoryStream.create; | |
| getXmlfileWithoutSignature(cheattable, cheattablecontents); | |
| //showmessage(pchar(cheattablecontents.Memory)); | |
| //generate a hash based on it | |
| s:=BCryptOpenAlgorithmProvider(hashAlgoritm, 'SHA512', nil, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedCreatingHasAlgorithmProvider); | |
| objectlength:=0; | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_OBJECT_LENGTH, @objectlength, sizeof(DWORD), size, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedGettingTheObjectLength); | |
| getmem(bHashObject, objectlength); | |
| zeromemory(bHashObject, objectlength); | |
| hHash:=0; | |
| s:=BCryptCreateHash(hashAlgoritm, hHash, bHashObject, objectlength, nil, 0, 0); | |
| if not Succeeded(s) then raise exception.create(rsFailedCreatingHash); | |
| s:=BCryptHashData(hHash, cheattablecontents.Memory, cheattablecontents.size, 0); | |
| if not Succeeded(s) then raise exception.create(rsFailedHashingTable); | |
| freeandnil(cheattablecontents); | |
| s:=BCryptGetProperty(hashAlgoritm, BCRYPT_HASH_LENGTH, @hashlength, sizeof(DWORD), size, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToGetHashlength); | |
| getmem(hashbuffer, hashlength); | |
| s:=BCryptFinishHash(hHash, hashbuffer, hashlength, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToFinishTheHash); | |
| //sign that hash with hKey and add it to the table | |
| signsize:=0; | |
| s:=BCryptSignHash(hKey, nil, hashbuffer, hashlength, nil, 0, @signsize, 0); | |
| if not succeeded(s) then raise exception.create(rsFailedToGetSignatureSize); | |
| getmem(signedbuffer, signsize); | |
| signsize2:=0; | |
| ZeroMemory(signedbuffer, signsize); | |
| s:=BCryptSignHash(hKey, nil, hashbuffer, hashlength, signedbuffer, signsize, @signsize2, 0); | |
| if not succeeded(s) then raise exception.create('Failed to sign the hash'); | |
| signature:=CheatTable.AppendChild(doc.CreateElement('Signature')); | |
| signedhash:=Signature.AppendChild(doc.CreateElement('SignedHash')); | |
| getmem(tempstr, (signsize2 div 4) * 5 + 5 ); | |
| BinToBase85(signedbuffer, tempstr,signsize2); | |
| signedhash.TextContent:=tempstr; | |
| TDOMElement(signedhash).SetAttribute('HashSize',IntToStr(signsize2)); | |
| freemem(tempstr); | |
| tempstr:=nil; | |
| //and add the public key to the table as well | |
| publickey:=Signature.AppendChild(doc.CreateElement('PublicKey')); | |
| getmem(tempstr, (publicdata.Size div 4) * 5 + 5 ); | |
| BinToBase85(publicdata.Memory, tempstr,publicdata.Size); | |
| publickey.TextContent:=tempstr; | |
| TDOMElement(publickey).SetAttribute('Size',IntToStr(publicdata.Size)); | |
| freemem(tempstr); | |
| tempstr:=nil; | |
| if pwhash<>nil then | |
| begin | |
| if not formsettings.cbAlwaysAskForPassword.checked then | |
| begin | |
| passwordhash:=encodepointer(pwhash); //so it's not needed to ask again | |
| passwordhashlength:=pwhashlength; | |
| end | |
| else | |
| freemem(pwhash); | |
| end; | |
| except | |
| on e:exception do | |
| if pwhash<>nil then | |
| raise exception.create(e.Message+#13#10+'('+rsIsPasswordCorrect+')') | |
| else | |
| raise; | |
| end; | |
| finally | |
| if m<>nil then | |
| begin | |
| FillMemory(m.memory,m.size,$ce); | |
| freeandnil(m); | |
| end; | |
| if publicdata<>nil then publicdata.free; | |
| if hkey<>0 then BCryptDestroyKey(hkey); | |
| if hAlgoritm<>0 then BCryptCloseAlgorithmProvider(hAlgoritm,0); | |
| if hHash<>0 then BCryptDestroyHash(hHash); | |
| if hashAlgoritm<>0 then BCryptCloseAlgorithmProvider(hashAlgoritm,0); | |
| if cheattablecontents<>nil then | |
| freeandnil(cheattablecontents); | |
| if bhashobject<>nil then | |
| freemem(bHashObject); | |
| if hashbuffer<>nil then | |
| freemem(hashbuffer); | |
| if signedbuffer<>nil then | |
| freemem(signedbuffer); | |
| if tempstr<>nil then | |
| freeandnil(tempstr); | |
| end; | |
| end; | |
| var k32: HMODULE; | |
| initialization | |
| k32:=GetModuleHandle('kernel32.dll'); | |
| pointer(encodepointer):=GetProcAddress(k32,'EncodePointer'); | |
| pointer(decodepointer):=GetProcAddress(k32,'DecodePointer'); | |
| if not assigned(encodepointer) then | |
| (encodepointer):=@EncodePointerNI; | |
| if not assigned(decodepointer) then | |
| (decodepointer):=@DecodePointerNI; | |
| end. | |