BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
Deen
Obsidian | Level 7

Hi All,

Do we have Encryption function which supports SHA256 in SAS9.3? I saw this function exists in SAS 9.4 but

 

per the new features SAS9.3 in bleow link

 

http://support.sas.com/documentation/cdl/en/whatsnew/64209/HTML/default/viewer.htm#p1fvz9q0q3wo8xn1l...

 

it says that SHA256 encrpytion does exist in SAS 9.3.

 

Please suggest.

 

Thanks,

Deen

1 ACCEPTED SOLUTION

Accepted Solutions
Deen
Obsidian | Level 7

I found the right sasjar version and executed the code below is log file. though it shows couple of warnings but it produced the desired result.


NOTE: PROCEDURE HTTP used (Total process time):
      real time           9.42 seconds
      cpu time            0.21 seconds



NOTE: PROCEDURE HTTP used (Total process time):
      real time           0.20 seconds
      cpu time            0.01 seconds


NOTE: The ADD CLASSPATH command completed.
NOTE: The ADD CLASSPATH command completed.
NOTE: The ADD CLASSPATH command completed.
WARNING: SAS jars do not have a source compatibility guarantee across versions of SAS. Future
         versions of these jars can change without notice.
NOTE: The ADD SASJAR command completed.
NOTE: The SUBMIT command completed.
Single Round: Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=

Final Round: aJDhkskZ9OwP1n1akIoOgReHjm+iFJ0ofPt3CNhvFy8=

NOTE: The SUBMIT command completed.

NOTE: PROCEDURE GROOVY used (Total process time):
      real time           0.64 seconds
      cpu time            0.00 seconds



NOTE: The data set WORK.FOO has 1 observations and 1 variables.
NOTE: DATA statement used (Total process time):
      real time           0.13 seconds
      cpu time            0.00 seconds



WARNING: Could not initialize classpath.  Classpath variable is not set.

one=Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=

thousand=aJDhkskZ9OwP1n1akIoOgReHjm+iFJ0ofPt3CNhvFy8=

NOTE: There were 1 observations read from the data set WORK.FOO.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds

 If any quick suggestions to resolve the warning it would be really helpful for me ..also meanwhile, I need to extend this functionality to apply this hashing on a big dataset column for final requirements.

View solution in original post

21 REPLIES 21
LinusH
Tourmaline | Level 20
It does for encrypting passwords, but I don't think it became a part of the SAS Language until 9.4.
Data never sleeps
ChrisHemedinger
Community Manager

The SHA256 function was added in SAS 9.4m1.  See this post: A fresh helping of hash: the SHA256 function in SAS 9.4m1.

 

I'm pretty sure that it wasn't present before then, even as an undocumented function.  I remember researching that before I wrote the blog post...

 

My colleague Rick Langston will have a Hashing Technique paper published for SAS Global Forum (April) -- might be of interest!

 

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Deen
Obsidian | Level 7

I see that SHA-256 encryption is availbale in SASv9.4 but also I see that its available in SAS9.3 in below link (under Encrpyption section)

 

http://support.sas.com/documentation/cdl/en/whatsnew/65742/HTML/default/viewer.htm#p1fvz9q0q3wo8xn1l...

 

but I think it requires SAS/Secure license..is it correct?

FriedEgg
SAS Employee

You can use the method I shared at the following link to create a hashing function for use in SAS prior to v9.4 where many new functions for this were added

 

https://gist.github.com/FriedEgg/79ad315afa1b315e8ac3

 

PROC GROOVY was introduced in SAS 9.3 but this method will work similarly for version prior using Java Component Objects and compiling the Java classes outside of SAS.  I do not have a example specific for plain SHA-256, however, the SHA-1 examples should be very easily adaptable.

 

I have a write-up for this as well:

 

https://communities.sas.com/t5/Base-SAS-Programming/Enable-SHA1-Hash-MessageDigest-in-SAS-with-Javao...

 

Deen
Obsidian | Level 7

I think this would work and looks like simple..

looks like it requires java..

but it seems I need to get java on my machine..

do you have similar code which uses Groovy...I read something on Proc Groovy..something there should be in proc groovy to achieve this..

 

meanwhile I do further research.. could you please post some commands in proc groovy to achieve sha256 in sas9.3

 

Thanks a lot!!

Deen
Obsidian | Level 7

also

i tried to make use of the proc groovy from one of your sugested programs in below link

