Hashing

Posted by Andrew Stalker on 20-Nov-2014 08:40

I dont want to use the built in Encode function.

How would i encrypt say a string of data by hashing with SHA-256 algorithm?

Posted by andrew.may on 20-Nov-2014 09:22

Firstly, as Jens said... Hashing <> Encrypting!

If you do want to hash & you’re doing it to hide sensitive data (e.g. passwords) then you should probably be using SHA-512 & a per-data-item salt:

message-digest("SHA-512", cMyPlainText, cMySalt)

The most common reason is to hash passwords so that you can store them in your DB & make the data resistant to attack. When doing this, a decent thing to do is to generate a user-specific random salt value when you create the user record & store that salt in the DB.

e.g. 

DEFINE TEMP-TABLE ttUser
    FIELD id AS CHAR
    FIELD salt AS RAW
    FIELD password AS RAW.

FUNCTION checkUserPassword RETURNS LOGICAL (ipcId AS CHARACTER , ipcPassword AS CHARACTER):

    FIND ttUser WHERE ttUser.id = ipcId.
    RETURN (ttUser.password = MESSAGE-DIGEST("SHA-512", ipcPassword, ttUser.salt)).
END.

/* Create user john.doe with password = "correct-password" */
RUN createUser("john.doe", "correct-password").

MESSAGE
    checkUserPassword("john.doe", "correct-password") SKIP
    checkUserPassword("john.doe", "a-different-password")
    VIEW-AS ALERT-BOX.
    
/* Change john doe's password */    
RUN updateUserPassword ("john.doe", "a-different-password").

MESSAGE
    checkUserPassword("john.doe", "correct-password") SKIP
    checkUserPassword("john.doe", "a-different-password")
    VIEW-AS ALERT-BOX. 
    
/*************************************************/

PROCEDURE createUser:
    DEFINE INPUT  PARAMETER ipcId AS CHARACTER NO-UNDO.
    DEFINE INPUT  PARAMETER ipcPassword AS CHARACTER NO-UNDO.

    CREATE ttUser.
    ttUser.id = ipcId.
    ttUser.salt = GENERATE-PBE-SALT.
    ttUser.password = MESSAGE-DIGEST("SHA-512", ipcPassword, ttUser.salt).
END.

PROCEDURE updateUserPassword:
    DEFINE INPUT  PARAMETER ipcId AS CHARACTER NO-UNDO.
    DEFINE INPUT  PARAMETER ipcPassword AS CHARACTER NO-UNDO.

    FIND ttUser WHERE ttUser.id = ipcId.
    ttUser.password = MESSAGE-DIGEST("SHA-512", ipcPassword, ttUser.salt).
END.


All Replies

Posted by Jens Dahlin on 20-Nov-2014 08:55

SHA-256 isn't really encryption, it's a hashing algorithm. Nevertheless, here's an example:

DEFINE VARIABLE mHash AS MEMPTR      NO-UNDO.
DEFINE VARIABLE cLongChar AS LONGCHAR NO-UNDO.

SET-SIZE(mHash) = 32.

PUT-BYTES(mHash, 1) = MESSAGE-DIGEST("SHA-256", "A string").

COPY-LOB mHash TO cLongChar.

SET-SIZE(mHash) = 0.


DISP cLongChar VIEW-AS EDITOR LARGE INNER-CHARS 60 INNER-LINES 2.


Unsure if MESSAGE-DIGEST was introduced in 10.2 OR 11.something.

Posted by andrew.may on 20-Nov-2014 09:22

Firstly, as Jens said... Hashing <> Encrypting!

If you do want to hash & you’re doing it to hide sensitive data (e.g. passwords) then you should probably be using SHA-512 & a per-data-item salt:

message-digest("SHA-512", cMyPlainText, cMySalt)

The most common reason is to hash passwords so that you can store them in your DB & make the data resistant to attack. When doing this, a decent thing to do is to generate a user-specific random salt value when you create the user record & store that salt in the DB.

e.g. 

DEFINE TEMP-TABLE ttUser
    FIELD id AS CHAR
    FIELD salt AS RAW
    FIELD password AS RAW.

FUNCTION checkUserPassword RETURNS LOGICAL (ipcId AS CHARACTER , ipcPassword AS CHARACTER):

    FIND ttUser WHERE ttUser.id = ipcId.
    RETURN (ttUser.password = MESSAGE-DIGEST("SHA-512", ipcPassword, ttUser.salt)).
END.

/* Create user john.doe with password = "correct-password" */
RUN createUser("john.doe", "correct-password").

MESSAGE
    checkUserPassword("john.doe", "correct-password") SKIP
    checkUserPassword("john.doe", "a-different-password")
    VIEW-AS ALERT-BOX.
    
/* Change john doe's password */    
RUN updateUserPassword ("john.doe", "a-different-password").

MESSAGE
    checkUserPassword("john.doe", "correct-password") SKIP
    checkUserPassword("john.doe", "a-different-password")
    VIEW-AS ALERT-BOX. 
    
/*************************************************/

PROCEDURE createUser:
    DEFINE INPUT  PARAMETER ipcId AS CHARACTER NO-UNDO.
    DEFINE INPUT  PARAMETER ipcPassword AS CHARACTER NO-UNDO.

    CREATE ttUser.
    ttUser.id = ipcId.
    ttUser.salt = GENERATE-PBE-SALT.
    ttUser.password = MESSAGE-DIGEST("SHA-512", ipcPassword, ttUser.salt).
END.

PROCEDURE updateUserPassword:
    DEFINE INPUT  PARAMETER ipcId AS CHARACTER NO-UNDO.
    DEFINE INPUT  PARAMETER ipcPassword AS CHARACTER NO-UNDO.

    FIND ttUser WHERE ttUser.id = ipcId.
    ttUser.password = MESSAGE-DIGEST("SHA-512", ipcPassword, ttUser.salt).
END.


Posted by Frank Meulblok on 20-Nov-2014 09:39

Note:

The value returned from the MESSAGE-DIGEST is an arbitraty stream of bytes. If you need to store that in a CHARACTER or LONGCHAR, base64-encode it to avoid errors/corruption due to improper codepage interpretations/conversions

Posted by Andrew Stalker on 20-Nov-2014 10:08

Thanks thats exactly the sort of thing I need.

This thread is closed