Rocket U2 | UniVerse & UniData

 View Only

 Subroutine to encrypt SHA256

Jump to Best Answer
  •   11.3.1
  •   BASIC
  •   Pick
  •   UniVerse
Alex M's profile image
Alex M posted 12-04-2020 09:52
Hello!  
I try to build a subrouting that will be used by an I-DESC.  Its goal is to encrypt another attribute, using SHA256.  The DICT item will be used in CSV exports, to transmit data to partners.  They want some columns to be encrypted (it would be too easy to encrypt the whole file I guess).  That is why I want to combine a subroutine with an I-DESC.

Okay, so I already wrote my subroutine but I am not sure about the result.  Maybe someone here already did something similar, and/or maybe someone could help me to find the right way to reach my goal.

My subroutine is simple: I use DIGEST (beacuse it was the only function that seems to know pure SHA256), and after, I encode the result as BASE64-OneLine, to make it human-readable.
MY.HASH       = "SHA256"
MY.STRING     = "HELLO"
DIGEST.STATUS = DIGEST(MY.HASH, MY.STRING, 1, MY.DIGEST)

FINAL.STRING  = ""
ENCODE.STATUS = ENCODE("BASE64A", 1, MY.DIGEST, 1, FINAL.STRING, 1)​

The result of the subroutine, for string HELLO, is L/qIdUmp4FD73SZttIGW+w==

It looks like something encrypted, it's a good sign!  I want to compare my result with online tools, so I went on SHA256 Online (emn178.github.io) and entered HELLO in the input box.  The result is 3733cd977ff8eb18b987357e22ced99f46097f31ecb239e878ae63760e83e4d5.  
I believe I did someting wrong, but now, I don't have any clues.

I also tried the ENCRYPT() function.  Buy the fact that I don't use an Encryption Key breaks the logic a little.
I hope someone could give me some hints!  Thank you very much all!
#UniVerse #11.3.1 #Pick #BASIC
​​​​
Jonathan Smith's profile image
ROCKETEER Jonathan Smith Best Answer
Before the BASE64A Encode is done the result is correct.

I tested this on 8.2.2 UniData and 11.3.2 UniVerse both on Windows, use this program

CRT
DIGEST.STATUS = DIGEST("SHA256","HELLO",1,DIGEST.RESULT)
IF DIGEST.STATUS = 0 THEN
LEND = LEN(DIGEST.RESULT)
FOR A.NXT = 1 TO LEND
SINGLE.CHAR = DIGEST.RESULT[A.NXT,1]
SINGLE.CHAR.ASCII = SEQ(SINGLE.CHAR)
SINGLE.CHAR.HEX = OCONV(SINGLE.CHAR.ASCII,"MX")
CRT SINGLE.CHAR.HEX :
NEXT A.NXT
END ELSE
CRT "Digest Failed"
END
END

And the result will be :

3733CD977FF8EB18B987357E22CED99F46097F31ECB239E878AE63760E83E4D5 (this is same as your web example)

So it's the ENCODE call that is changing it, why are doing the BASE64A encode ?
Alex M's profile image
Alex M
Hi @Jonathan Smith !  Thanks for your reply, I have changed my subroutine and added your code (edited it a little to fit mine).  The funky thing is I get a different output for HELLO:
353535313230353135313132373234383233353234313835313335353331323633343230363231373135393730393132373439323336313738353732333231323031373439393131383134313331323238323133

I wanted to encode it to base64 to make it human-readable, I realise it was an error :)​

    MY.RESULT = ""
    RESULT.LEN = LEN(MY.DIGEST)

    * Convert each characters of the Digest
    FOR NDX = 1 TO RESULT.LEN   
        THIS.CHAR  = MY.DIGEST[NDX,1]
        CHAR.ASCII = SEQ(THIS.CHAR)
        CHAR.HEX   = OCONV(CHAR.ASCII, "MX")
        * Add HEX to the final String
        MY.RESULT := CHAR.HEX
    NEXT NDX

    DISPLAY MY.RESULT​

You gave me a very good hint, now I will look at why I have a different result than you.  Thanks for your help :) 

Alex M's profile image
Alex M
@Jonathan Smith, I am almost there!!

Goal: 3733cd977ff8eb18b987357e22ced99f46097f31ecb239e878ae63760e83e4d5
What I have now: 3733cd977ff8eb18b987357e22ced99f4697f31ecb239e878ae6376e83e4d5​

There is 2 differences: zeros are not in my result.  I need to find why.  To get this result, I changed the OCONV from MX to MCD (Decimal to HEX).
Thanks for your help!
Alex M's profile image
Alex M
Finally got it !
Had to add leading 0 if OCONV MCD is less than 2 characters!  Here is my final code:

    MY.RESULT = ""
    RESULT.LEN = LEN(MY.DIGEST)

    * Convert each characters of the Digest
    FOR NDX = 1 TO RESULT.LEN   
        THIS.CHAR  = MY.DIGEST[NDX,1]
        CHAR.ASCII = SEQ(THIS.CHAR)
        CHAR.HEX   = OCONV(CHAR.ASCII, "MCD")
        IF LEN(CHAR.HEX) LT 2 THEN  
            CHAR.HEX = "0":CHAR.HEX 
        END
        * Add HEX to the final String
        MY.RESULT := CHAR.HEX
    NEXT NDX​
Later convert OCONV MCL to lower case and it's pretty!
Thanks again @Jonathan Smith !​