https://gist.github.com/FriedEgg/79ad315afa1b315e8ac3

 

 

%let toHash=something to hashify;


proc groovy;


submit "&toHash.";
import java.security.MessageDigest
exports.sha1 = new BigInteger(1, MessageDigest.getInstance("SHA1").digest(args[0].getBytes())).toString(16)
endsubmit;


quit;


%put &sha1.;

 

it produces below result

 

8d3d5f3c32ca98e8d9c4125509b3d7a00466d296

 

I think above code performs SHA256 hashing ...

and when I test above code for 'abc123' text as below its not producing the desired result as one of our requirements.

 

%let toHash=abc123;


proc groovy;


submit "&toHash.";
import java.security.MessageDigest
exports.sha1 = new BigInteger(1, MessageDigest.getInstance("SHA1").digest(args[0].getBytes())).toString(16)
endsubmit;


quit;


%put &sha1.;

 

am getting below result for the above code.

 

6367c48dd193d56ea7b0baad25b19455e529f5ee

 

but whereas expected result for hashing 'abc123' text using SHA256 algorithm is below.

 

Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=

 

the requirement is below from our end user.

Hashing Requirements

1.Concatenate last name and date of birth to create Salt input

–Last Name is uppercase

–Date is in string format YYYY-MM-DD

Output as string (varchar), e.g. "JONES1983-12-30’

2.Hash result from Step 1 one time using SHA 256 to create the Salt

3.Concatenate the results from Steps 1 and 2

4.Convert result from Step 3 to lower case and remove binary "0x"

5.Hash result from Step 4 one time using SHA 256

6.Hash result of Step 5 for 1000 iterations

7.Base 64 hashed result from step 6

8.Output value in ME998

 

Hashing Audit

Hashed value for ‘abc123’ based on single round, should be:

Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=

 

if I have a proc groovy code or any suggestions to achieve above requirement it would be really helpful.

 

Thanks..

 

 

FriedEgg
SAS Employee

@Deen

You are using SHA-1 encrypting in the code you posted. Which is what my example you used does... not SHA-256. The correct value for SHA-256 encryption is

6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090

for an input value of:

abc123

Your requirements go far beyond just a regular SHA-256 hash and several components of those instructions make little to no sense to me. They appear to be written for some specific platform rather than a generalization...

Step 4. The notion of removing a binary '0x' doesn't make sense, but lets assume that this just means that we want to convert the byte array produced in step2 to a string of hex values in the form of

6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090

rather than

0x6ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090

No matter what, this isn't 'binary'


Next, we want to convert that value to lower case, so step4 is ultimately equal to

abc1236ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090

or are we expected to somewhere convert the result of step 1 to a hex string as well?

616263313233366ca13d52ca70c883e0f0bb101e425a89e8624de51db2d2392593af6a84118090

Is this then meant to get hashed with SHA-256 as a string or as a byte array of itself? Very unclear instructions...

Finally in Step 8, I've never heard of anything called ME998 before, so, I am left to assume this is some internal system or table to your environment.

Regardless of the method I tried as outlined above, I cannot produce the 'expected' output you provided.

 

import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import javax.xml.bind.DatatypeConverter

def toHexString(byte[] bytes) {
    return DatatypeConverter.printHexBinary(bytes)
}
def toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s)
}

def Sha256(byte[] bytes) throws NoSuchAlgorithmException {
    MessageDigest md = MessageDigest.getInstance("SHA-256")
    md.update(bytes)
    return md.digest()
}

def Base64(byte[] bytes) {
    return new String(Base64.getEncoder().encodeToString(bytes))
}

def merryGoRound(byte[] bytes) {
    step6 = bytes
    for (i=0; i<1000; i++) { step6 = Sha256(step6) }
    return step6
}
def DeenEncrypt1(String input) {
    step2 = Sha256(input.getBytes())
    step3 = input + toHexString(step2)
    step4 = step3.toLowerCase()
    step5 = Sha256(step4.getBytes())
    step6 = merryGoRound(step5)
    step7 = Base64(step6)
    return step7
}

def DeenEncrypt2(String input) {
    step2 = Sha256(input.getBytes())
    step3 = toHexString(input.getBytes()) + toHexString(step2)
    step4 = step3.toLowerCase()
    step5 = Sha256(step4.getBytes())
    step6 = merryGoRound(step5)
    step7 = Base64(step6)
    return step7
}

