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

Hello everyone,

I'm trying to use sas/secure to generate a hmac-sha1 oauth signature.  I have SAS 9.3 installed on a PC running windows 7 professional.  Note I tried using proc pwencode with Method=sas003.  My code ran, but the signature did not match the one I generated online.  It was way too long.  I'm using the linked page below to create the oauth_signature.  How should I go about solving this problem?  Do I need to use java (yikes!), or can I simply use a proc or options statement?  Any help would be greatly appreciated.  Thanks very much.

-Bill

http://nouncer.com/oauth/authentication.html

1 ACCEPTED SOLUTION

Accepted Solutions
FriedEgg
SAS Employee

I would recommend you continue using the private Java runtime provided by your SAS installation.

This is because they are looking for the base64 encoding of the byte array, you are creating the base64 encoding of the hexadecimal representation of the byte Hmac-SHA1 digest.

%let key = kd94hf93k423kf44&pfkkdhi9sl3r4s00;

%let message = GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal;

proc groovy;

add sasjar="commons_codec" version="1.7.0.0_SAS_20121211183158";*version may differ based on your installation.  Check your SAS Versioned Jar Repository;


submit "&key." "&message.";

import javax.crypto.Mac

import javax.crypto.spec.SecretKeySpec

import org.apache.commons.codec.binary.Base64

def base64hmacsha1(key, message) {

    mac = Mac.getInstance("HmacSHA1")

    mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA1"))

    sha1_bytes = mac.doFinal(message.getBytes())

    base64 = new Base64()

    return new String(base64.encode(sha1_bytes))

}

exports.base64hmacsha1 = base64hmacsha1(args[0], args[1])

endsubmit;

quit;

%put &base64hmacsha1.;

/*tR3+Ty81lMeYAr/Fid0kMTYa/WM=*/

Message was edited by: FriedEgg - typo corrected in RED, also added reference for common-codec sasjar

View solution in original post

21 REPLIES 21
FriedEgg
SAS Employee

Specifying method=sas003 will give you 256-bit key plus 16-bit salt AES encoding, totally different from SHA1.  There is not a way (that I am familiar with) to generate a SHA1 hash with PROC PWENCODE.  You can use java, which wouldn't be too complicated.  Made much easier by the fact that PROC GROOVY exists in 9.3+

%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.;

Side-note: You shouldn't post the same question to multiple communities.

BillJones
Calcite | Level 5

FriedEgg,

Thanks so much for your help.  Code works and produces a sha1 signature.  Quick follow-up questions, if I have key and text components to go into the digest function (digest = HMAC-SHA1 (key, text)), can I simply use a macro variable like %let disgest_inputs=&key.,&text.;?  Or should I do something different?

My apologies about the double post.  I deleted the other thread.  I was having trouble posting my question the other night and inadvertently created a duplicate post.

Thanks again!

Regards,

Bill

FriedEgg
SAS Employee

%let key = mykey;

%let message = helloworld;

proc groovy;

submit "&key." "&message.";

import javax.crypto.Mac

import javax.crypto.spec.SecretKeySpec

def hmacsha1(key, message) {

    mac = Mac.getInstance("HmacSHA1")

    mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA1"))

    sha1_bytes = mac.doFinal(message.getBytes())

    return new BigInteger(1, sha1_bytes).toString(16)

}

exports.hmacsha1 = hmacsha1(args[0], args[1])

endsubmit;

quit;

%put &hmacsha1.;

BillJones
Calcite | Level 5

FriedEgg,

Thanks so much for the code and your time.  I tried to recreate the oauth_signature for a GET example on nouncer.com (url is below).  I created macro variables that generate the key and message inputs correctly (comparisons are below).  However, when I compute the oauth_signature, I get a much different answer to what's on the website.  Noucner.com states that the oauth_signature must be base64-encoded.    I'm using put statement with format $base64x32767.  Is this correct?  Also, should I upgrade java?  Currently, I'm running version 6 update 24.

Thanks again and sorry to keep hassling you with this.

-Bill



Compare oauth signature inputs

Key

sas

kd94hf93k423kf44&pfkkdhi9sl3r4s00

website

kd94hf93k423kf44&pfkkdhi9sl3r4s00

Message

sas

GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal

website (called signature base string)

GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal

Compare oauth_signature output

sas

YjUxZGZlNGYyZjM1OTRjNzk4MDJiZmM1ODlkZDI0MzEzNjFhZmQ2Mw==

website

tR3+Ty81lMeYAr/Fid0kMTYa/WM=

Link to GET example on http://nouncer.com/oauth/authentication.html

(May have to first click on a radio button on the top of the page to something other than the example and then back on the example to see the details.  This is the only way that I can view all the information.)

SAS log:

529  dm 'clear log';

530

531  *Oauth vars;

532  %let oauth_consumer_key=dpf43f3p2l4k3l03;

