Added to A-Shell, August 2016
xcall BLOFSH, opcode(=1), impure, key
xcall BLOFSH, opcode(=2), impure, cleartext, ciphertext
xcall BLOFSH, opcode(=3), impure, ciphertext, cleartext
BLOFSH.SBR implements the Blowfish encryption algorithm. It is used to encrypt or decrypt data in memory using a variable length key of 32 to 448 bits.
Blowfish is a symmetric-key block cipher, designed in 1993 by Bruce Schneier and made available to the world for royalty-free use. See the Blowfish entry at Wikipedia for more information.
opcode (Num) [in]
1 to load the key, 2 to encrypt, 3 to decrypt
impure (Raw, 4168) [in/out]
A block of 4168 bytes which must be provide to the subroutine for its use as a work area. Do not modify it between calls.
key (Raw) [in]
A variable containing your encryption key. The mapped size of key determines the length of the encryption key, which can be from 4 to 56 bytes—i.e. 32 to 448 bits. Note being a symmetric cipher, the same key is used for encryption and decryption. Obviously you should generate an unpredictable key and store it securely.
cleartext (Raw) [in/out]
An area containing or overlaying the clear data. For opcode 2 (encrypt), this is the source; for opcode 3 (decrypt), it is the destination. The size in bytes must be divisible by 4, and must match the ciphertext size. You can use an overlay or an assignment to up-size your actual clear text field. For example, to encrypt a string 29 bytes long, you might map it as follows:
map1 cleartext$,s,29
map1 cleartext,x,32,@cleartext$
ciphertext (Raw) [in/out]
An area containing or overlaying the encrypted data. Restrictions and comments given for cleartext apply here as well.
MAP1 X,I,2
MAP1 BF'IMPURE,X,4168 ! internal work area
MAP1 BF'KEY ! (4 to 56 bytes, divisible by 4)
MAP2 BF'KEY(4),B,4 ! 16 bytes (128 bits)
MAP1 SECRETS
MAP2 NAME,S,36
MAP2 CODE,F,6
MAP1 CLEARTEXT,X,48,@SECRETS ! must be divisible by 8
MAP1 CIPHERTEXT,X,48 ! must be same size as CLEARTEXT
X = SRND2(0,0,&hFFFFFFFF) ! randomize, set 32 bit range
for X = 1 to 4 ! generate 4 32-bit random values for key
BF'KEY(X) = RND2()
next X
open #1, "BLOTST.KEY", output ! save the key
? #1, BF'KEY;
close #1
xcall BLOFSH, 1, BF'IMPURE, BF'KEY ! init cipher from key
NAME = "James Bond"
CODE = 0.007
xcall BLOFSH, 2, BF'IMPURE, CLEARTEXT, CIPHERTEXT ! encrypt
open #2, "BLOTST.DAT", OUTPUT
? #2, CIPHERTEXT; ! write encrypted data to file
close #2
! later, to decrypt...
open #1, "BLOTST.KEY", input ! retrieve the saved key
input raw #1, BF'KEY
close #1
xcall BLOFSH, 1, BF'IMPURE, BF'KEY ! re-init cipher from key
open #2, "BLOTST.DAT", input
input raw #2, CIPHERTEXT ! read encrypted data
close #2
xcall BLOFSH, 3, BF'IMPURE, CIPHERTEXT, CLEARTEXT ! decrypt
? "NAME = ";NAME;", CODE = ";CODE
end
When encrypting string fields, you can copy to/from the original (S format) field and the cleartext / ciphertext (X format) fields. But when encrypting numeric fields or structures, you must use the overlay method shown above. In all cases, you must save the entire ciphertext variable, not just the number of bytes in the actual data. In the example above, the actual data is only 43 bytes but the encrypted data is 48 bytes long, i.e rounded up to the next multiple of 8 bytes.
To generate truly unpredictable keys, see Random Number Generators. To avoid saving the key, you may be able to use some fixed function based on inputs unique to the situation—file #, customer #, ppn, etc.—to produce the seed from which you then can generate and later regenerate a pseudo-random sequence.
If you are exporting your application which encrypts or contains encrypted data, you may want to check your country's regulations. The US has loosened its requirements but there are still situations where Blowfish encryption with keys longer than 56 bits may be restricted.
See Also
• CRYPTO.SBR