Replicate BTOA Javascript Function in SAS Data Step - javascript

When I encrypt the string g.b#yahoo.it in Javascript using the BTOA function I get the result Zy5iQHlhaG9vLml0.
This function converts the string to the base64 representation of the string. When I try and do the equivalent in SAS I get a different value:
proc fcmp outlib=common.funcs.funcs;
function b64(string $) $;
length digest $32767;
digest=strip(put(string,$base64x32767.));
return(digest);
endsub;
quit;
data email;
input email $12.;
datalines;
g.b#yahoo.it
run;
data X;
set email;
e1 = "<" || trim(email) || ">";
pw_e = b64(e1);
put _all_;
run;
Gives me:
email=g.b#yahoo.it e1=<g.b#yahoo.it> pw_e=PGcuYkB5YWhvby5pdD4= _ERROR_=0 _N_=1
Based on the documentation for each, they are using the same alphabet:
http://support.sas.com/documentation/cdl/en/lrdict/64316/HTML/default/viewer.htm#a003161924.htm
https://www.w3schools.com/jsref/met_win_btoa.asp
I want to replicate the same function in SAS Data Step to obtain the same result. Is there a way to do this in SAS?

They are doing the same thing. You are modifying the string that you are passing to the base64 encoding function in SAS which is why you are getting a different result. The string you are using in SAS is <g.b#yahoo.it> (you added the < and > characters around it.
If you run that same string of <g.b#yahoo.it> through btoa() you get the same result of PGcuYkB5YWhvby5pdD4=

Related

ABAP string to SHA256 different to SAPUI5/Javascript

Currently on my SAPUI5 project, I am creating a HMAC encoded string with this line of code:
var secretKey = CryptoJS.enc.Hex.parse('SECRETKEY'); //USING THE CRYPTOJS LIBRARY!
var hash = CryptoJS.HmacSHA256('abc', secretKey);
hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
which gives eZdbNMwgWKOANEiozokNG2FGfzI7Yy/B8IQKXr3+krY=
I am using the CryptoJS library to execute this code in UI5.
However the problem is that I am receiving the wrong HMAC encoded string when I want to do the same in ABAP. After testing a few times, it seems like the encoding (in abap) is wrong before the HMAC is calculated.
Is there a function module that does 'CryptoJS.enc.Hex.parse()' - after googling what it does it interprets the parameter as encoded and converts it into a word array:
DATA:
lv_sign_key_x TYPE xstring,
lv_hmac_result TYPE string.
DATA(lv_binary_secret) = cl_abap_hmac=>string_to_xstring('SECRETKEY').
cl_abap_hmac=>calculate_hmac_for_char(
EXPORTING
if_algorithm = 'SHA256' "Hash Algorithm
if_key = lv_binary_secret "HMAC Key
if_data = 'abc' "Data
IMPORTING
ef_hmacb64string = lv_hmac_result "HMAC value as base64-encoded string
).
which gives 9dyEZn5G+uiRwsNqgY5S6k9/gmCheFNF4vFa5qBKK1w=
Shows exact way to encode to hex and calculate to HMAC256. Link
data lv_binary_secret type xstring.
data lv_string type string value '48656c6c6f2c20576f726c6421'.
translate lv_string to upper case.
lv_binary_secret = lv_string.
cl_abap_hmac=>calculate_hmac_for_char(
EXPORTING
if_algorithm = 'SHA256' "Hash Algorithm
if_key = lv_binary_secret "HMAC Key
if_data = 'abc' "Data
IMPORTING
ef_hmacb64string = data(lv_hmac_result) "HMAC value as base64-encoded string
).`enter code here`

Base64 encode a javascript object