533  %let oauth_consumer_secret=kd94hf93k423kf44;

534  %let oauth_token=nnch734d00sl2jdk;

535  %let oauth_token_secret=pfkkdhi9sl3r4s00;

536  %let oauth_signature_method=HMAC-SHA1;

537  %let oauth_version=1.0;

538  %let url=%sysfunc(urlencode(http://photos.example.net/photos));

539  %let oauth_size=original;

540  %let oauth_file=vacation.jpg;

541  %let oauth_timestamp=1191242096;

542  %let oauth_nonce=kllo9940pd9333jh;

543

544  *Vars for oauth signature;

545  %let API_TIME_STAMP=%str(oauth_timestamp=&oauth_timestamp.);

546  %let API_NONCE=%str(oauth_nonce=&oauth_nonce.);

547  %let API_KEY=%str(oauth_consumer_key=&oauth_consumer_key.);

548  %let API_SECRET=%str(oauth_consumer_secret=&oauth_consumer_secret.);

549  %let API_METHOD=%str(oauth_signature_method=&oauth_signature_method.);

550  %let API_TOKEN=%str(oauth_token=&oauth_token.);

551  %let API_VERSION=%str(oauth_version=1.0);

552  %let API_SIZE=%str(size=&oauth_size.);

553  %LET API_FILE=%str(file=&oauth_file.);

554  %let API_CONSUMER_SECRET=%sysfunc(urlencode(&oauth_consumer_secret.));

555  %let API_TOKEN_SECRET=%sysfunc(urlencode(&oauth_token_secret.));

556

557  %let

557! string=&API_FILE.%str(&)&API_KEY.%str(&)&API_NONCE.%str(&)&API_METHOD.%str(&)&API_TIME_STAMP.%str

557! (&)&API_TOKEN.%str(&)&API_VERSION.%str(&)&API_SIZE.;

558  %let message=%str(GET)%str(&)&url.%str(&)%sysfunc(urlencode(&string.));

559  %put &message.;

GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-

SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal

560

561  %let key=&API_CONSUMER_SECRET.%str(&)&API_TOKEN_SECRET.;

562  %put &key;

kd94hf93k423kf44&pfkkdhi9sl3r4s00

563

564

565  proc

565!      groovy;

566

567      submit "&key." "&message.";

WARNING: The quoted string currently being processed has become more than 262 characters long.  You

         might have unbalanced quotation marks.

568

569      import javax.crypto.Mac

570      import javax.crypto.spec.SecretKeySpec

571

572      def hmacsha1(key, message) {

573          mac = Mac.getInstance("HmacSHA1")

574          mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA1"))

575

576          sha1_bytes = mac.doFinal(message.getBytes())

577

578          return new BigInteger(1, sha1_bytes).toString(16)

579      }

580

581      exports.hmacsha1 = hmacsha1(args[0], args[1])

582

583       endsubmit;

NOTE: Exporting macro variable "hmacsha1".

NOTE: The SUBMIT command completed.

584

585  quit;

NOTE: PROCEDURE GROOVY used (Total process time):

      real time           0.01 seconds

      cpu time            0.00 seconds

586

587  %put &hmacsha1.;

b51dfe4f2f3594c79802bfc589dd2431361afd63

588

589  data _null_;

590      oauth_signature = put("&hmacsha1.",$base64x32767.);

591      call symput('oauth_signature',oauth_signature);

592  run;

NOTE: DATA statement used (Total process time):

      real time           0.00 seconds

      cpu time            0.00 seconds

593

594  %put &oauth_signature.;

YjUxZGZlNGYyZjM1OTRjNzk4MDJiZmM1ODlkZDI0MzEzNjFhZmQ2Mw==

FriedEgg
SAS Employee

I would recommend you continue using the private Java runtime provided by your SAS installation.

This is because they are looking for the base64 encoding of the byte array, you are creating the base64 encoding of the hexadecimal representation of the byte Hmac-SHA1 digest.

%let key = kd94hf93k423kf44&pfkkdhi9sl3r4s00;

%let message = GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal;

proc groovy;

add sasjar="commons_codec" version="1.7.0.0_SAS_20121211183158";*version may differ based on your installation.  Check your SAS Versioned Jar Repository;


submit "&key." "&message.";

import javax.crypto.Mac

import javax.crypto.spec.SecretKeySpec

import org.apache.commons.codec.binary.Base64

def base64hmacsha1(key, message) {

    mac = Mac.getInstance("HmacSHA1")

    mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA1"))

    sha1_bytes = mac.doFinal(message.getBytes())

    base64 = new Base64()

    return new String(base64.encode(sha1_bytes))

}

exports.base64hmacsha1 = base64hmacsha1(args[0], args[1])

endsubmit;

quit;

%put &base64hmacsha1.;

/*tR3+Ty81lMeYAr/Fid0kMTYa/WM=*/

Message was edited by: FriedEgg - typo corrected in RED, also added reference for common-codec sasjar

BillJones
Calcite | Level 5

I added the classpath for the groovy-all.2.4.0.jar per your recommendation in another thread.   However, now I'm getting a different type of error:

334  dm 'clear log';

335

336  %let key = %nrstr(kd94hf93k423kf44&pfkkdhi9sl3r4s00);

337  %let message =

337! %nrstr(GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddp

337! f43f3p2l4k3l03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_time

337! stamp%3D1191242096%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal);

338

339

340  proc

340!      groovy;

341

342  add classpath="C:\Program Files (x86)\Groovy\Groovy-2.4.0\lib\groovy-all.2.4.0.jar";

NOTE: The ADD CLASSPATH command completed.

343

344  submit "&key." "&message.";

WARNING: The quoted string currently being processed has become more than 262 characters long.  You

         might have unbalanced quotation marks.

345

346  import javax.crypto.Mac

347  import javax.crypto.spec.SecretKeySpec

348  import org.apache.commons.codec.binary.Base64

349

350  def base64hmacsha1(key, message) {

351      mac = Mac.getInstance("HmacSHA1")

352      mac.init(new SecretKeySpec(key.getBytes(), "HmacSHA1"))

353

354      sha1_bytes = mac.doFinal(message.getBytes())

355

356      base64 = new Base64()

357      return new String(base64.encode(sha1_bytes))

358  }

359

360

361  exports.base64hmacsha1 = hmacsha1(args[0], args[1])

362

363

364  endsubmit;

groovy.lang.MissingMethodException: No signature of method: Script10.hmacsha1() is applicable for

argument types: (java.lang.String, java.lang.String) values: [kd94hf93k423kf44&pfkkdhi9sl3r4s00,

GET&http%3A%2F%2Fphotos.example.net%2Fphotos&file%3Dvacation.jpg%26oauth_consumer_key%3Ddpf43f3p2l4k3l

03%26oauth_nonce%3Dkllo9940pd9333jh%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D119124209

6%26oauth_token%3Dnnch734d00sl2jdk%26oauth_version%3D1.0%26size%3Doriginal]

     at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:54)

     at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78)

     at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:44)

     at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:143)

     at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:155)

     at Script10.run(Script10.groovy:17)