def DeenEncrypt3(String input) {
    step2 = Sha256(input.getBytes())
    step3 = toHexString(input.getBytes()) + toHexString(step2)
    step4 = step3.toLowerCase()
    step5 = Sha256(toByteArray(step4))
    step6 = merryGoRound(step5)
    step7 = Base64(step6)
    return step7
}
def to0xString(byte[] bytes) {
return "0x" + toHexString(bytes)
}

def DeenEncrypt4(String input) {
step2 = Sha256(input.getBytes())
step3 = input + toHexString(step2)
step4 = step3.toLowerCase()
step5 = Sha256(step4.getBytes())
step6 = to0xString(step5)
for (i=0; i<999; i++) { step6 = to0xString(Sha256(step6.getBytes()))}
step7 = Base64(Sha256(step6.getBytes()))
return step7
}

myString="abc123"
println(DeenEncrypt1(myString))
//Ir4+t3lTvPeE0s+daBIZY3btG0u8ist8znq6FnhIJNc=
println(DeenEncrypt2(myString))
//UqPhYbaI/bZ5s7jO3jnVIfPP4mT+BvPDYLWgInRSHB4=
println(DeenEncrypt3(myString))
//pobTckp4TAuDudylcugnzJGBc9YM4poSUPRk2zTgHrY=
println(DeenEncrypt4(myString))
//2wQPtEPxQJLCkmpH1Bo4t1OFqdcnGR8bzA7/uUrDiTY=

 

I would recommend you get some clearer hashing requirements

Deen
Obsidian | Level 7

Matt,

Thanks for your prompt response with more detailed explanation . I will test your code once again and test our requirements.

You got the correct understanding about our requirement.however, after my testing and would check with the requirements once again..

 

Thanks a ton!!!

Deen
Obsidian | Level 7

Matt,

I tried to test your code by keeping it between proc groovy and quit but somehow i was getting bleow error.

 

 

81     import java.security.MessageDigest
       ------
       180
ERROR 180-322: Statement is not valid or it is used out of proper order.

100                  i<1000;
                     -
                     180
ERROR 180-322: Statement is not valid or it is used out of proper order.

100                          i++) { step6 = Sha256(step6) }
                             -
                             180
ERROR 180-322: Statement is not valid or it is used out of proper order.

139                  i<999;
                     -
                     180
ERROR 180-322: Statement is not valid or it is used out of proper order.

139                         i++) { step6 = to0xString(Sha256(step6.getBytes()))}
                            -
                            180
ERROR 180-322: Statement is not valid or it is used out of proper order.

 

Here are the clear requirements recieved from end user.

 

Step 1: hashing the input ('abc123' in our example) using SHA 256 algorithm
Step 2: input + lower (convert to hexadecimal(step 1 result))
Step 3: hashing the step 2 result using SHA 256 algorithm
Step 4: hashing the step 3 result for 1000 times using SHA 256 algorithm

 

Hashed value for ‘abc123’ based on single round, should be:

Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=

 

Hashed value on above result after 1000 rounds, should be:

aJDhkskZ9OwP1n1akIoOgReHjm+iFJ0ofPt3CNhvFy8=

 

FriedEgg
SAS Employee
You requirements are still missing a component to fully make sense.

Most obviously, the two strings you posted here are Base64 encoded, which isn't in the instructions. I can now duplicate the 'single round' value. When does the Base64 encoding applied? Just for display? In between each round?
Deen
Obsidian | Level 7
Thanks for your response
Deen
Obsidian | Level 7

yes   for display purpose only we need Base64 encoding.

FriedEgg
SAS Employee
Okay, turns out the problem is that the last step should read... Hash it 999 more times, for 1000 total... Not 1000 more times...
FriedEgg
SAS Employee
filename groovy temp;

proc http method='get'
url="http://central.maven.org/maven2/org/codehaus/groovy/groovy-all/2.4.6/groovy-all-2.4.6.jar"
out=groovy;
run;

filename xmlbind temp;

proc http method='get'
url="http://central.maven.org/maven2/javax/xml/bind/jaxb-api/2.2.12/jaxb-api-2.2.12.jar"
out=xmlbind;
run;

filename cp temp;

options set=classpath= "%sysfunc(pathname(cp,f))";

proc groovy classpath=cp;
add classpath=groovy;
add classpath=xmlbind;
add sasjar="commons_codec" version="1.7.0.0_SAS_20121211183158"; *version is specific to SAS Installation and may differ from this;

submit parseonly;

