Decoding encrypted data
Author: cdouglass@siriussoftware.com.au (Colin)
Hi,
I am having problems decoding data that has been encoded using the uniface proc code $encode.
I am trying to use a secure format like "AES" using "CBC" as is described in the uniface documentation, but I keep getting an error when trying to read the data back and decode it. $procerrorcontext="ERROR=-1791;MNEM=<UENCERR_GENERAL>;DESCRIPTION=Encode/decode general error;COMPONENT=CDMNTDEB;PROCNAME=21\DECR;TRIGGER=DECR;LINE=2;ADDITIONAL=StreamTransformationFilter: ciphertext length is not a multiple of block size"
The documentation has this
; Create an initialization vector.
vIv = $datim
; Encrypt the source data by AES in CBC mode.
vEnc = $encode("AES", vSource, vKey, "CBC", vIv)
; Decrypt the encrypted data.
; DECRYPT must be the same as SOURCE.
vDecrypt = $decode("AES", vEnc, vKey, "CBC", vIv)
I have this code in the encrypt trigger which encodes the data (apparently correctly because the result in the database is the encrypted string)
variables
string v_enc
endvariables
v_enc = $encode("AES", @$fieldname, "creditcardnumber", "CBC", $datim)
card_no.cd_debtor/init = v_enc
I have this code in the decrypt trigger that gives the above error
variables
string v_enc
endvariables
v_enc = $decode("AES", @$fieldname, "creditcardnumber", "CBC", $datim)
card_no.debtor/init = v_enc
?
I have tried for a while but I am getting nowhere. I can get it to properly encrypt and decrypt if I use BASE64 but I would rather use something a little more secure.
Thanks in advance
Colin Douglass
10 Comments
Local Administrator
I think your initialisation vector has to be the same for both coding and decoding, so they have used a variable, initialised to $datim, (Which is therefore the same each time) and you have used $datim directly (which will therefore be different for each command.)
If I am right, then you will need to store the initialisation vector alongside the encoded data in order to have the same IV to decode from.
It also says
Block Ciphers
A block cipher works on a fixed block size, but source data can be in a variety of lengths. Therefore, ECB and CBC mode require that the final block be padded before encryption. Uniface uses the PKCS7 padding scheme for ECB and CBC mode when the data is encrypted, so $decode expects the decrypted result to contain PKCS7-padded data. If this is not the case, Uniface issues a UENCERR_GENERAL error.
Which would indicate that the padding is missing from your data for the decode.
Author: Iain Sharp (i.sharp@pcisystems.co.uk)
Local Administrator
That's correct Iain, but the mentioned Proc error is caused by the fact that the variable v_enc is defined as string. In the doc of $encode it says the following regarding the return value:
"Returns encoded or encrypted data in the Uniface raw data type, unless the Algorithm is BASE64, HEX, URL or USTRING, in which case a data is returned as a Uniface string data type."
Many thanks to my colleague Mike for pointing out the "obvious" to me, since I also fell into this pitfall when I first tested the described problem.
Hope this helps.
Kind regards,
Daniel
*** Usual disclaimer ***
Author: diseli (daniel.iseli@uniface.com)
Local Administrator
Okay, I've done a little testing.
1. Your variable type (v_enc) must be raw, not string.
2. Therefore so must your field type in the database (raw data).
3. Your I.V. must be the same for both encode and decode.
Author: Iain Sharp (i.sharp@pcisystems.co.uk)
Local Administrator
So Daniel and I crossed posts.
Author: Iain Sharp (i.sharp@pcisystems.co.uk)
Local Administrator
Hi bigbaddad,
A little more information about the IV - according to mathematicians, cytology experts and Wikipedia (none of which I claim to be) the IV does not have to be kept secret but MUST be used only once. Given this it is perfectly ok to add the IV onto the resulting string. The following code should give you what you need.
Here is some working code
Regards
Mike
Author: Mike Taylor (michael.taylor@uniface.com)
Local Administrator
Thanks to everyone who answered but I am still having problems.
I have a database field called card_no which is defined as raw, c80
In the Encrypt trigger I now have this code taken largely from Mikes response. This appears to work correctly as its puts data (although of course unrecognizable) into the database.
variables
raw v_enc
string v_iv
endvariables
; Encrypt the source data by AES in CBC mode.
v_iv = $replace($uuid,0,"-","",-1)
v_enc = $encode("AES", @$fieldname, "creditcardnumber", "CBC", v_iv)
card_no/init = $concat(v_iv,$encode("USTRING",v_enc))
In the Decrypt trigger i have
variables
raw v_enc
string v_iv
endvariables
v_iv = @$fieldname[1,32]
card_no.init = $decode("AES", $encode("URAW",@$fieldname[33]), "creditcardnumber", "CBC", v_iv)
This code still gives the original error in the DECRYPT trigger
Author: Colin (cdouglass@siriussoftware.com.au)
Local Administrator
That $encode("USTRING"... is going to strip the padding off the end of the field. I think you need to either settle on a I.V. and hard code it, or store it separately.
Iain
Author: Iain Sharp (i.sharp@pcisystems.co.uk)
Local Administrator
I've found an alternative: just convert the result of $encode("AES") into a BASE64 string.
For example (the database field called card_no which is defined as string, c80):
ENCRYPT trigger:
variables
raw v_enc
string v_iv
endvariables
; Encrypt the source data by AES in CBC mode.
v_iv = $replace($uuid,0,"-","",-1)
v_enc = $encode("AES", @$fieldname, "creditcardnumber", "CBC", v_iv)
@$fieldname = $concat(v_iv,$encode("BASE64",v_enc))
DECRYPT trigger:
variables
raw v_enc
string v_iv
endvariables
v_iv = @$fieldname[1,32]
@$fieldname = $decode("AES", $decode("BASE64",@$fieldname[33]), "creditcardnumber", "CBC", v_iv)
This works for me.
Hope this helps.
Best regards,
Daniel
*** Usual disclaimer ***
Author: diseli (daniel.iseli@uniface.com)
Local Administrator
Hi all,
my colleque told me, that he faced similar problem, but he used instead of base64 the hex-cryption.....
So this is also an alternativ to keep all bytes ;)
Best regards
Thomas
Author: Thomas.Young (thomas.young@young-consulting.de)
Local Administrator
Hello,
one option is to encode it to some text (like HEX or BASE64) as Daniel and Thomas mentioned. I just wonder... why do you use interface C80 for a raw field? Wouldn't it be better to use R for Raw datatype? I didn't try it, but we use SR* for binary data (e.g. documents), so this might help in storing raw encrypted data. Could someone please check if it works?
BTW, I was facing the same problem with MD5, before I noticed $encode returns raw, which I have to convert to HEX to be able to compare it with stored MD5 from non-Uniface application, since MD5 in HEX is very common over internet.
Zdenek
Author: sochaz (zdenek.socha@fullsys.cz)