Anybody who has wished to encrypt data within a UNIFACE application has probably given up any attempt to write it in UNIFACE and has opted instead for a 3GL solution. This is OK if you have access to suitable 3GL resources, but not everybody does. I have often wondered if it was possible to write any sort of encryption routine within UNIFACE, and after a bit of trial and error I have eventually succeeded. You may find my efforts to be of some use to you.
The second way is to apply another 'fudge factor' to the index number before using it to extract from STRING2. You can add another number to the list obtained from the key. A method contained in my source code is to accumulate all the key numbers and put this total at the start of the list. Another method is to change each key number before it is put back at the end of the list, such as making it negative if it is divisible by 3, or simply adding 1.5 each time. The possible permutations are countless.
The important thing is that the same combination of user id and password will always yield the same encrypted value, but that a hacker will have his work cut out to break the code (I hope!).
Here is a screen shot of the sample program:
In this example the password field has been padded out to its maximum length (16 bytes) with trailing spaces. Note that each of these trailing spaces has been converted to a different character.
The sample source code contained in my web site includes routines for both encryption and decryption. Try it for yourself and see. For those of you who are too lazy to download the source code here it is:
entry ENCRYPT params string pi_UserKey : IN string pio_Target : INOUT endparams variables string lv_Source string lv_Char1 numeric lv_Num1 string lv_Char2 numeric lv_Num2 numeric lv_KeyNum numeric lv_Factor numeric lv_ScrambleLen endvariables NOTE: the local constants are defined as follows: <SCRAMBLE1> =! %%"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz <SCRAMBLE2> =&q13`h5w_79f^jAE]okI\OzU[24p@6s8?BgP>dFV=m D<TcS%Zer:lGK/uCy.JLt-RMa,NvW+Ynb*0Xx)HiQ!%%"#$'(; End note $Scramble1$ = "<SCRAMBLE1>" ; see note above $Scramble2$ = "<SCRAMBLE2>" ; see note above length $Scramble1$ lv_ScrambleLen = $result ; store length of string length $Scramble2$ if ($result != lv_ScrambleLen) message "$scramble1$ not same length as $scramble2$" return(-1) endif ; convert UserKey into a sequence of numbers call LP_CONV_USERKEY(pi_UserKey,$FactorList$) if ($status) return($status) lv_Source = pio_Target ; copy pio_Target = "" ; initialise while (lv_Source != "") lv_Char1 = lv_Source[1:1] ; extract 1st character lv_Source = lv_Source[2] ; drop 1st character scan $Scramble1$,lv_Char1 ; find char in $Scramble1$ if ($result = 0) message "cannot find '%%lv_Char1' in $scramble1$" return(-1) endif lv_Num1 = $result call LP_GET_KEYNUM(lv_KeyNum) ; from $FactorList$ lv_Factor = lv_Factor + lv_KeyNum ; add to factor lv_Num2 = lv_Num1 + lv_Factor ; apply adjustment call LP_CHECK_RANGE(lv_Num2,lv_ScrambleLen) ; ensure it's within range lv_Factor = lv_Factor + lv_Num2 ; add to factor lv_Char2 = $Scramble2$[lv_Num2:1] ; extract new character pio_Target = "%%pio_Target%%lv_Char2" ; append to target endwhile return(0) end ENCRYPT ;============================================================================== entry LP_CONV_USERKEY ; convert key into a list of numbers params string pi_UserKey : IN string po_ListOfNumbers : OUT endparams variables string lv_Char numeric lv_Length numeric lv_Total endvariables if (pi_UserKey = "") message "Key for encryption/decryption is empty" return(-1) endif po_ListOfNumbers = "" ; initialise output putitem po_ListOfNumbers, 1, "0" ; reserve 1st number in list length pi_UserKey ; get length of input string lv_Length = $result ; convert string into a sequence of numbers while (pi_UserKey != "") lv_Char = pi_UserKey[1:1] ; extract 1st character pi_UserKey = pi_UserKey[2] ; remove 1st character ; find this char's position in $Scramble1$ and add to output list scan $Scramble1$,lv_Char if ($result > 0) putitem po_ListOfNumbers, -1, $result lv_Total = lv_Total + $result ; accumulate values else ; character not found! ignore it (should never happen!) endif endwhile lv_Total = lv_Total - lv_Length ; subtract number of characters putitem po_ListOfNumbers, 1, lv_Total ; 1st number is grand total return(0) end LP_CONV_USERKEY ;============================================================================== entry LP_GET_KEYNUM ; get index number from $factorlist$ params numeric po_KeyNum : OUT endparams variables numeric lv_KeyNum endvariables ; pass back the first number from $FactorList$ (whole numbers only) getitem lv_KeyNum, $FactorList$, 1 ; get 1st number po_KeyNum = lv_KeyNum[round] ; return the value rounded if (po_KeyNum%3 = 0) ; if it is divisible by 3 po_KeyNum = po_KeyNum * -1 ; make it negative endif ; Note that the number is adjusted before being put back into the list. ; Decimal places are allowed in the adjustment as they are rounded before ; being returned to the calling module. ; This produces an irregular effect to further confuse any hacker. delitem $FactorList$, 1 ; drop from front of list lv_KeyNum = lv_KeyNum + 1.75 ; change it putitem $FactorList$, -1, lv_KeyNum ; put back at end of list end LP_GET_KEYNUM ;============================================================================== entry LP_CHECK_RANGE ; check that number is within range ; (not < 1, not > limit) params numeric pio_Number : INOUT numeric pi_Limit : IN endparams pio_Number = pio_Number[round] ; must be a whole nunmber while (pio_Number > pi_Limit) ; test for above range pio_Number = pio_Number - pi_Limit endwhile while (pio_Number < 1) ; test for below range pio_Number = pio_Number + pi_Limit endwhile end LP_CHECK_RANGE ;============================================================================== entry DECRYPT params string pi_UserKey : IN string pio_Target : INOUT endparams variables string lv_Source string lv_Char1 numeric lv_Num1 string lv_Char2 numeric lv_Num2 numeric lv_KeyNum numeric lv_Factor numeric lv_ScrambleLen endvariables $Scramble1$ = "<SCRAMBLE1>" ; see note above $Scramble2$ = "<SCRAMBLE2>" ; see note above length $Scramble1$ lv_ScrambleLen = $result ; store length of string length $Scramble2$ if ($result != lv_ScrambleLen) message "$scramble1$ not same length as $scramble2$" return(-1) endif ; convert UserKey into a sequence of numbers call LP_CONV_USERKEY(pi_UserKey,$FactorList$) if ($status) return($status) length $Scramble1$ lv_ScrambleLen = $result ; store length of string lv_Source = pio_Target ; copy pio_Target = "" ; initialise while (lv_Source != "") lv_Char2 = lv_Source[1:1] ; extract 1st character lv_Source = lv_Source[2] ; drop 1st character scan $Scramble2$,lv_Char2 ; find char in $Scramble2$ if ($result = 0) message "cannot find '%%lv_Char2' in $scramble2$" return(-1) endif lv_Num2 = $result call LP_GET_KEYNUM(lv_KeyNum) ; from $FactorList$ lv_Factor = lv_Factor - lv_KeyNum ; subtract from factor lv_Num1 = lv_Num2 + lv_Factor ; apply adjustment call LP_CHECK_RANGE(lv_Num1,lv_ScrambleLen) ; ensure it's within range lv_Factor = lv_Factor - lv_Num2 ; subtract from factor lv_Char1 = $Scramble1$[lv_Num1:1] ; extract new character pio_Target = "%%pio_Target%%lv_Char1" ; append to target endwhile ; remove trailing spaces from output string length pio_Target lv_Num1 = $result while (pio_Target[lv_Num1:1] = " ") ; if last char is a space lv_Num1 = lv_Num1 - 1 pio_Target = pio_Target[1:lv_Num1] ; remove it endwhile return(0) end DECRYPT
Tony Marston
10th July 2000
mailto:tony@tonymarston.net
mailto:TonyMarston@hotmail.com
http://www.tonymarston.net