VFP implementation of the Cipher encryption

Tagged:

This is a VFP implementation of the Cipher encryption. Cipher50 C source code and the binary is available as separate downloads File #21474 and File #9222 at http://UniversalThread.com.

Cipher was originally put into the public domain by Tom Rettig Associates in 1991 and has been re-produced by different parties as necessary for newer versions of FoxPro. Obviously, the VFP implementation is much slower than the C library and should be used for short strings, like passwords, only. The code has been tested under VFP 8.0 and VFP 9.0 but should work in previous versions. If it doesn't, feel free to modify it.

This is sample code. Add error handling and adjust to your requirements as necessary.

&&
&& Parameters:
&&   tcStr      - string to encrypt/decrypt
&&   tcPassword - password to use for encryption/decryption 
&&
&&----------encrypt.prg----------
&&
&& Alias for cipher
FUNCTION encrypt
LPARAMETERS tcStr, tcPassword
RETURN cipher(tcStr, tcPassword)
&&
&&----------decrypt.prg----------
&&
&& Alias for cipher
FUNCTION decrypt
LPARAMETERS tcStr, tcPassword
RETURN cipher(tcStr, tcPassword)
&&
&&----------cipher.prg----------
FUNCTION cipher 
LPARAMETERS tcStr, tcPassword
 
#define   PW_MIN_LEN   3		&&  /* min  number of characters in the password */
#define   PW_MIN_NUM   1000		&&  /* min value for the password seed */
 
LOCAL lnStrLen, lnPassLen, lnPassNum, laPassword[1,2], lcPassword
LOCAL lcStrOut, lnPassPos, lnNum01, lcStrOut, lnInPos, lnPassPos
 
IF TYPE("tcStr") <> "C" ;
		OR TYPE("tcPassword") <> "C" ;
		OR LEN(tcPassword) < PW_MIN_LEN
	Error 11
ENDIF
 
lnStrLen = LEN(tcStr)
 
&& Because of the bug in the original C code we've to add CHR(0) to the password and use it later
lcPassword = tcPassword + CHR(0)
lnPassLen = LEN(lcPassword)
DIMENSION laPassword[lnPassLen+1,2]
FOR lnPassPos=1 TO lnPassLen
	laPassword[lnPassPos,2] = SUBSTR(lcPassword,lnPassPos,1)
	laPassword[lnPassPos,1] = ASC(laPassword[lnPassPos,2])
ENDFOR
 
&& Get seed value
lnPassNum = INT((((CipherGetPnum(lcPassword)/997) - 1) % 254) + 1 )
lcStrOut = ""
lnPassPos = 1
 
&& Encode/decode each character
FOR lnInPos=0 TO lnStrLen-1
	&& Get new seed value
	lnNum01 = (( lnPassNum + (lnInPos - lnStrLen)) - 1)
	lnPassNum = (ABS(lnNum01) % 254) * SIGN(lnNum01) + 1
	&& Encode current character
	lnByte = BITXOR( ASC(SUBSTR(tcStr,lnInPos+1,1)), ;
		BITXOR(lnPassNum, laPassword[lnPassPos,1]))
	&& Convert signed value to unsigned, if necessary
	lnByte = BITAND(lnByte, 0xFF)
	&& If result is zero, use current character
	lcStrOut = lcStrOut + IIF(lnByte = 0, SUBSTR(tcStr,lnInPos+1,1), CHR(lnByte))
	&& Advance to the next password character
	lnPassPos = IIF( lnPassPos => lnPassLen, 1, lnPassPos + 1)
ENDFOR
 
RETURN lcStrOut
 
&& Returns a seed value based on the string passed as parameter
FUNCTION CipherGetPnum(tcStr)
LOCAL liRet, lnPos
liRet = 1
FOR lnPos=0 TO LEN(tcStr ) - 1
	liRet = liRet + ASC(SUBSTR(tcStr,lnPos+1,1)) + lnPos
ENDFOR
DO WHILE (liRet < PW_MIN_NUM)
	liRet = BITLSHIFT(liRet,1)
ENDDO
RETURN liRet