unit uccookie; (* Copyright (c) 1998-2003 HREF Tools Corp. Permission is hereby granted, on 1-Nov-2003, free of charge, to any person obtaining a copy of this file (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Author of original version of this file: Michael Ax *) // simple but effective (i hope) one way signing routine to wrap an account number // into a cookie and routines to take the cookie apart and validate it. // the goal here is to hide the account number and to keep the password from // traveling over the wire while using it to scramble/sign the account number // to put an acceptable level of security in place that should defeat most // break-in attempts. interface //scramble an account number with a password. //the result is always 16 digits long. function CookieText(Account:Integer;const PW:String):string; //extract the account number from the cookie (we obscured it in the cookie) function CookieAccount(const aCookieText:String):cardinal; //check to see is a cookietext matches the cookietext for the Account/pw provided. function CookieValid(Account:Integer;const PW,aCookieText:String):Boolean; implementation uses sysutils,ucInteg; const cSignDigit=2; //range 1..4; letter used to advance the random generator //four digits of the password at a time are used to scramble, //the ord of cSignDigit is used to spin the numbers in btwn. cFillText='P#3A'; //4 arbitrary chars used to pad the password if is less //then 4 digits long. not used when the pw is >=4 long. cPWsecond=true;//boolean to control if the password or the account number //string goes first when the interleaving happens. function CookieText(Account:Integer;const PW:String):string; var r,i,n:integer; a1:string; begin r:=randseed; randseed:=Account; a1:=pw; //make sure the pw length is a multiple of 4 n:=length(a1); if n=0 then a1:=inttostr(Account); i:=4- n mod 4; if i<4 then a1:=a1+copy(a1+cFillText,1,i); // while length(a1)>=4 do begin for i:=0 to ord(a1[cSignDigit]) do random; randseed:=randseed xor longint(pchar(a1)^); delete(a1,1,4); end; // a1:=IntToHex(Account xor RandSeed,8)+IntToHex(RandSeed,8); // (added the xor after showing the merge details below) //Account-0, pw=Edit2 --> 00000000B8A65798 //00000000B8A65798 //0 0 0 0 0 0 0 0 // B 8 A 6 5 7 9 8 //0B080A0605070908 --> 0B080A0605070908 result:=''; for i:=1 to 8 do if cPWsecond then result:=Result+copy(a1,i,1)+copy(a1,i+8,1) else result:=Result+copy(a1,i+8,1)+copy(a1,i,1); randseed:=r; end; function CookieAccount(const aCookieText:String):cardinal; var i:integer; c1,c2:cardinal; a1,a2:string; begin Result:=0; if length(aCookieText)<>16 then exit; a1:=''; a2:=''; for i:=1 to 8 do begin a1:=a1+aCookieText[i+i-1]; a2:=a2+aCookieText[i+i]; end; c1:=HexToInt(a1); c2:=HexToInt(a2); if cPWsecond then Result:=c1 xor c2 else Result:=c2 xor c1; end; function CookieValid(Account:Integer;const PW,aCookieText:String):Boolean; begin Result:=CookieText(CookieAccount(aCookieText),PW)=aCookieText; end; end.