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

  1. 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)
  2. 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)
  3. 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)
  4. So Daniel and I crossed posts.


    Author: Iain Sharp (i.sharp@pcisystems.co.uk)
  5. 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

    ; Encode
    variables
        string v_input, v_IV
            raw v_enc
    endvariables
    
    v_Input = "1234-5678-9012-3456"
    v_IV = $replace($uuid, 0, "-", "", -1)
    v_enc = $encode("AES", v_Input, "A Secret Key Is Required", "CBC", v_IV)
    DATAFIELD.DUM = $concat( v_IV, $encode("USTRING", v_enc))
    
    ;Decode
    variables
            string v_iv
    endVariables
    
    v_IV = DATAFIELD[1,32]
    DECODED.DUM = $decode("AES", $encode("URAW", DATAFIELD.DUM[33]), "A Secret Key Is Required", "CBC", v_IV)
    
    


    Regards

    Mike


    Author: Mike Taylor (michael.taylor@uniface.com)
  6.  

     

    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)
  7. 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)
  8. 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)
  9. 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)
  10. 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)