Generate HMAC SHA Algorithm using URI and Key - javascript

I wrote a Java program which generates HMAC SHA hash code, But due to some reason I have to write the same code in NodeJs/JavaScript. I tried googling around but did not get anything. In this Java code, I am passing URI and Key as arguments, to generate the hash code, where URI contains Timestamp.
The java code is as :
public static String calcMAC(String data, byte[] key) throws Exception {
String result=null;
SecretKeySpec signKey = new SecretKeySpec(key, SecurityConstants.HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(SecurityConstants.HMAC_SHA1_ALGORITHM);
mac.init(signKey);
byte[] rawHmac;
try {
rawHmac = mac.doFinal(data.getBytes("US-ASCII"));
result = Base64.encodeBase64String(rawHmac);
} catch (Exception e) {
e.printStackTrace();
}
return result.trim();
}
public static void main(String args[]) {
String timestamp = args[0];
String key = "d134hjeefcgkahvg32ajkdbaff84ff180";
String out = null;
try {
out = calcMAC("/req?app_id=47ca34" + timestamp + "=2018-05-22T12:02:15Z",
key.getBytes());
System.out.println(URLEncoder.encode(out, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
}
Is it possible to achieve the same goal in NodeJs/JavaScript?
Note:: I have to call this script from Postman pre-request script.

The crypto module should do this for you, you can substitute the 'data' variable with whatever you want to hash:
const crypto = require('crypto');
const data = 'The fault dear Brutus lies not in our stars';
const key = Buffer.from('d134hjeefcgkahvg32ajkdbaff84ff180', 'utf8');
const hash = crypto.createHmac('sha1', key).update(data).digest('base64');
const uriEncodedHash = encodeURIComponent(hash);
console.log('Hash: ' + uriEncodedHash);
Hashing the data in both Java and Node.js gives me the result (URI Encoded) of:
TJJ3xj93m8bfVpGoucluMQqkB0o%3D
The same Java code would be:
public static void main(String args[]) {
String data = "The fault dear Brutus lies not in our stars";
String key = "d134hjeefcgkahvg32ajkdbaff84ff180";
String out = null;
try {
out = calcMAC(data, key.getBytes());
System.out.println(URLEncoder.encode(out, "UTF-8"));
} catch (Exception e) {
e.printStackTrace();
}
}
Again, we can put anything into 'data' we want.

Related

Android Capacitor JS Plugin does not reply

I am working on a java plugin that is supposed to recieve some info from a js vue3 program and then do a URL post operation, and then return some of the info found back to the js code. I am using capacitor and android. This is my error message:
2022-08-22 13:46:23.773 27544-27544/org.theguy.GptEtc E/Capacitor/Console: File: http://localhost/js/app.6577adf2.js - Line 1 - Msg: Uncaught (in promise) SyntaxError: Unexpected token o in JSON at position 1
I think this means that something other than valid JSON is being delivered to the js code. I know that the app is delivering info to the java android class. This is some of my java code.
#CapacitorPlugin(name = "URLPOST")
public class PluginURLPost extends Plugin {
#PluginMethod()
public void post(PluginCall call) {
String post_url = call.getString("post_url", "");
String bearer = call.getString("bearer", "pipeline_");
JSObject ret = new JSObject();
try {
String value = this.doPost(post_url, bearer);
System.out.println("value " + value);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(value));
ResultPreview preview = gson.fromJson(reader, ResultPreview.class);
String val = preview.getResult_preview()[0][0];
val = "result string here."; // <-- add this for easy testing
ret.put("response_text", val.replace("\n", "\\n"));
System.out.println("response here: " + val);
}
catch (Exception e) {
e.printStackTrace();
}
//call.setKeepAlive(true);
call.resolve(ret);
}
OkHttpClient client = new OkHttpClient();
public static final MediaType JSON
= MediaType.parse("application/json; charset=utf-8");
String doPost(String post_url, String bearer ) throws IOException {
// ... do some post request here ...
return response_body;
}
}
class ResultPreview {
#SerializedName("result_preview")
String [][] result_preview ;
public void setResult_preview(String[][] result) {
this.result_preview = result;
}
public String[][] getResult_preview() {
return this.result_preview;
}
}
This is some of my js code.
import { registerPlugin } from "#capacitor/core";
const URLPOST = registerPlugin("URLPOST");
const request = {
"line": line,
"pipeline_model": details[engine]["app_model"].trim(),
"bearer": details[engine]["api_key"].trim(),
"post_url": details[engine]["url"].trim(),
"length": 25,
"top_k": 50
};
console.log("request", request);
var {response_text} = await URLPOST.post(request);
console.log("response_text 1",response_text);
I don't know what to do.
I tried this, and things work better. I don't know if this is the ultimate solution.
#PluginMethod()
public void post(PluginCall call) {
bridge.saveCall(call); // <-- add this
call.release(bridge); // <-- add this
String pipeline_model = call.getString("pipeline_model", "pipeline_");
String post_url = call.getString("post_url", "");
JSObject ret = new JSObject();
try {
String value = this.doPost(post_url);
Gson gson = new Gson();
JsonReader reader = new JsonReader(new StringReader(value));
ResultPreview preview = gson.fromJson(reader, ResultPreview.class);
String val = preview.getResult_preview()[0][0];
ret.put("response_text", val.replace("\n", "\\n"));
System.out.println("response here: " + val);
}
catch (Exception e) {
e.printStackTrace();
}
call.resolve(ret);
}
This is not found on the capacitor site, but instead I found it digging around the internet.

How to get same base64 hmac in java as in nodejs code?

I am trying to create a base64 hmac for sha256. I have two codes for the same, one in JS and other in Java,though I am doing it in android and a kotlin one will help me as well. I have mostly used codes from other SO answers only. The one in node js seems to give correct results and matches with the backend but in java is does not. Here are the codes
const crypto = require('crypto')
const base64urlm = require('base64url')
console.log('hello')
var yourMessage = 'Pritish8-s9';
var sharedSecret = 'Nilesh/ev12/';
//generate hmac sha256 hash
var hmacSignature = crypto.createHmac('SHA256', new Buffer(sharedSecret, 'base64')).update(yourMessage).digest('base64');
hmacSignature = base64urlm.fromBase64(hmacSignature)
console.log(hmacSignature)
It gives the output as
_eiq1peyHuPx8yQwzORwoT7wcNdzv2Y0LUp_E70aIvM
The above is the correct value. Now following is the java code.
package com.drivertest.hmactest;
import android.util.Log;
import org.apache.commons.codec.binary.Hex;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
public class HMAC {
public static String cal() {
try {
String secret = "Nilesh/ev12/";
String message = "Pritish8-s9";
byte[] secretByteArray = new byte[0];
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
secretByteArray = Base64.getEncoder().encode(secret.getBytes());
}
//byte[] secretByteArray = Base64.encodeBase64(secret.getBytes("utf-8"), true);
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secretByteArray, "HmacSHA256");
sha256_HMAC.init(secret_key);
String hash = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
hash = Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(message.getBytes()));
}
System.out.println("hash "+hash);
Log.d("++++",hash);
return hash;
}
catch (Exception e){
System.out.println("Error");
}
return "";
}
public static String encode(String key, String data) {
try {
String secret = "Nilesh/ev12/";
String message = "Pritish8-s9";
key=secret;
data=message;
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256_HMAC.init(secret_key);
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKey);
String hash = android.util.Base64.encodeToString(sha256_HMAC.doFinal(message.getBytes()), android.util.Base64.DEFAULT);
Log.d("++",hash);
return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
}
It is a class where I have attempted to do it in different ways with other SO answers. Unfortunately I get a value like
8i/ce0u0GZ+JhL3yblsGhaMnFC0UKkUwJSQSXZ3536s=
or
f22fdc7b4bb4199f8984bdf26e5b0685a327142d142a45302524125d9df9dfab
So can anyone help me in writing java/kotlin code for the same and get the same value like the above in nodejs ?
PS : I have verified the java results on random sites and they seem to match, but my api is failing with this value , and will only work if it can match with that os nodejs, so it is incorrect in that sense.
Thank you :)
There are two differences between your nodejs and Java implementations.
First and the most important: in nodejs you decode your secret using base64, while in Java you encode it:
Base64.getEncoder().encode(secret.getBytes())
Replace it with:
Base64.getDecoder().decode(secret.getBytes())
Second, in nodejs you use URL variant of base64 (base64urlm) when encoding the final result. In Java you use a regular base64. Replace it with:
Base64.getUrlEncoder().encodeToString(...)

