Skip to content

Instantly share code, notes, and snippets.

@FriedEgg
Last active July 11, 2022 05:28
Show Gist options
  • Save FriedEgg/79ad315afa1b315e8ac3 to your computer and use it in GitHub Desktop.
Save FriedEgg/79ad315afa1b315e8ac3 to your computer and use it in GitHub Desktop.
Using PROC GROOVY in SAS to Calculate Hash Digests
%let key = %nrstr(kd94hf93k423kf44&pfkkdhi9sl3r4s00);
%let message = %nrstr(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 is specific to SAS Installation and may differ from this;
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=*/
%let key = mykey;
%let message = helloworld;
proc groovy;
submit "&key." "&message.";
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
def sha1(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 = sha1(args[0], args[1])
endsubmit;
quit;
%put &hmacsha1.;
filename inc temp;
data _null_;
file inc;
input @;
put _infile_;
cards4;
filename cp temp;
proc groovy classpath=cp;
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 java.security.MessageDigest
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import org.apache.commons.codec.binary.Base64
class SASHash {
private def mac(algorithm, key) {
def mac = Mac.getInstance(algorithm)
mac.init(new SecretKeySpec(key.getBytes(), algorithm))
return mac
}
String base64hmacsha1(String key, String message) {
def mac = this.mac("HmacSHA1", key)
return Base64.encodeBase64String(mac.doFinal(message.getBytes()))
}
String base64hmacsha256(String key, String message) {
def mac = this.mac("HmacSHA256", key)
return Base64.encodeBase64String(mac.doFinal(message.getBytes()))
}
private def sha(algorithm, message) {
return MessageDigest.getInstance(algorithm).digest(message.getBytes())
}
String sha1(String message) {
return new BigInteger(1, this.sha("SHA1",message)).toString(16)
}
String base64sha1(String message) {
return Base64.encodeBase64String(this.sha("SHA1",message))
}
String sha256(String message) {
return new BigInteger(1, this.sha("SHA-256",message)).toString(16)
}
String base64sha256(String message) {
return Base64.encodeBase64String(this.sha("SHA-256",message))
}
}
endsubmit;
quit;
options set=classpath "%sysfunc(pathname(cp,f))";
;;;;
run;
%macro SASHash(action,key=key,message=message,return=hash,include=inc);
%goto &action;
%compile:
%include &include;
%return;
%declare:
if _n_=1 then declare javaobj SASHash('SASHash');
%return;
%hash:
SASHash.callStringMethod("&action",strip(&message),&return);
%return;
%hmachash:
SASHash.callStringMethod("&action",strip(&key),strip(&message),&return);
%return;
%base64hmacsha256:
%goto hmachash;
%base64hmacsha1:
%goto hmachash;
%sha1:
%goto hash;
%base64sha1:
%goto hash;
%sha256:
%goto hash;
%base64sha256:
%goto hash;
%mend;
%let key = sdfoij3242039sdflkj3r23;
%SASHash(compile,include=inc)
data class;
%SASHash(declare)
length hashname $ 128;
set sashelp.class;
%SASHash(sha256,message=name,return=hashname)
run;
/*This is to encode items in a data set instead of a macro variable, using javaobj*/
filename cp temp;
proc groovy classpath=cp;
submit parseonly;
import java.security.MessageDigest
class Sha1 {
public String encode(String message) {
return new BigInteger(1, MessageDigest.getInstance("SHA1").digest(message.getBytes())).toString(16);
}
}
endsubmit;
quit;
options set=classpath "%sysfunc(pathname(cp,f))";
data class;
dcl javaobj sha1('Sha1');
do until (done);
set sashelp.class end=done;
length encoded_name $ 40;
sha1.callStringMethod('encode', strip(name), encoded_name);
output;
end;
run;
%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.;
*https://github.com/FriedEgg/java-jwt/releases/download/java-jwt-2.1.2/java-jwt-2.1.1-SNAPSHOT.jar;
filename jwt '/path/to/java-jwt-2.1.2-SNAPSHOT.jar';
filename cp temp;
proc groovy classpath=cp;
add classpath=jwt;
/* test *//*
submit;
import java.security.KeyFactory
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.RSAPrivateKeySpec;
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.Algorithm;
modulus = new BigInteger("AB34D0D48B16438BBBDFF6DA0CC7D3936DC2CE71E89DEF5B4AA9EA2539EAC17B5765FAAF2C533D176AF95CF16F157FECB977F51DE6E5473808E95A487321A3AB", 16);
privateExponent = new BigInteger("0FEA1CEF64EE70E0F059E54C679BBBA31CB4DB13E397AAC445B07DBF701ECE554DE0266E99B96CE8F3148291551E70357E5AF29FB192FB9E5C2F4AA5C45A0141", 16);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(modulus,privateExponent);
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(rsaPrivateKeySpec);
signer = new JWTSigner(rsaPrivateKey);
HashMap<String, Object> claims = new HashMap<String, Object>();
String token = signer.sign(claims, new JWTSigner.Options().setAlgorithm(Algorithm.RS256));
println token
endsubmit;
*/
submit load;
import java.security.KeyFactory
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.RSAPrivateKeySpec;
import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.Algorithm;
public class Jwt4SAS {
private JWTSigner signer;
private HashMap<String, Object> claims = new HashMap<String, Object>();
public Jwt4SAS(String modulus, String privateExponent) {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPrivateKeySpec rsaPrivateKeySpec = new RSAPrivateKeySpec(
new BigInteger(modulus, 16),
new BigInteger(privateExponent, 16)
);
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyFactory.generatePrivate(rsaPrivateKeySpec);
signer = new JWTSigner(rsaPrivateKey);
}
public void addClaim(String key, String value) {
this.claims.put(key, value);
}
public String sign() {
return signer.sign(claims, new JWTSigner.Options().setAlgorithm(Algorithm.RS256));
}
}
endsubmit;
quit;
options set=classpath "%sysfunc(pathname(cp,f))";
data x;
dcl javaObj jwt4sas('Jwt4SAS',
'AB34D0D48B16438BBBDFF6DA0CC7D3936DC2CE71E89DEF5B4AA9EA2539EAC17B5765FAAF2C533D176AF95CF16F157FECB977F51DE6E5473808E95A487321A3AB',
'0FEA1CEF64EE70E0F059E54C679BBBA31CB4DB13E397AAC445B07DBF701ECE554DE0266E99B96CE8F3148291551E70357E5AF29FB192FB9E5C2F4AA5C45A0141');
jwt4sas.callVoidMethod('addClaim','sub','123456789');
jwt4sas.callVoidMethod('addClaim','name','John Doe');
length jwt $ 2048;
Jwt4SAS.callStringMethod('sign',jwt);
jwt = strip(jwt);
put jwt=;
array enc[3] $ 1024 encodedHeader encodedPayload signedData;
do _n_=1 to dim(enc);
enc[_n_]=scan(jwt,_n_,'.');
end;
length header payload $ 1024;
header = input(encodedHeader,$base64x1024.);
payload = input(encodedPayload,$base64x1024.);
put (encodedHeader header ) (=/) //
(encodedPayload payload) (=/) //
signedData=;
run;
/*http://jwt.io*/
@zhanglianbo35
Copy link

How to get the checksum for one file using SAS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment