I have code like this in JSR223 Sampler , and it gets passed also. But not able to see any output as response. Not sure what i have missed in it.
import android.util.Base64;
import java.security.spec.X509EncodedKeySpec;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PublicKey;
import javax.crypto.Cipher;
String Original_String= ctx.getPreviousResult().getResponseDataAsString();
String Trim1=Original_String.substring(0, Original_String.lastIndexOf(","));
String Trim2=Trim1.replaceFirst("-----BEGIN PUBLIC KEY-----", "");
String Trim3=Trim2.replaceFirst("-----END PUBLIC KEY-----", "");
String[] parts = Trim3.split(":");
String myString = parts[1].substring(1, parts[1].length()-1);
String final_string=myString.replaceAll("\\\\n", "");
log.info(final_string);
String input="4000221111111111";
try{
byte[] byteKey = Base64.decode(final_string.getBytes(), Base64.DEFAULT);
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
Key k=kf.generatePublic(X509publicKey);
//return (PublicKey) k;
def cipher = Cipher.getInstance("RSA/NONE/OAEPPadding","BC");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] encryptedBytes = cipher.doFinal(input.getBytes());
log.info( Base64.encodeToString(encryptedBytes, Base64.NO_WRAP));
}
catch(Exception e){
e.printStackTrace();
}
Could any one help me out on this Please ?
If you want your JSR223 Sampler to have response data you need to go for one of the following approaches:
return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
or even better:
SampleResult.setResponseData(Base64.encodeToString(encryptedBytes, Base64.NO_WRAP), 'UTF-8')
See SampleResult class JavaDoc for all available functions, this way you have full control of response code, headers, body, message, etc.
You may also be interested in Apache Groovy - Why and How You Should Use It article which contains comprehensive information on Groovy scripting in JMeter tests.
Related
I am trying to figure out how to do RSA encryption with OAEPwithMD5andMGF1Padding in node-rsa.
Below is my code in node.js.
var NodeRSA = require('node-rsa');
var fs = require('fs');
var publicKey = '-----BEGIN PUBLIC KEY-----\n*****\n-----END PUBLIC KEY-----';
var privateKey = '-----BEGIN RSA PRIVATE KEY-----\n*****\n-----END RSA PRIVATE KEY-----'
const constants = require('constants');
var options1 = {
environment: 'node',
encryptionScheme: {
scheme: 'pkcs1_oaep',
hash: 'md5', //hash using for scheme
}
}
var text = 'This is the string to be encrypted using RSA!';
var encryptKey = new NodeRSA(publicKey, 'pkcs8-public', options1);
encryptKey.setOptions(options1)
var encrypted = encryptKey.encrypt(text, 'base64');
console.log(encrypted);
console.log(encryptKey.isPublic(true))
var options2 = {
environment: 'node',
encryptionScheme: {
scheme: 'pkcs1_oaep', //scheme
hash: 'md5', //hash using for scheme
}
}
var decryptKey = new NodeRSA(privateKey, 'pkcs1', options2);
decryptKey.setOptions(options2)
var decrypted = decryptKey.decrypt(encrypted, 'utf8');
console.log('decrypted: ', decrypted);
Result of running the above code.
f1zi49yKJSqkWW2J3Jt2lf1fe79JgqufFawYESOJRqhM4YEcGQBcaP39yptn7vShhsJBCTUOsbiV1YcW/YUzoaSQzX9YU0iTMara7h+LNLUrq4FZ2twy5X3uyAP1sUD1SnvQvlRJqrAh23UAwnx31rv6ySC+XgpLPR7wHYaDbSgyQKiF3qhGRj2SIAZ6weziNPfEm9FifBVjnWMvGDQYbjLbanbnSriN+bWpRtXKH9pQqMoskkiMwCviJdKtKzz/vVr0littPLnw0ojbsGSPKQPS3U3xCH3QiBmxEegc0uy3sJdk6aH/2SMuoPzGu7VS+PsLQctxnvKNnC9qsLFWyA==
true
decrypted: This is the string to be encrypted using RSA!
Below is my code in JAVA
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class DecryptATT {
public static void main(String[] args) throws Exception {
String encryptedData = "f1zi49yKJSqkWW2J3Jt2lf1fe79JgqufFawYESOJRqhM4YEcGQBcaP39yptn7vShhsJBCTUOsbiV1YcW/YUzoaSQzX9YU0iTMara7h+LNLUrq4FZ2twy5X3uyAP1sUD1SnvQvlRJqrAh23UAwnx31rv6ySC+XgpLPR7wHYaDbSgyQKiF3qhGRj2SIAZ6weziNPfEm9FifBVjnWMvGDQYbjLbanbnSriN+bWpRtXKH9pQqMoskkiMwCviJdKtKzz/vVr0littPLnw0ojbsGSPKQPS3U3xCH3QiBmxEegc0uy3sJdk6aH/2SMuoPzGu7VS+PsLQctxnvKNnC9qsLFWyA==";
// Cipher decrypt = Cipher.getInstance("RSA/ECB/OAEPwithMD5andMGF1Padding");
Cipher decrypt = Cipher.getInstance("RSA/ECB/OAEPwithSHA1andMGF1Padding");
RSAPrivateKey privateKey = getPrivateKey();
System.out.println("test");
decrypt.init(Cipher.DECRYPT_MODE, privateKey);
byte[] original = decrypt.doFinal(Base64.getDecoder().decode(encryptedData));
System.out.println(new String(original));
}
public static RSAPrivateKey getPrivateKey() throws Exception {
String keyPath = "/Users/C.SubbiahVeluAngamuthu/Desktop/Samsung/Docs/att/Keys/3_my_testing/pkcs8_key";
File privKeyFile = new File(keyPath);
BufferedInputStream bis = null;
try {
bis = new BufferedInputStream(new FileInputStream(privKeyFile));
} catch (FileNotFoundException e) {
throw new Exception("Could not locate keyfile at '" + keyPath + "'", e);
}
byte[] privKeyBytes = new byte[(int) privKeyFile.length()];
bis.read(privKeyBytes);
bis.close();
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
KeySpec ks = new PKCS8EncodedKeySpec(privKeyBytes);
RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(ks);
return privKey;
}
}
Below is the result of running the JAVA code
test
This is the string to be encrypted using RSA!
But when I change the cipher instance from RSA/ECB/OAEPwithSHA1andMGF1Padding to "RSA/ECB/OAEPwithMD5andMGF1Padding"(which I am assuming is the one that I mentioned in encryptionScheme of node.js program) it throws the below error
test
Exception in thread "main" javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadOAEP(RSAPadding.java:499)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:293)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:363)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at DecryptATT.main(DecryptATT.java:26)
Could some one help me where it is going wrong ?
RSAES-OAEP is parametrized by
the hash Hash used by OAEP, and its width in octet noted hLen
the size of the public key, k octets
the Mask Generation Function (MGF) used by OAEP
Almost invariably, the MGF is MFG1, which itself is parametrized by the hash Hash' used by MFG1, and its width in octet noted hLen' (the ' is not in the standard, I'm making up this notation).
You guessed it, there's noting stating that Hash and Hash' are the same, or even that hLen= hLen'.
And, believe me, unless something special is done about it, under a typical Java environement "RSA/ECB/OAEPwithMD5andMGF1Padding" (if supported) will use MD5 for Hash but default to SHA-1 for Hash'; when perhaps node.js uses MD5 for both.
Facing a similar problem with SHA-256 rather than MD5, we can coerce the nice Java runtime to do the Right Thing with
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey, new OAEPParameterSpec(
"SHA-256", "MGF1", MGF1ParameterSpec.SHA256, PSource.PSpecified.DEFAULT
));
I fear you won't be so lucky, since MGF1ParameterSpec seems to never have had an MD5 specifier; but perhaps give a try to new MGF1ParameterSpec("MD5") to get one before giving up.
If one really needs to get the job done under Java, one option is to roll one's RSAES-OAEP with MD5 on top of Cipher invoked with "RSA/ECB/NoPadding", which will perform textbook RSA, by far the most complex building block (at least, all the key management, modular arithmetic, and ability to offload to an HSM is taken care of). That's few dozens lines of code, including MFG1.
Another option might be BouncyCastle.
It's a bad idea to keep using MD5, even in MFG1. And it is an unmitigated disaster to use it as the main hash if adversaries can choose a part of the message at a time when they know what's before that part. If in doubt, don't use MD5.
I want to setup an endpoint for testing webhooks from third parties. Their documentation is uniformly poor and there is no way ahead of time to tell exactly what I will be getting. What I've done is setup an ApiController that will just take a request and add a row to a table with what they are sending. This lets me at least verify they are calling the webhook, and to see the data so I can program to it.
// ANY api/webook/*
[Route("{*path}")]
public ActionResult Any(string path)
{
string method = Request.Method;
string name = "path";
string apiUrl = Request.Path;
string apiQuery = Request.QueryString.ToString();
string apiHeaders = JsonConvert.SerializeObject(Request.Headers);
string apiBody = null;
using (StreamReader reader = new StreamReader(Request.Body))
{
apiBody = reader.ReadToEnd();
}
Add(method, name, apiUrl, apiQuery, apiHeaders, apiBody);
return new JsonResult(new { }, JsonSettings.Default);
}
This works great, except for this new webhook I am usign that posts as form data so some middleware is reading the body and it ends up null in my code. Is there any way to disable the model processing so I can get at the request body?
You could actually use model binding to your advantage and skip all that stream reading, using the FromBody attribute. Try this:
[Route("{*path}")]
[HttpPost]
public ActionResult Any(string path, [FromBody] string apiBody)
I'm new to Retrofit. I make a POST request to a website. Website returns response as HTML. So I will parse it. However Retrofit try to parse it as JSON. How can do it?
#FormUrlEncoded
#POST("/login.php?action=login")
void postCredentials(#Field("username") String username,
#Field("password") String password);
Should I use a callback?
Retrofit uses a converter to process responses from endpoints and requests as well. By default, Retrofit uses GsonConverter, which encoded JSON responses to Java objects using the gson library. You can override that to supply your own converter when constructing your Retrofit instance.
The interface you need to implement is available here (github.com). Here's a short tutorial as well, although for using Jackson library, many bits are still relevant: futurestud.io/blog
Also note that the converter works both ways, converting requests and responses. Since you want HTML parsing in one direction only, you may want to use GsonConverter in your custom converter, to convert outgoing Java objects to JSON, in the toBody method.
May be not the best solution but this how i managed to get the source of an html page with retrofit:
MainActivity.java
ApiInterface apiService = ApiClient.getClient(context).create(ApiInterface.class);
//Because synchrone in the main thread, i don't respect myself :p
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
//Execution of the call
Call<ResponseBody> call = apiService.url();
response = call.execute();
//Decode the response text/html (gzip encoded)
ByteArrayInputStream bais = new ByteArrayInputStream(((ResponseBody)response.body()).bytes());
GZIPInputStream gzis = new GZIPInputStream(bais);
InputStreamReader reader = new InputStreamReader(gzis);
BufferedReader in = new BufferedReader(reader);
String readed;
while ((readed = in.readLine()) != null) {
System.out.println(readed); //Log the result
}
ApiInterface.java
#GET("/")
Call<ResponseBody> url();
ApiClient.java
public static final String BASE_URL = "https://www.google.com";
private static Retrofit retrofit = null;
public static Retrofit getClient(Context context) {
if (retrofit==null) {
OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
.build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(ScalarsConverterFactory.create())
.client(okHttpClient)
.build();
}
return retrofit;
}
I am trying to write a http client which connects to a kerberos enabled tomcat(tested to be correct using browsers). It first gets the response code (which will be 401) and as according continue with its work.
The code is
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.*;
public class SampleHTTP2 {
static final String kuser = "correctusername"; // your account name
static final String kpass = "correctpassword"; // your password for the account
static class MyAuthenticator extends Authenticator {
public PasswordAuthentication getPasswordAuthentication() {
//System.out.println("I am reaching here");
// I haven't checked getRequestingScheme() here, since for NTLM
// and Negotiate, the username and password are all the same.
System.err.println("Feeding username and password for "
+ getRequestingScheme());
return (new PasswordAuthentication(kuser, kpass.toCharArray()));
}
}
public static void main(String[] args) throws Exception {
URL url = new URL("http://mycompname:6008/examples/");
HttpURLConnection h1 = (HttpURLConnection) url.openConnection();
int rescode = h1.getResponseCode();
System.out.println(rescode);
System.setProperty("sun.security.krb5.debug", "true");
System.setProperty("java.security.auth.login.config", "C:\\login2.conf");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
System.setProperty("java.security.krb5.conf", "C:\\krb5.ini");
if(rescode == 401){
Authenticator.setDefault(new MyAuthenticator());
URL url2 = new URL("http://mycompname/examples/");
URLConnection h2 = url2.openConnection();
InputStream ins2 = h2.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(ins2));
String str;
while((str = reader.readLine()) != null)
System.out.println(str);
}
}
}
Now when i comment the line:-
int rescode = h1.getResponseCode();
and put if(true) instead of if(rescode ==401), it works.
I am not sure what is going wrong. getResponseCode() internally calls getinputStream and thus I have used a separate url connection. Even still it does not work
P.S - Server is perfectly set up and the Authenticator class is also correct.
public boolean setContacts(String name, String number) {
serviceUrl = "http://...../sample.php?method=setcontacts";
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("name", name));
nameValuePairs.add(new BasicNameValuePair("num", number));
try {
httpClient = new DefaultHttpClient();
httpPost = new HttpPost(serviceUrl);
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse httpResponse = httpClient.execute(httpPost);
..................
}
In this code i sending a single row having name and number to server its working fine,
but i want to send a list of name and number like
ArrayList<Strng[]> contactsList =...............;
so how i can implement this
public boolean setContacts(ArrayList<String[]> contactsList) {
}
if you have any alternative way please suggest me thanks in advance.
Serialize the information as a string and send it in the POST body. There are many ways to skin this cat, but the big 3 are:
Form encoding
XML
JSON