FUNCTION bitXOR RETURNS INTEGER (INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
DO n = 1 TO 32:
ASSIGN
b1 = GET-BITS(X, n, 1)
b2 = GET-BITS(Y, n, 1)
.
IF b1 + b2 = 1 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
function RC4 RETURNS character (input pInput as character, input pKey as character):
DEFINE VARIABLE cResult AS CHARACTER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE x AS INTEGER NO-UNDO.
DEFINE VARIABLE y AS INTEGER NO-UNDO.
DEFINE VARIABLE box AS INTEGER EXTENT 256 NO-UNDO.
DEFINE VARIABLE keyLen AS INTEGER NO-UNDO.
DEFINE VARIABLE inputLen AS INTEGER NO-UNDO.
DEFINE VARIABLE boxIndex AS INTEGER NO-UNDO.
cResult = "".
keyLen = LENGTH(pKey).
inputLen = LENGTH(pInput).
/* Initialize the box */
DO i = 1 TO 256:
box[i ] = i.
END.
/* Key-scheduling algorithm */
DO i = 1 TO 255:
j = (ASC(SUBSTRING(pKey, (i MOD keyLen) + 1, 1)) + box[i + 1] + j) MOD 256.
x = box[i + 1].
box[i + 1] = box[j + 1].
box[j + 1] = x.
END.
/* Pseudo-random generation algorithm */
DO i = 0 TO inputLen - 1 :
y = i MOD 256.
j = (box[y + 1] + j) MOD 256.
x = box[y + 1].
box[y + 1] = box[j + 1].
box[j + 1] = x.
cResult = cResult + CHR(bitXOR( ASC(SUBSTRING(pInput, i + 1, 1)) , box[(box[y + 1 ] + box[j + 1]) MOD 256])).
END.
RETURN cResult.
end function.
def var encptString as character no-undo.
assign encptString = "Decryption in RC4 is essentially the same process as encryption".
message "Input:" encptString.
encptString = RC4(input encptString, input "1234").
message "Scrambled:" encptString.
encptString = RC4(input encptString, input "1234").
message "Unscrambled:" encptString.
FUNCTION bitXOR RETURNS INTEGER (INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b1 AS INTEGER NO-UNDO.
DEFINE VARIABLE b2 AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INTEGER NO-UNDO.
DO n = 1 TO 32:
ASSIGN
b1 = GET-BITS(X, n, 1)
b2 = GET-BITS(Y, n, 1)
.
IF b1 + b2 = 1 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
FUNCTION bitAnd returns integer ( input X as integer, input Y as integer):
define variable b as integer no-undo.
define variable n as integer no-undo.
define variable Z as integer no-undo.
do n = 1 to 32:
if get-bits(X, n, 1) = 1 and get-bits(Y, n, 1) = 1 then
b = 1.
PUT-BITS(Z, n, 1) = b.
b = 0.
end.
return Z.
end FUNCTION.
function RC4 RETURNS character (input pInput as character, input pKey as character):
DEFINE VARIABLE cResult AS CHARACTER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE x AS INTEGER NO-UNDO.
DEFINE VARIABLE y AS INTEGER NO-UNDO.
DEFINE VARIABLE box AS INTEGER EXTENT 256 NO-UNDO.
DEFINE VARIABLE keyLen AS INTEGER NO-UNDO.
DEFINE VARIABLE inputLen AS INTEGER NO-UNDO.
DEFINE VARIABLE boxIndex AS INTEGER NO-UNDO.
DEFINE VARIABLE iByte AS INTEGER NO-UNDO.
cResult = "".
keyLen = LENGTH(pKey).
inputLen = LENGTH(pInput).
/* Initialize the box */
DO i = 1 TO 256:
box[i] = (i - 1).
END.
/* Key-scheduling algorithm */
DO i = 0 TO 255:
j = (ASC( SUBSTRING(pKey, ((i + 1) MOD keyLen) + 1, 1)) + box[i + 1] + j) MOD 256.
x = box[i + 1].
box[i + 1] = box[j + 1].
box[j + 1] = x.
END.
/* Pseudo-random generation algorithm */
DO i = 0 TO inputLen - 1 :
y = i MOD 256.
j = (box[y + 1] + j) MOD 256.
x = box[y + 1].
box[y + 1] = box[j + 1].
box[j + 1] = x.
iByte = bitXOR( ASC(SUBSTRING(pInput, i + 1, 1)) , box[(box[y + 1 ] + box[j + 1]) MOD 256]).
cResult = cResult + CHR(bitAnd(iByte, 255)).
end.
RETURN cResult.
end function.
def var encptString as character no-undo.
assign
encptString = "Decryption in RC4 is essentially the same process as encryption. Decryption in RC4 is essentially the same process as encryption Decryption in RC4 is essentially the same process as encryption. Decryption in RC4 is essentially the same process as encryption".
message "Input:" encptString.
encptString = RC4(input encptString, input "1234").
message "Scrambled:" encptString.
encptString = RC4(input encptString, input "1234").
message "Unscrambled:" encptString.
/* RC4 Encryption/Decryption Function in Progress ABL */
FUNCTION bitXOR RETURNS INT64 (INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b1 AS INT64 NO-UNDO.
DEFINE VARIABLE b2 AS INT64 NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INT64 NO-UNDO.
DO n = 1 TO 64:
ASSIGN
b1 = GET-BITS(X, n, 1)
b2 = GET-BITS(Y, n, 1)
.
IF b1 + b2 = 1 THEN PUT-BITS(Z, n, 1) = 1.
END.
RETURN Z.
END FUNCTION.
FUNCTION bitAnd RETURNS INT64 ( INPUT X AS INTEGER, INPUT Y AS INTEGER):
DEFINE VARIABLE b AS INTEGER NO-UNDO.
DEFINE VARIABLE n AS INTEGER NO-UNDO.
DEFINE VARIABLE Z AS INT64 NO-UNDO.
DO n = 1 TO 64:
IF GET-BITS(X, n, 1) = 1 AND get-bits(Y, n, 1) = 1 THEN
b = 1.
PUT-BITS(Z, n, 1) = b.
b = 0.
END.
RETURN Z.
END FUNCTION.
FUNCTION RC4 RETURNS MEMPTR
(INPUT pwd AS MEMPTR, INPUT data AS MEMPTR):
DEFINE VARIABLE a AS INTEGER NO-UNDO.
DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE VARIABLE j AS INTEGER NO-UNDO.
DEFINE VARIABLE k AS INTEGER NO-UNDO.
DEFINE VARIABLE tmp AS INTEGER NO-UNDO.
DEFINE VARIABLE key AS INTEGER EXTENT 256 NO-UNDO.
DEFINE VARIABLE box AS INTEGER EXTENT 256 NO-UNDO.
DEFINE VARIABLE dataLength AS INTEGER NO-UNDO.
DEFINE VARIABLE pwdLength AS INTEGER NO-UNDO.
DEFINE VARIABLE cipher AS MEMPTR NO-UNDO.
DEFINE VARIABLE cPtr AS INTEGER NO-UNDO. /* Pointer for MEMPTR manipulation */
/* Initialize lengths */
ASSIGN
dataLength = GET-SIZE(data)
pwdLength = GET-SIZE(pwd).
/* Allocate memory for the cipher */
SET-SIZE(cipher) = dataLength.
cPtr = 1.
/* Key-scheduling algorithm (KSA) */
DO i = 1 TO 256:
key[i] = GET-BYTE(pwd, (i - 1) MODULO pwdLength + 1).
box[i] = i - 1.
END.
j = 1.
DO i = 1 TO 256:
j = (j + box[i] + key[i]) MODULO 256 + 1.
/* Swap */
tmp = box[i].
box[i] = box[j].
box[j] = tmp.
END.
/* Pseudo-random generation algorithm (PRGA) */
a = 1.
j = 1.
DO i = 1 TO dataLength:
a = a MODULO 256 + 1.
j = (j + box[a]) MODULO 256 + 1.
/* Swap */
tmp = box[a].
box[a] = box[j].
box[j] = tmp.
k = box[(box[a] + box[j]) MODULO 256 + 1].
/* XOR the data with the generated key stream and store in cipher */
tmp = bitXOR(GET-BYTE(data, i), k).
PUT-BYTE(cipher, cPtr) = bitAnd(tmp, 255).
cPtr = cPtr + 1.
END.
RETURN cipher.
END FUNCTION.
/* Test the RC4 function */
DEFINE VARIABLE pwd AS MEMPTR NO-UNDO.
DEFINE VARIABLE data AS MEMPTR NO-UNDO.
DEFINE VARIABLE encrypted AS MEMPTR NO-UNDO.
DEFINE VARIABLE decrypted AS MEMPTR NO-UNDO.
DEFINE VARIABLE tempString AS CHARACTER NO-UNDO.
DEFINE VARIABLE passwordString AS CHARACTER NO-UNDO.
DEFINE VARIABLE dataEncryptionString AS CHARACTER NO-UNDO.
/* Alway zero out your memptrs */
SET-SIZE(pwd) = 0.
SET-SIZE(data) = 0.
SET-SIZE(encrypted) = 0.
SET-SIZE(decrypted) = 0.
ASSIGN
passwordString = "This is the private key!"
dataEncryptionString = "RC4 (also known as Rivest Cipher 4) is a form of stream cipher. It encrypts messages one byte at a time via an algorithm.~r~n~r~nPlenty of stream ciphers exist, but RC4 is among the most popular. It's simple to apply, and it works quickly, even on very large pieces of data. If you've ever used an application like TSL (transport layer security) or SSL (secure socket layer), you've probably encountered RC4 encryption.~r~n~r~nBut you may not know how it works.~r~n~r~nWe'll take a high-level approach and explain what the Rivest Cipher is in terms anyone can understand. We'll also explain why it's helpful, and we'll point out a few known limitations. EOL".
SET-SIZE(pwd) = LENGTH(passwordString).
SET-SIZE(data) = LENGTH(dataEncryptionString).
PUT-STRING(pwd, 1, LENGTH(passwordString)) = passwordString.
PUT-STRING(data, 1, LENGTH(dataEncryptionString)) = dataEncryptionString.
/* Encrypt the data */
encrypted = RC4(pwd, data).
tempString = GET-STRING(encrypted, 1) .
MESSAGE "Encrypted (HEX): " STRING(HEX-ENCODE(encrypted)) SKIP(1)
"Encrypted (TXT): " tempString
VIEW-AS ALERT-BOX INFORMATION TITLE "ABL ARC4 Encryption (Encrypted)".
/* Decrypt the data (using the same RC4 function) */
ASSIGN
decrypted = RC4(pwd, encrypted).
tempString = GET-STRING(decrypted, 1).
MESSAGE "Decrypted: " tempString VIEW-AS ALERT-BOX INFORMATION TITLE "ABL ARC4 Encryption (Decrypted)".
/* Clean up */
FINALLY:
SET-SIZE(pwd) = 0.
SET-SIZE(data) = 0.
SET-SIZE(encrypted) = 0.
SET-SIZE(decrypted) = 0.
END.
/*PUT-BYTE(cipher, cPtr) = bitAnd(tmp, 255).*/
PUT-BYTE(cipher, cPtr) = tmp.
Hi Cecil,I've tested it with a binary file (1.2MB) and to my surprise it did work. However, it was very, very slow and that just because the ABL language is just not optimal for bitwise operations.
Recommendation is to use an alternative encryption method which is supported by OpenEdge.
If you do need to continue to use the CR4 cipher work with smaller files.
I've also converted the code to be a class object and uploaded it to GitHub if anyone else is interested. ABL-RC4/src at main · Jimbobnz/ABL-RC4
Update: I don't think there is a requirement to bitAnd operation. It seems to work well without it and so it improves performance.
Code:/*PUT-BYTE(cipher, cPtr) = bitAnd(tmp, 255).*/ PUT-BYTE(cipher, cPtr) = tmp.
I've updated the code on GitHub. I've altered things a bit and made it into a ABLOO static class object. GitHub - Jimbobnz/ABL-RC4: ABL RC4 (RC4) cipherCecillllllll,
I am beyond elated! I figured out what I was doing wrong. I was saving tempstring /** tempString = GET-STRING(encrypted, 1) . **/ to a file and then importing it as binary in order to decrypt it and get the original string.
I should have been using the IMPORT/EXPORT in order to save and retrieve MEMPTRs.
Now I need to clean up my code and run the same test using multiple files. I am so glad I re-read your code. I took a break from this task and re-read your code once I got notification that you replied. I think the break did me good. I will post an update about my testing. I don't think there is an issue in your code.
Thanks again!
Liza
Thank you so much! I was over my head making the implementation complex than it should be. I ran my revised code using simple string and converting files. The results are consistent now. I will get the latest from GitHub tomorrow and work on it again. Thanks again. I need to get some sleep.I've updated the code on GitHub. I've altered things a bit and made it into a ABLOO static class object. https://github.com/Jimbobnz/ABL-RC4/
I've crossed check the output with other RC4 utilities and it encrypts/decrypts as expected.