import javax.xml.bind.DatatypeConverter
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.ArrayList
import org.apache.commons.codec.binary.Base64

/**
 * DeenHash Requirements
 *
 *
 * 1. Hash an input String (ex. "abc123") using SHA-256 algorithm
 * 2. Concatenate input string + hexDump of step1 result
 * 3. Hash step2 result using SHA-256 algorithm
 *      a. this marks a single-round
 *      b. print raw step3 result in Base64 encoding
 * 4. Hash step3 result 999 additional times using SHA-256 algorithm
 */
public class DeenHash {

    private String input = "abc123";
    private String algorithm = "SHA-256";
    protected ArrayList<byte[]> results=new ArrayList();

    public DeenHash() {}

    public DeenHash(String input) {
        setInput(input);
    }

    public DeenHash(String algorithm, String input) throws NoSuchAlgorithmException{
       setAlgorithm(algorithm);
    }

    public String getInput() {
        return this.input;
    }

    public void setInput(String input) {
        this.input = input;
    }

    public String getAlgorithm() {
        return this.algorithm;
    }

    public void setAlgorithm(String algorithm) throws NoSuchAlgorithmException {
        MessageDigest.getInstance(algorithm);
        this.algorithm = algorithm;
    }

    private String toHexString(byte[] bytes) {
        return DatatypeConverter.printHexBinary(bytes);
    }

    private String toBase64(byte[] bytes) {
        Base64 base64 = new Base64();
        return new String(base64.encode(bytes));
    }

    private byte[] merryGoRound(byte[] bytes) throws NoSuchAlgorithmException {
        byte[] step4 = bytes;
        for (int i=0; i<999; i++) { step4 = doSingleHash(step4); }
        return step4;
    }

    public byte[] doSingleHash(byte[] bytes) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance(this.algorithm);
        md.update(bytes);
        return md.digest();
    }

    public void doDeenHash() throws NoSuchAlgorithmException {
        byte[] step1 = doSingleHash(this.input.getBytes());
        String step2 = this.input + toHexString(step1).toLowerCase();
        byte[] step3 = doSingleHash(step2.getBytes());
        this.results.add(step3);
        byte[] step4 = merryGoRound(step3);
        this.results.add(step4);
    }

    public String getFinalHash() {
        return toBase64(this.results.get(1));
    }

    public String getInitialHash() {
        return toBase64(this.results.get(0));
    }

    public void main(String[] args) {
        if (args.length == 1) {
            setInput(args[0]);
        } else if (args.length == 2) {
            try {
                setAlgorithm(args[0]);
                setInput(args[1]);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }

        try {
            doDeenHash();
            System.out.println("Single Round: " + toBase64(this.results.get(0)));
            System.out.println("Final Round: " + toBase64(this.results.get(1)));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}
endsubmit;

submit;
foo = new DeenHash()
foo.main()
endsubmit;

quit;

data foo;
input foo $;
cards;
abc123
;
run;

data _null_;
dcl javaobj hash('DeenHash');
do until(done);
set foo end=done;
length one thousand $ 64;
hash.callVoidMethod('setInput',strip(foo)); *strip is important;
hash.callVoidMethod('doDeenHash');
hash.callStringMethod('getInitialHash',one);
hash.callStringMethod('getFinalHash',thousand);
put (one thousand) (=/);
end;
stop;
run;

 

 

 190        endsubmit;
 NOTE: The SUBMIT command completed.
 191        
 192        submit;
 193        foo = new DeenHash()
 194        foo.main()
 195        endsubmit;
 Single Round: Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=
 Final Round: aJDhkskZ9OwP1n1akIoOgReHjm+iFJ0ofPt3CNhvFy8=
 NOTE: The SUBMIT command completed.
 196        
 197        quit;
 
 NOTE: PROCEDURE GROOVY used (Total process time):
       real time           0.14 seconds
       cpu time            0.01 seconds

 

 215        put (one thousand) (=/);
 216        end;
 217        stop;
 218        run;
 
 one=Pbb2/dJkywFxhuW2O33twGm+Gu67UfoEFupDMUeBnuo=
 thousand=aJDhkskZ9OwP1n1akIoOgReHjm+iFJ0ofPt3CNhvFy8=
 NOTE: There were 1 observations read from the data set WORK.FOO.
 NOTE: DATA statement used (Total process time):
       real time           0.02 seconds
       cpu time            0.00 seconds

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 21 replies
  • 9432 views
  • 6 likes
  • 4 in conversation