Home > Archive > Clipper > August 2006 > RATECRYPT() Version 1.3 included below
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
RATECRYPT() Version 1.3 included below
|
|
| Mel Smith 2006-08-19, 6:55 pm |
| Bill & Others:
Version 1.3 of Ratecrypt is included below:
This version uses your 'nifty' pseudo-random generator technique.
What I did was copy your one line 'encrypter', modify a few variables
and defines.
then place it in my RateCrypt() function.
I did a test on 2057 employees with their widely varying Rates and
Employee Numbers using
my year 2000 IBM Aptiva Win98se machine (600MHz).
Results: The complete conversion from encrypting a record's Rate
field to an encrypted field (NuRate), then immediately decrypting that same
record from the decrypted NuRate field back into the Rate field took .44
seconds
The lowest encrypted Rate was $559.67, the highest was
$983.85.
Of the 2057 records, I had 59 records that had duplicate
Encrypted Rates.
Anyway, thanks for all the work !
-Mel Smith
(watch out for Word Wrap below)
---------------------- Version 1.3 of RateCrypt() below ---------------
FUNCTION RATECRYPT(cCRYPT,nRATE,cEMPNUM)
// Author: Mel Smith, Aug 17, 2006
// With Lots of Help from the Guys on the c.l.g newsgroup
// Especially: Bill Robertson
// Aug 18/06 -- Version 1.2
// 1. Removed Duplicate Code / Re-structured
// 2. Changed NUROUND() to standard ROUND()
// (Thanks to BillRobertson)
// 3. Changed the nMININC 'define' to lessen 'loops'
// (But would like to find a way to eliminate this step)
// Aug 19/06 -- Version 1.3
// 1. Bill provided a better encrypting algorithm.
// 2. I made slight mods to this algo and
placed it as one computation below.
// 3. Works great and eliminates the obnoxious loop that
// was used to set Min and Max return values from the encrypter
// That is, the 'loops' problem noted above is now gone !
/*
My wish with this function is to create an encrypted rate which will
'fit' in the same field as the actual rate, but will have a value
that will be obvious (to my function) as either encrypted (or actual).
Thus, this function allows the programmer to 'obscure' an employee's
hourly
Rate from casual viewing (using database viewing software) by his peers.
The technique uses a pseudo Random Number generator copied/modified
from NanForum's rand1.prg, but then modified by Bill Robertson
The mods include using the '%' operator (instead of the MOD() function),
and later including an organization's own code (nORGCODE) to
differentiate
it from other orgs who would also use this function.
I also have to deal with variously-structured 'Employee Numbers' which
require some extra coding below. *My* Employee numbers are (for now)
either, for example, 'R1234' or '59028'. So I have to use either
*all* digits or the right-most 4 digits.
*/
#define nB 31415621 // Good old 'PI' is used here
#define nM 100000000 // The widest possible range of values
#define nMIN 60000 // Minimum returned value from encryption
#define nMAX 99999 // Maximum returned value from encryption
#define nDIFF nMAX-nMIN // The nDIFF definition is used below
#define nMININC 10000 // To 'boost' the nCODEBASE to within limits
#define nORGCODE 1234 // Choose Your own private org's code here --
NEVER CHANGE !
#define nMINLENEMP 5 // Minimum input allowable length of employee
number
#define nMINCODERATE 400 // Any value > nMINCODERATE is already encrypted
LOCAL nEMPVAL,nCODEBASE,nCODERATE,cDIGSTR,nDEC
RYPRATE
GABORT := .T. // Global 'Abort' indicator for Calling routine
// Assume failure at the outset
IF EMPTY(nRATE) // I won't encrypt a 'zero' Rate
RETURN nRATE
ENDIF
cEMPNUM := ALLTRIM(cEMPNUM)
IF EMPTY(cEMPNUM) .OR. LEN(cEMPNUM) < nMINLENEMP // Faulty Employee Number
RETURN nRATE
ENDIF
// Try to use *both* the n-digit Employee Numbers and also
// the letter + (n-1)-digit Employee Numbers used by other related orgs.
IF ISDIGIT(cEMPNUM) // THEN WE CAN USE ALL n DIGITS
nEMPVAL := VAL(cEMPNUM)
ELSE // ELSE ONLY USE THE RIGHT-MOST n-1 DIGITS
IF .NOT. ISDIGIT(cDIGSTR:=SUBSTR(cEMPNUM,2,10)) // THEN WE HAVE A
NON-CONFORMING EMPNUM
RETURN nRATE
ENDIF
nEMPVAL := VAL(cDIGSTR)
ENDIF
// Testing Bill Robertson's formula below
// Aug 19/06 -- It now returns an integer
nCODEBASE := Int(nMIN+(nMAX-nMIN)*(((nORGCODE+nEMPVAL)*nB+1)%nM)/nM)
cCRYPT := ALLTRIM(UPPER(cCRYPT))
IF cCRYPT == "E" // Means to 'E'ncrypt
IF nRATE > nMINCODERATE // Already encrypted
RETURN nRATE // It is 'already' encrypted -- a Programming Fault
:((
ENDIF
nCODERATE := ROUND((nCODEBASE*.01) - nRATE,2) // and establish the Coded
Rate
GABORT := .F. // Signal globally that this encryption worked.
RETURN nCODERATE // and Return this Coded Rate
ELSEIF cCRYPT="D" // MEANS 'D'ecrypt
IF nRATE <= nMINCODERATE // Already decrypted
RETURN nRATE // It is 'already' decrypted -- a Programming Fault
:((
ENDIF
nDECRYPRATE := ROUND(ABS(nRATE - (nCODEBASE*.01)),2) // and set Coded
Rate
GABORT := .F. // Signal globally that this encryption worked.
RETURN nDECRYPRATE // and Return this Coded Rate
ENDIF
GABORT := .T.
RETURN nRATE
| |
| bill robertson 2006-08-19, 6:55 pm |
| Mel Smith wrote:
> Bill & Others:
>
> The lowest encrypted Rate was $559.67, the highest was $983.85.
>
Does that means the the lowest plain rate was about 16.14 and the
highest about 40.33. Where do I apply for the 40.33?
> Of the 2057 records, I had 59 records that had duplicate
> Encrypted Rates.
Most of these duplicate rates also have the same unencrypted rates. You
divide the 60-100K by 100 to get numbers in the 600-999.99 range. That
makes it 100 times more likely that you will get duplicates than if you
left the range 60,000-99,999. I understand that you have to use the same
field length as before so it may not be possible to make the values this
large.
I took the routine I sent you and generated 250,000 random rates between
10.00 & 40.00. I looked at the total number of duplicates and within
these duplicates the number of duplicate encrypted values with the same
plain value.
I got the following pairs (91,79), (75,66), (88,72) & (85,64). I used
"true" random numbers for the rates which is why each run is different.
This shows that most of the duplicate encrypted values are also
duplicate plain values. Also note that that they are about the expected
2 orders of magnitude less duplicates than your duplicate encrypted
rates because I used 2 orders of magnitude greater values. I point this
out only to show that you can lower your duplicates per 2057 records if
you aren't satisfied with the 59/2057 to about 1 in 2057 if you change
your field size. I don't think it's a serious risk because what can you
do with the rate anyway?
>
> #define nB 31415621 // Good old 'PI' is used here
Pi is actually 3.1415926535... so I'm not sure why the original nanforum
routine used this value. It's strange but I used 31415926 and got a
slightly stronger encryption algorithm: getting the following pairs:
(71,58), (68,59), (69,57), (66,58).
| |
| Mel Smith 2006-08-19, 9:55 pm |
| Bill said:
> your field size. I don't think it's a serious risk because what can you
> do with the rate anyway?
>
Bill:
I wasn't complaining -- because in my 2057 actual records, there are
*many more* actual duplicate rates than encrypted Rates !
This is because many tradesmen have *identical* actual Rates. When I
encrypt them there are many fewer identical encrypted rates than identical
actual rates.
Anyway, thanks for the encryption algorithm !
My next task is to create a SINCrypt() function (for Social Insurance
Number), then DateCRYPT() for birth dates. But I'm going to leave those
tasks for now ,and concentrate on the implementation problems for
RateCrypt() first. And there are *many* probs in simultaneously doing the
conversion over all the five major apps where the Employee's Rates are read,
used, exported, changed, etc. Unfortunately, I can't do this conversion a
step-at-a-time. Lots of fun ahead !
Thanks again !
-Mel Smith
| |
| bill robertson 2006-08-20, 3:55 am |
| Mel Smith wrote:
> I wasn't complaining -- because in my 2057 actual records, there are
> *many more* actual duplicate rates than encrypted Rates !
I suspected there couldn't possible be that many different wage rates.
The encrypted rate doesn't depend on the wages anyway; just the
encrypted employee number. Subtracting the wages from the encrypted
employee number was what I found interesting in your procedure. If I had
to encrypte a rate, encrypting something else wouldn't have occured to me.
I'm not sure if you realize that your procedure is self decrypting like
the xor function. The math is just simple algebra. If eRate is the
encrypted rate, Rate is the plaintext rate and empCrypt is the encrypted
employee number then:
eRate = empCrypt - Rate (encrypts)
Rate = empCrypt - eRate (decrypts)
The Social Insurance Number is the most important to encrypt. I assume
that it's a character field 9 characters wide. If so, it can be
encrypted using 64bit DES/AES which would make it very secure. I think
Canada uses the LUHN-10 algorithm for error control. This means that you
only have 8 characters in the SIN but if you use a character field you
can store 0-0xFF in each character position.
You shouldn't use just numbers for the encrypted SIN as it severly
limits the security. The first digit of the SIN encodes location, digits
2-3 encode registration date, etc. Like the IP address system, many
(30+%, over 30 million) of the SIN numbers are reserved which is a nice
way of saying wasted.
The LUHN-10 which is used for error control and the interdependancy of
the real 8 digit SIN number makes it extremely easy to break the code if
you have a few records. If you do plan to store only numbers, verify the
real SIN number and use the leftmost 8 digits ignoring the check digit.
Encode the valid 8 digit SIN number and create a valid check digit using
LUHN-10. The encoded SIN number is now a valid LUHN-10 which should
delay knowing it's encrypted. To decode, use the leftmost encoded SIN
and calculate the check digit using LUHN-10. This should keep the SIN
safe from the casual hacker.
Alex Strickland has posted TEA (Tiny Encryption Algorithm) port to
clipper. Klas Engwall has ported blowfish to Clipper. The links are in
this newsgroup. I have downloaded both and expect to compile them soon.
I have used Alex Kreskin's adaption of Bruce Schneier's blowfish.c
routine in xHarbour. It is easy to use but note that the encryped data
is wider than the plaintext data. Since it's a 64 bit block cipher it
must allocate in chucks of 8 bytes. Each block can hold 8 characters but
there is a 2 character overhead. One block can hold 6 characters, 2
blocks hold 14 characters, n-blocks = 8n-2.
| |
| Mel Smith 2006-08-21, 6:55 pm |
| Bill said:
> I suspected there couldn't possible be that many different wage rates.
> The encrypted rate doesn't depend on the wages anyway; just the
> encrypted employee number. Subtracting the wages from the encrypted
> employee number was what I found interesting in your procedure. If I had
> to encrypte a rate, encrypting something else wouldn't have occured to me.
>
> I'm not sure if you realize that your procedure is self decrypting like
> the xor function. The math is just simple algebra. If eRate is the
> encrypted rate, Rate is the plaintext rate and empCrypt is the encrypted
> employee number then:
> eRate = empCrypt - Rate (encrypts)
> Rate = empCrypt - eRate (decrypts)
>
> The Social Insurance Number is the most important to encrypt. I assume
> that it's a character field 9 characters wide. If so, it can be
> encrypted using 64bit DES/AES which would make it very secure. I think
> Canada uses the LUHN-10 algorithm for error control. This means that you
> only have 8 characters in the SIN but if you use a character field you
> can store 0-0xFF in each character position.
Yesterday, (Sunday) I spent an hour or so 'googling' for SIN Authentication
and found the following site:
http://en.wikipedia.org/wiki/Social_Insurance_Number.
This site (and others) did mention the LUHN-10 algorithm but did not
mention the existence of a 'Check Digit' or its position in the string of
nine characters.
I have, in the past, done a lot of work with HealthCare Numbers in my
province of Alberta, Canada. This number is callled here a ULI (Unique
Lifetime Identifier). It *also* has nine digits but the 'check-digit' is in
the *fifth* position -- not the ninth as you stated for the SIN.
>
> You shouldn't use just numbers for the encrypted SIN as it severly
> limits the security. The first digit of the SIN encodes location, digits
> 2-3 encode registration date, etc. Like the IP address system, many
> (30+%, over 30 million) of the SIN numbers are reserved which is a nice
> way of saying wasted.
>
Right, I intend to use a mix of characters, as long as I can easily
re-capture the 'Original SIN' -- pun intended.
> The LUHN-10 which is used for error control and the interdependancy of
> the real 8 digit SIN number makes it extremely easy to break the code if
> you have a few records. If you do plan to store only numbers, verify the
> real SIN number and use the leftmost 8 digits ignoring the check digit.
> Encode the valid 8 digit SIN number and create a valid check digit using
> LUHN-10. The encoded SIN number is now a valid LUHN-10 which should
> delay knowing it's encrypted. To decode, use the leftmost encoded SIN
> and calculate the check digit using LUHN-10. This should keep the SIN
> safe from the casual hacker.
But, after reading the above, maybe I *will* stick to digits. Puzzle,
puzzle .... ???
I wish to have a *false* SIN that *looks* like a real SIN but *fails*
authentication !
> Alex Strickland has posted TEA (Tiny Encryption Algorithm) port to
> clipper. Klas Engwall has ported blowfish to Clipper. The links are in
> this newsgroup. I have downloaded both and expect to compile them soon.
> I have used Alex Kreskin's adaption of Bruce Schneier's blowfish.c
> routine in xHarbour. It is easy to use but note that the encryped data
> is wider than the plaintext data. Since it's a 64 bit block cipher it
> must allocate in chucks of 8 bytes. Each block can hold 8 characters but
> there is a 2 character overhead. One block can hold 6 characters, 2
> blocks hold 14 characters, n-blocks = 8n-2.
Interesting !
Thanks again for all the help
-Mel Smith
|
|
|
|
|