I have large Javascript objects which I would like to encode to base-64 for AWS Kinesis`
It turns out that:
let objStr = new Buffer(JSON.stringify(obj), 'ascii');
new Buffer(objStr, 'base64').toString('ascii') !== objStr
I'm trying to keep this as simple as possible.
How can I base-64 encode JSON and safely decode it back to its original value?
From String to Base-64
var obj = {a: 'a', b: 'b'};
var encoded = btoa(JSON.stringify(obj))
To decode back to actual
var actual = JSON.parse(atob(encoded))
For reference look here.
https://developer.mozilla.org/en/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
You misunderstood the Buffer(str, [encoding]) constructor, the encoding tells the constructor what encoding was used to create str, or what encoding the constructor should use to decode str into a byte array.
Basically the Buffer class represents byte streams, it's only when you convert it from/to strings that encoding comes into context.
You should instead use buffer.toString("base64") to get base-64 encoded of the buffer content.
let objJsonStr = JSON.stringify(obj);
let objJsonB64 = Buffer.from(objJsonStr).toString("base64");
When converting object to base64 I was getting out of latin range issues and character invalid error.
I made it work in my project with the below line.
Include the base64 and utf8 node packages and access them like this:
var bytes = base64.encode(utf8.encode(JSON.stringify(getOverviewComments())));
You can easily encode and decode from and to JSON/Base64 using a Buffer:
JSON to Base64:
function jsonToBase64(jsonObj) {
const jsonString = JSON.stringify(jsonObj)
return Buffer.from(jsonString).toString('base64')
}
Base64 to JSON:
function encodeBase64ToJson(base64String: string) {
const jsonString = Buffer.from(base64String,'base64').toString()
return JSON.parse(jsonString)
}
atob() and btoa() are outdated and should no longer be used.

How can I obfuscate a string in JavaScript?

Basically, I want to make a game in JavaScript and allow a user to get a copy paste-able code which stores their data. In reality, this "code" is actually obfuscated JSON that can be decoded by the application later.
I don't need much security, as I am aware that if people put some effort in they can view/modify the save, and I have no interest in stopping them. I just want the average user to not be tempted and/or see unnecessary information.
Thanks in advance.
you can use base64 encoding to encode your json String. it would be faster approach.
If you with pure javascript :
var encodedData = btoa("stringToEncode");
If you are using nodejs:
base-64 encoding:
var encodedStr = new Buffer("Hello World").toString('base64')
decode to original value:
var originalString = new Buffer("SGVsbG8gV29ybGQ=", 'base64').toString('utf-8')
Well... given that there is no security concern and you only want users to see what appears to be garbled data you can "encode" all the json data
var jsonData = {"key":"value"};
// turn it into a string
var jsonString = JSON.stringify(jsonData);
// replace some letters
var awkardString = jsonString.replace(/a/g, '!Ax6'); // be carefull, you should replace a letter with a pattern that does not already exist on the string.
// encode it with some type of reversible encoding
var garbledData = encodeURI(jsonString);
// output is: %7B%22key%22:%22v!Ax6lue%22%7D
// to "decode" it do the same steps in reverse
awkardString = decodeURI(garbledData);
jsonString = awkardString.replace(/!Ax6/g, 'a'); // now you see, if '!Ax6' existed on the source string, you would loose it and get an 'a' in return. That is why the replacement should be as unique as possible
jsonData = JSON.parse(jsonString);

Parsing email from query string

I'm trying to create a piece of JS that will parse the email address from a url query string. Once that's done, I want it to send the results to anaytics for use in whatever I need to use it in.
so basically abc.com?wemail=abc#abc.com
<script type="text/javascript">
/*Extracts email from query string using ?email=name#abc.com*/
function GetUrlValue(VarSearch) {
var SearchString = window.location.search.substring(1);
var VariableArray = SearchString.split('&');
for (var i = 0; i < VariableArray.length; i++) {
var KeyValuePair = VariableArray[i].split('=');
if (KeyValuePair[0] == VarSearch) {
return KeyValuePair[1];
}
}
The anayltics is receiving the data, but the # sign is being replaced by %40 and it isn't coding it the way I want.
I'm sure that is it simple, but what changes need to be made to ensure this works properly?
The %40 symbol you are getting is the encoded url symbol for the # symbol.
Refer to the link which refers to the usage of
decodeURIComponent() function in javascript
url decode function javascript
please check this link out
The # symbol is a originally used when the URL contains authentication info:
user:pass#myurl.com
So modern browsers will encode the # symbol in query string to %40. Use decodeURIComponent() to decode the value before sending to Segment.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent

make a javascript HMAC token

I am trying to emulate the following .NET code in javascript using the Crypto.js library.
var hashInput = "public=ID1000000001::routetype=POST::route=personsearch::key1=ID1000000001::key2=1043"
byte[] inputBytes = new byte[hashInput.Length * sizeof(char)];
System.Buffer.BlockCopy(hashInput.ToCharArray(), 0, inputBytes,0,inputBytes.Length);
byte[] keyBytes = HexadecimalStringToByteArray("A_HEX_STRING_GOES_HERE");
var hmac = HMACSHA256.Create();
hmac.Key = keyBytes;
var clientHash = hmac.ComputeHash(inputBytes);
This gives me a ByteArray which is used as part of POST to a WebAPI in the form of
[41,197,254,91,244,87.....] etc.
I want to make the same exact byte array in a javascript client but i am having diffculty getting this. I have tried the following:
var stringToHash = 'public=ID1000000001::routetype=POST::route=personsearch::key1=ID1000000001::key2=1043';
var privateKey = 'A_HEX_STRING_GOES_HERE';
var hash = CryptoJS.HmacSHA256(stringToHash, privateKey);
//this results in a WordArray, which can be converted to many types
//however i cannot get the byte array as in the .net example
//i.e. i just want to get [41,197,254,91,244,87....] etc.
I can see on the documentation for Crypto.js how to convert to base64, and other formats, but not to the ByteArray which i need.
Any ideas?
--UPDATE
Thanks for the advice on not using BlockCopy, and also for pointing me in the direction of the encoding issues which i had completely neglected.
This was part of the issue. The other part was that i had managed to misuse the HMACSHA256 class. I found (after several, several hours) that the .NET code was not producing the correct hash value.
It turns out this code DID produce the correct Hash:
var hashInput = "a::string::to::hash";
var privateKey = "C0B615950F9D577A4EAF64C9B4F2E50F3DA2C6BB6F790FA346E9732788B29A08AC5444F1B82984DB190A75D3861CC4802D598EBF0025FD1C327928F43EB1C80E";
byte[] inputBytes = Encoding.UTF8.GetBytes(hashInput);
byte[] keyBytes = Encoding.UTF8.GetBytes(privateKey);
HMACSHA256 hmac = new HMACSHA256(keyBytes);
hmac.Initialize();
var clientHash = hmac.ComputeHash(inputBytes);
var base64 = Convert.ToBase64String(clientHash);
Lucky for me my WebAPI is not live yet!
The problem is probably the character encoding. You should use for instance the method encode_utf8(stringValue) in JavaScript and new UTF8Encoding.getBytes(String value) in .NET, to make sure that the character encodings match. Note that modern cryptography is based on bytes, not on strings or characters. Using System.Buffer.BlockCopy() to encode characters is really bad practice.

Categories