source of the Variant 2
* Function: sha1encoder
* Description: Perform an SHA1 encoding on a text parameter
FUNCTION sha1encoder(lcMessage)
PRIVATE HO, H1, H2, H3, H4
LOCAL lnNumberOfBlocks, lnHigh, lnLow
H0 = 0x67452301
H1 = 0xEFCDAB89
H2 = 0x98BADCFE
H3 = 0x10325476
H4 = 0xC3D2E1F0
* Concatenate to the message a "1" followed by as many zeros as necessary
* to make the length a multiple of 512 with the last 8 bytes storing the length
* of the message.
lnLength = LEN(lcMessage)
* append bits 10000000
lcMessage = lcMessage + CHR(2^7)
* add as many 0 bytes as required to have message bit length a multiple of 512
* with the last 8 bytes being the number of bits in the original message.
lnRemainder = MOD(LEN(lcMessage), 64)
IF lnRemainder > 56
lcMessage = lcMessage + REPLICATE(CHR(0), (64 - lnRemainder) + 56)
ELSE
lcMessage = lcMessage + REPLICATE(CHR(0), (56 - lnRemainder))
ENDIF
lnHigh = (lnLength*8) / 2^32
lnLow = MOD(lnLength*8, 2^32)
lcMessage = lcMessage + CHR(BITAND(BITRSHIFT(lnHigh, 24), 0xFF)) ; && 56
+ CHR(BITAND(BITRSHIFT(lnHigh, 16), 0xFF)) ; && 57
+ CHR(BITAND(BITRSHIFT(lnHigh, 8), 0xFF)) ; && 58
+ CHR(BITAND(lnHigh, 0xFF)) ; && 59
+ CHR(BITAND(BITRSHIFT(lnLow, 24), 0xFF)) ; && 60
+ CHR(BITAND(BITRSHIFT(lnLow, 16), 0xFF)) ; && 61
+ CHR(BITAND(BITRSHIFT(lnLow, 8), 0xFF)) ; && 62
+ CHR(BITAND(lnLow, 0xFF)) && 63
lnNumberOfBlocks = LEN(lcMessage) / 64
LOCAL I
FOR I = 1 TO lnNumberOfBlocks
DO SHA1_ProcessBlock WITH SUBSTR(lcMessage, 1 + 64*(I-1), 64)
ENDFOR
lcDigest = SUBSTR(TRANSFORM(H0,"@0"),3) + ;
SUBSTR(TRANSFORM(H1,"@0"),3) + ;
SUBSTR(TRANSFORM(H2,"@0"),3) + ;
SUBSTR(TRANSFORM(H3,"@0"),3) + ;
SUBSTR(TRANSFORM(H4,"@0"),3)
* return the 20 character string for the 40 hex digit message digest.
lcReturnValue = ""
FOR i = 1 TO 20
lnValue = HexCharToDec(lcDigest, i * 2 - 1) * 16 + HexCharToDec(lcDigest, i * 2)
lcReturnValue = lcReturnValue + CHR(lnValue)
ENDFOR
RETURN lcReturnValue
PROCEDURE SHA1_ProcessBlock
LPARAMETERS cBlock
LOCAL I, A, B, C, D, E, nTemp
LOCAL ARRAY W(80)
* For each block of 512 bits, divide the block into 16 words of 32 bits and
* assign them to W1, W2... W16.
FOR I = 1 TO 16
W(I) = Word32Bits(BITLSHIFT(ASC(SUBSTR(cBlock, (I - 1) * 4 + 1, 1)), 24) ;
+ BITLSHIFT(ASC(SUBSTR(cBlock, (I - 1) * 4 + 2, 1)), 16) ;
+ BITLSHIFT(ASC(SUBSTR(cBlock, (I - 1) * 4 + 3, 1)), 8) ;
+ ASC(SUBSTR(cBlock, (I - 1) * 4 + 4, 1)))
ENDFOR
* For I varying from 17 to 80, one affects the W(I) words in the following way:
* W(I) = W(I-3) XOR W(I-8) XOR W(I-14) XOR W(I-16)
FOR I = 17 TO 80
W(I) = BitLRotate(1, BITXOR(W(I - 3), W(I - 8), W(I - 14), W(I - 16)))
ENDFOR
A = H0
B = H1
C = H2
D = H3
E = H4
*For I varying from 1 to 80 and with Sn a left circular shift of N bits,
* one carries out following calculations:
FOR I = 1 TO 80
nTemp = BitLRotate(5, A) + E + W(I)
DO CASE
CASE I <= 20
nTemp = nTemp + BITOR(BITAND(B, C), BITAND(BITNOT(B), D)) + 0x5A827999
CASE BETWEEN(I, 21, 40)
nTemp = nTemp + BITXOR(B, C, D) + 0x6ED9EBA1
CASE BETWEEN(I, 41, 60)
nTemp = nTemp + BITOR(BITAND(B, C), BITAND(B, D), BITAND(C, D)) + 0x8F1BBCDC
CASE I >= 61
nTemp = nTemp + BITXOR(B, C, D) + 0xCA62C1D6
ENDCASE
nTemp = Word32Bits(nTemp)
E = D
D = C
C = BitLRotate(30, B)
B = A
A = nTemp
ENDFOR
H0 = Word32Bits(H0 + A)
H1 = Word32Bits(H1 + B)
H2 = Word32Bits(H2 + C)
H3 = Word32Bits(H3 + D)
H4 = Word32Bits(H4 + E)
RETURN
FUNCTION BitLRotate(nBits, nWord)
RETURN Word32Bits(BITOR(BITLSHIFT(nWord, nBits), BITRSHIFT(nWord, (32 - nBits))))
ENDFUNC
FUNCTION Word32Bits(lnValue)
LOCAL ln32Bits
ln32Bits = BITAND(lnValue, 2^32 - 1)
DO WHILE ln32Bits < 0
ln32Bits = ln32Bits + 2^32
ENDDO
RETURN ln32Bits
ENDFUNC
FUNCTION HexCharToDec(lcString, lnPosition)
lcChar = SUBSTR(lcString,lnPosition,1)
IF BETWEEN(lcChar, '0', '9')
RETURN VAL(lcChar)
ELSE && BETWEEN(lcChar, 'A', 'F')
RETURN ASC(lcChar) - ASC('A') + 10
ENDIF
ENDFUNC