ERROR: The SUBMIT command failed.

365

366

367  quit;

NOTE: The SAS System stopped processing this step because of errors.

NOTE: PROCEDURE GROOVY used (Total process time):

      real time           0.03 seconds

      cpu time            0.01 seconds

WARNING: Apparent symbolic reference HMACSHA1 not resolved.

368  %put &hmacsha1.;

&hmacsha1.

369  /*tR3+Ty81lMeYAr/Fid0kMTYa/WM=*/

FriedEgg
SAS Employee

I did not test that posting and missed replacing the method call with the proper name.  You should be good now.

BillJones
Calcite | Level 5

Success!  Thanks so very much for your time and help with this.  I've tried numerous different ways to generate the oauth_signature.  Finally, I found a solution that works with sas.

Regards,

Bill

FriedEgg
SAS Employee

@BillJones,

Glad it work out for you.

NG_Forest
Calcite | Level 5

HI,

Firstly apologies if this is the wrong place to post...first time I've used this!

Thank you for posting the code above - it's really helped me.  I'm trying to SHA1 encode entries in a file, but I can't find a way of incorporating the code into a macro and thus can only do one at a time using the code you provided below.

proc sql noprint;

     select mskey, emailcode

     into :mskey, :emailcode

     from trust;

quit;

%let toHash=&mskey&emailcode;

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 &toHash;

%put &sha1.;

When I try and incorporate in a macro it mentions that the submit block cannot be directly placed in a macro.  Instead, place the submit block into a file first and then use %include to include the file within a macro definition.  Sorry, my coding is not good enough to make this work Smiley Sad

Any help would be much appreciated!

FriedEgg
SAS Employee

@NG_Forest,

It would be best to create a new post for you question as SHA1 and HMAC-SHA1 are significantly different topics.

Also, I have posted on this subject previously, it does not use PROC GROOVY, as it did not exist at the time (the code in this post could be adapted to use is though):

Using a macro to perform this type of task on every record in a file is really less than ideal.  The better approach would be using the data step java object.

NG_Forest
Calcite | Level 5

@FriedEgg,

Thanks for taking the time to respond and apologies for not starting a new post.

Once I have a Java compiler installed on my machine I'll certainly give your other method a go.

FriedEgg
SAS Employee

@NG_Forest

I updated the post to include a similar method using PROC GROOVY at the same link as above

NG_Forest
Calcite | Level 5

@FriedEgg,

Once again, thank you so much...it works perfectly Smiley Happy

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
  • 3445 views
  • 7 likes
  • 3 in conversation