Encrypt Javascript - Decrypt Java

I want to encrypt the password before to submit.
app.js
function encryptPass() {
var encrypted = CryptoJS.AES.encrypt("Test", "1234").toString();
$("#password").val(encrypted)
}
After to submit, the tool call method: decrypt
pass.java
public static String decrypt(String strToDecrypt) {
def result
try {
if (strToDecrypt) {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, obtenerSecretKey());
result = new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt)))
}
} catch (Exception e) {
println e
throw e;
} finally {
return result
}
}
private static SecretKeySpec obtenerSecretKey () {
MessageDigest sha = MessageDigest.getInstance("SHA-1");
def semilla = "1234"
def key = sha.digest(semilla.getBytes("UTF-8"));
key = Arrays.copyOf(key, 16);
return new SecretKeySpec(key, "AES");
}
I'm getting this error:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
Any suggestions or other encrypt type?

Crypto.js SHA1 vs MessageDigest java SHA1: why different results?

I need to encrypt a string. The initial version was written in Java, but it needs to be rewritten in javascript now. But i have different results.
Here is the code in java:
Java Version:
private static String getEncrypt(String input, String salt) throws NoSuchAlgorithmException {
byte[] raw_salt = Base64.getDecoder().decode(salt);
byte[] raw_data = input.getBytes(StandardCharsets.UTF_8);
byte[] test_data = new byte[raw_salt.length + raw_data.length];
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
System.arraycopy(raw_salt, 0, test_data, 0, raw_salt.length);
System.arraycopy(raw_data, 0, test_data, raw_salt.length, raw_data.length);
mdTemp.update(test_data);
byte[] bytes = mdTemp.digest();
return new String(Base64.getEncoder().encode(bytes));
}
input: 123456789
salt: pMm6kWsoWjR18sWKnoG4Az==
output: 6u/VAXS9ZKmLEbHw/OZ1AVarth4=
JS Version: (use crypto.js)
const crypto = require("crypto");
function getEncrypt(input, salt){
const sha1 = crypto.createHash('sha1');
const beforeCrypto = salt + input;
const afterCrypto = sha1.update(beforeCrypto).digest('base64');
return afterCrypto;
}
input: 123456789
salt: pMm6kWsoWjR18sWKnoG4Az==
output: ie/3j+92nxvcNT5i+3WUJbWsEAg=
The MessageDigest method in java requires me to enter input in byte[] format. While in javascript, I use ·string· type input.
They also use salt to make the encryption more safe, but it brings more different that i cannot rewrite it in javascript.
I try many ways to solve it. But I still cannot get the same result.
The following snippet also gives me the correct answer:
98O8HYCOBHMq32eZZczDTKeuNEE=
There must be some detail in your code that is different.
One thing I did was to use the UTF8 standard charset, to avoid any mishaps with the way "utf-8", vs. "UTF8" etc is specified.
Your code does not compile (missing return type on getEncrypt, for example) so there might be something else that is different.
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Main {
private static String getEncrypt(String input) throws NoSuchAlgorithmException {
byte[] raw_data = input.getBytes(StandardCharsets.UTF_8);
MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
mdTemp.update(raw_data);
byte[] bytes = mdTemp.digest();
return new String(Base64.getEncoder().encode(bytes));
}
public static void main(String[] args){
try {
System.out.println(getEncrypt("123456789"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
}

Import and consume javascript in android activity

I am trying to establish a connection between android app and webservice. I am sending the encrypted username and password using AES encryption. But my encrypted username and password do not match with the webservice and responses as false.
Same thing I am doing in website encrypting credential with AES encryption in javascript and validating user with webservice everything works fine. I checked AES output for android defers from javascript output.
Bellow code is used in android to encrypt username and password
public class RijndaelCrypt {
public static final String TAG = "EncryptLog2";
private static String TRANSFORMATION = "AES/CBC/PKCS7Padding";
private static String ALGORITHM = "AES";
private static String DIGEST = "MD5";
private static Cipher _cipher;
private static SecretKey skeySpec;
private static IvParameterSpec _IVParamSpec;
//16-byte private key
private static byte[] IV = MainActivity.key.substring(0,16).getBytes();
/**
* Constructor
*
* #password Public key
*/
public RijndaelCrypt(String password) {
try {
//Encode digest
MessageDigest digest;
digest = MessageDigest.getInstance(DIGEST);
skeySpec = new SecretKeySpec(digest.digest(password.getBytes()), ALGORITHM);
//Initialize objects
_cipher = Cipher.getInstance(TRANSFORMATION);
_IVParamSpec = new IvParameterSpec(IV);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, "No such algorithm " + ALGORITHM, e);
} catch (NoSuchPaddingException e) {
Log.e(TAG, "No such padding PKCS7", e);
}
}
/**
* Encryptor.
*
* #return Base64 encrypted text
* #text String to be encrypted
*/
public String encrypt(byte[] text) {
byte[] encryptedData;
try {
_cipher.init(Cipher.ENCRYPT_MODE, skeySpec, _IVParamSpec);
encryptedData = _cipher.doFinal(text);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
return Base64.encodeToString(encryptedData, Base64.DEFAULT);
}
/**
* Decryptor.
*
* #return decrypted text
* #text Base64 string to be decrypted
*/
public String decrypt(String text) {
try {
_cipher.init(Cipher.DECRYPT_MODE, skeySpec, _IVParamSpec);
byte[] decodedValue = Base64.decode(text.getBytes(), Base64.DEFAULT);
byte[] decryptedVal = _cipher.doFinal(decodedValue);
return new String(decryptedVal);
} catch (InvalidKeyException e) {
Log.e(TAG, "Invalid key (invalid encoding, wrong length, uninitialized, etc).", e);
return null;
} catch (InvalidAlgorithmParameterException e) {
Log.e(TAG, "Invalid or inappropriate algorithm parameters for " + ALGORITHM, e);
return null;
} catch (IllegalBlockSizeException e) {
Log.e(TAG, "The length of data provided to a block cipher is incorrect", e);
return null;
} catch (BadPaddingException e) {
Log.e(TAG, "The input data but the data is not padded properly.", e);
return null;
}
}
}
Can i use that javascript in android without WebView.
Note: webservice is built in .net c#.
Sorry for any grammatical mistake, This is my 1st question on StackOverflow.

Categories

Resources