Sending request to REST API using oAuth - fatsecret API - java

I try to send valid request to REST API which uses oAuth. I keep receiving respond : "Invalid signature"
Here's steps I do to generate request:
Build Request:
public String buildRequest() {
ArrayList<String> params = new ArrayList<>(generateParams());
params.add("oauth_signature=" + sign(buildSignatureBaseString()));
Collections.sort(params);
return join(params.toArray(template), "&");
}
Creating Signature Base String:
public String buildSignatureBaseString(){
StringBuilder builder = new StringBuilder();
builder.append(METHOD);
builder.append("&");
builder.append(percentEncoding(URL));
builder.append("&");
builder.append(percentEncoding(join(generateParams().toArray(template), "&")));
return builder.toString();
}
Generating parameters sorted in natural order:
private ArrayList<String> generateParams() {
ArrayList<String> params = new ArrayList<>();
params.add("oauth_consumer_key=" + "...");
params.add("oauth_signature_method=HMAC-SHA1");
params.add("oauth_timestamp=" + Long.valueOf(System.currentTimeMillis() / 1000).toString());
params.add("oauth_nonce=" + getNonce());
params.add("oauth_version=1.0");
params.add("format=json");
params.add("method=foods.search");
params.add("search_expression=pasta");
Collections.sort(params);
return params;
}
Creating Signature Base String:
public String buildSignatureBaseString(){
StringBuilder builder = new StringBuilder();
builder.append(METHOD);
builder.append("&");
builder.append(percentEncoding(URL));
builder.append("&");
builder.append(percentEncoding(join(generateParams().toArray(template), "&")));
return builder.toString();
}
Generating signature with HMAC-SHA1:
public String sign(String sbs) {
String key = <SharedSecret> + "&";
SecretKeySpec sk = new SecretKeySpec(key.getBytes(Charset.forName("UTF-8")), ALGORITHM);
try {
Mac m = Mac.getInstance(ALGORITHM);
m.init(sk);
byte[] hmacEncoded = m.doFinal(sbs.getBytes(Charset.forName("UTF-8")));
byte[] base64Encoded = Base64.encode(hmacEncoded, Base64.DEFAULT);
return Uri.encode(new String(base64Encoded, Charset.forName("UTF-8")));
} catch (java.security.NoSuchAlgorithmException e) {
Log.w("FatSecret_TEST FAIL", e.getMessage());
return null;
} catch (java.security.InvalidKeyException e) {
Log.w("FatSecret_TEST FAIL", e.getMessage());
return null;
}
}
Could someone more experienced in this matter help?
Regards

The param entries from generateParams all are in the form tag=value. Your sign method seems only to return a value.
And: Are you sure the sign method does not throw? I this case you would return null, which you should check in the caller method and only add it to the params if it is not null

Related

solanaj - invalid transaction: Transaction failed to sanitize accounts offsets correctly

I'm using solanaj (Java sdk for solana) and trying to write hello-world example of solana-labs but getting this error on sendTransaction() 'invalid transaction: Transaction failed to sanitize accounts offsets correctly'. There is no additional information in the error about what I'm passing wrong. Can someone help me, here is my Java code:
'''
//establishConnection
RpcClient client = new RpcClient("http://127.0.0.1:8899");
//establishPayer
Long fee = Long.valueOf(0);
FeeCalculatorInfo feeCalculatorInfo = client.getApi().getFeeCalculatorForBlockhash(client.getApi().getRecentBlockhash());
fee += client.getApi().getMinimumBalanceForRentExemption(greetingMessageSize);
fee += feeCalculatorInfo.getValue().getFeeCalculator().getLamportsPerSignature() * 100;
if (payee == null) {
try {
String str = Files.readString(payeePath, StandardCharsets.UTF_8);
Gson gson = new Gson();
byte[] parsed = gson.fromJson(str, byte[].class);
payee = TweetNaclFast.Signature.keyPair_fromSecretKey(parsed);
payeePubKey = new PublicKey(payee.getPublicKey());
} catch (IOException e) {
e.printStackTrace();
}
}
Long lamportBalance = client.getApi().getBalance(payeePubKey);
if (lamportBalance < fee) {
String sign = client.getApi().requestAirdrop(payeePubKey, fee - lamportBalance);
ConfirmedTransaction confirmedTransaction = client.getApi().getConfirmedTransaction(sign);
}
Long lamportBalanceUpdated = client.getApi().getBalance(payeePubKey);
//checkProgram
try {
String str = Files.readString(programIdPath, StandardCharsets.UTF_8);
Gson gson = new Gson();
byte[] parsed = gson.fromJson(str, byte[].class);
programKeyPair = TweetNaclFast.Signature.keyPair_fromSecretKey(parsed);
programId = new PublicKey(programKeyPair.getPublicKey());
} catch (IOException e) {
e.printStackTrace();
}
AccountInfo programAccountInfo = client.getApi().getAccountInfo(programId);
String greetingSeed = "hellogreetingtoyou";
PublicKey greetingPubKey = null;
try {
greetingPubKey = PublicKey.createProgramAddress(Collections.singletonList(greetingSeed.getBytes()), programId);
} catch (Exception e) {
e.printStackTrace();
}
Account signer = new Account(payee.getSecretKey());
AccountInfo greetingAccountInfo = client.getApi().getAccountInfo(greetingPubKey);
if (greetingAccountInfo.getValue() == null) {
Transaction transaction = new Transaction();
long lamports = client.getApi().getMinimumBalanceForRentExemption(greetingMessageSize);
transaction.addInstruction(SystemProgram.createAccount(payeePubKey, greetingPubKey, lamports,
greetingMessageSize, PROGRAM_ID));
String signature = client.getApi().sendTransaction(transaction, signer);
}
'''
The program is mixing two separate concepts, creating accounts at the transaction level by adding SystemProgram.createAccount to your transaction, and creating PDA accounts using invoke_signed from within your program.
When trying to add SystemProgram.createAccount(payeePubkey, greetingPubkey,...), the transaction expects a signature from greetingPubkey, but only payeePubkey has signed, causing the error.
The easiest way to resolve this problem is to not use a program address for greetingPubkey, and instead do something like:
Account signer = new Account(payee.getSecretKey());
KeyPair greeting = TweetNaclFast.Signature.keyPair();
Account greetingSigner = new Account(greeting.getSecretKey());
PublicKey greetingPubkey = new PublicKey(greeting.getPublicKey())
Transaction transaction = new Transaction();
long lamports = client.getApi().getMinimumBalanceForRentExemption(greetingMessageSize);
transaction.addInstruction(SystemProgram.createAccount(payeePubKey, greetingPubKey, lamports, greetingMessageSize, PROGRAM_ID));
String signature = client.getApi().sendTransaction(transaction, signer, greetingSigner);
Note that I haven't tried to compile this!

How to create a Verification Key for my web Service from android?

in my current android app I need a key which is special to my App and hackers can't reach it , and I can verify that in each API call , is there any app specific key or way of creating one that is safe for using?
You cannot prevent hackers completely as there's always a way they exploit your but you can use this prevent calls this way so authorized user action will be more secure
Create hash with each login of user, and save that in database and in shared preference in the application, for every further call send hash to API and check against the database to check if user is authorized to call the API
Here's an example how you can create hash
Put this into your "Utils" class.
public static String getSha256Hash(String password) {
try {
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e1) {
e1.printStackTrace();
}
digest.reset();
return bin2hex(digest.digest(password.getBytes()));
} catch (Exception ignored) {
return null;
}
}
private static String bin2hex(byte[] data) {
StringBuilder hex = new StringBuilder(data.length * 2);
for (byte b : data)
hex.append(String.format("%02x", b & 0xFF));
return hex.toString();
}
public static String getCurrentTimeStamp(){
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String currentDateTime = dateFormat.format(new Date()); // Find todays date
return currentDateTime;
} catch (Exception e) {
e.printStackTrace();
return null;
}
public static String random() {
Random generator = new Random();
StringBuilder randomStringBuilder = new StringBuilder();
int randomLength = generator.nextInt(MAX_LENGTH);
char tempChar;
for (int i = 0; i < randomLength; i++){
tempChar = (char) (generator.nextInt(96) + 32);
randomStringBuilder.append(tempChar);
}
return randomStringBuilder.toString();
}
Example of use:
String token = Utils.getSha256Hash(getCurrentTimeStamp()+username+random())

Parsing Representation in Restlet

I am getting JSONException when I try to put in JSONObject.
#Post
public String someCode(Representation rep) throws ResourceException{
try {
rep.getText();
} catch (IOException e) {
LOGGER.error("Error in receiving data from Social", e);
}
try {
JSONObject json = new JSONObject(rep);
String username = json.getString("username");
String password = json.getString("password");
String firstname = json.getString("firstname");
String lastname = json.getString("lastname");
String phone = json.getString("phone");
String email = json.getString("email");
LOGGER.info("username: "+username); //JsonException
LOGGER.info("password: "+password);
LOGGER.info("firstname: "+firstname);
LOGGER.info("lastname: "+lastname);
LOGGER.info("phone: "+phone);
LOGGER.info("email: "+email);
} catch (JSONException e) {
e.printStackTrace();
}
return "200";
}
ERROR LOG:
org.json.JSONException: JSONObject["username"] not found.
at org.json.JSONObject.get(JSONObject.java:516)
at org.json.JSONObject.getString(JSONObject.java:687)
NOTE:
When I try to print rep.getText(), I get the following data:
username=user1&password=222222&firstname=Kevin&lastname=Tak&phone=444444444&email=tka%40gmail.com
Your rep object isn't a JSON object. I actually think that when you pass it to JSONObject(), it only captures a weird string. I suggest to parse it into an array :
Map<String, String> query_pairs = new LinkedHashMap<String, String>();
String query = rep.getText();
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
}
What you are Receiving in the POST is HTTP Form encoded data not JSON.
Restlet can and does handle these objects natively providing the Form object to interact with them. rather than new JSONObject(String) try new Form(String), for example:
String data = rep.getText();
Form form = new Form(data);
String username = form.getFirstValue("username");
I leave the remainder as an exercise to the reader.
Alternatively you will need to adjust the client submitting the data to encode it in JSON see http://www.json.org/ for the description of this syntax.
For reference the Form class is org.restlet.data.Form in the core Restlet library.

Retrieve Subject alternative names of X.509 certificate in java

I have tried using the solution provided in this link.
I am getting following error when i tried reading subject alternative names of X.509 Certificate
java.lang.NoSuchMethodError: org.bouncycastle.asn1.ASN1InputStream.readObject()Lorg/bouncycastle/asn1/DERObject;
At below line of code
ASN1InputStream decoder = new ASN1InputStream((byte[]) item.toArray());
DEREncodable encoded = decoder.readObject();
.der file is used to create certificate as follows.
X509Certificate cert=null;
fis = new FileInputStream(file.getAbsoluteFile()); //.der file
bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
try{
cert = cf.generateCertificate(bis);
}
catch (CertificateException e) {
e.printStackTrace();
}
List list=getSubjectAlternativeNames((X509Certificate) cert);
Below is the solution i got from the link mentioned above.
public static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
List<String> identities = new ArrayList<String>();
try {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
// Check that the certificate includes the SubjectAltName extension
if (altNames == null)
return Collections.emptyList();
// Use the type OtherName to search for the certified server name
for (List item : altNames) {
Integer type = (Integer) item.get(0);
if (type == 0)
// Type OtherName found so return the associated value
try {
// Value is encoded using ASN.1 so decode it to get the server's identity
ASN1InputStream decoder = new ASN1InputStream((byte[]) item.toArray()[1]);
DEREncodable encoded = decoder.readObject();
encoded = ((DERSequence) encoded).getObjectAt(1);
encoded = ((DERTaggedObject) encoded).getObject();
encoded = ((DERTaggedObject) encoded).getObject();
String identity = ((DERUTF8String) encoded).getString();
// Add the decoded server name to the list of identities
identities.add(identity);
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
// log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
}
catch (Exception e) {
// log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
e.printStackTrace();
}
// Other types are not good for XMPP so ignore them
//log.warn("SubjectAltName of invalid type found: " + certificate);
}
}
catch (CertificateParsingException e) {
e.printStackTrace();
// log.error("Error parsing SubjectAltName in certificate: " + certificate + "\r\nerror:" + e.getLocalizedMessage(),e);
}
return identities;
}
Is it that i have not used proper .jar file?
.jar i have used is --> bcprov-jdk16-1.45.jar
Suggest me where i have gone wrong.
I tried with your code for me it is working, I tested with a certificate exported from internet explorer
Internet Explorer -> Tools -> Internet Options -> Content -> Certificates -> Untrusted Publishers -> www.google.com
I exported this as ".cer", I made few changes to your code
public static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
List<String> identities = new ArrayList<String>();
try {
Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
if (altNames == null)
return Collections.emptyList();
for (List item : altNames) {
Integer type = (Integer) item.get(0);
if (type == 0 || type == 2){
try {
ASN1InputStream decoder=null;
if(item.toArray()[1] instanceof byte[])
decoder = new ASN1InputStream((byte[]) item.toArray()[1]);
else if(item.toArray()[1] instanceof String)
identities.add( (String) item.toArray()[1] );
if(decoder==null) continue;
DEREncodable encoded = decoder.readObject();
encoded = ((DERSequence) encoded).getObjectAt(1);
encoded = ((DERTaggedObject) encoded).getObject();
encoded = ((DERTaggedObject) encoded).getObject();
String identity = ((DERUTF8String) encoded).getString();
identities.add(identity);
}
catch (UnsupportedEncodingException e) {
log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
}
catch (Exception e) {
log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
}
}else{
log.warn("SubjectAltName of invalid type found: " + certificate);
}
}
}
catch (CertificateParsingException e) {
log.error("Error parsing SubjectAltName in certificate: " + certificate + "\r\nerror:" + e.getLocalizedMessage(),e);
}
return identities;
}
I saved the file to c:\aa1.cer
X509Certificate cert=null;
FileInputStream fis = new FileInputStream("c:\\aa1.cer");
BufferedInputStream bis = new BufferedInputStream(fis);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
if (bis.available() > 0)
try{
cert = (X509Certificate)cf.generateCertificate(bis);
}
catch (CertificateException e) {
e.printStackTrace();
}
System.out.println(CertificateInfo.getSubjectAlternativeNames(cert));
I got the output as [www.google.com, google.com]
Please check your certificate, I think the problem is your certificate
Many examples use hard-coded integers. For readability, I much prefer to use:
GeneralName.dNSName = 2
GeneralName.iPAddress = 7
... etc
The code:
public static String[] parseHostNames(X509Certificate cert) {
List<String> hostNameList = new ArrayList<>();
try {
Collection<List<?>> altNames = cert.getSubjectAlternativeNames();
if (altNames != null) {
for(List<?> altName : altNames) {
if(altName.size()< 2) continue;
switch((Integer)altName.get(0)) {
case GeneralName.dNSName:
case GeneralName.iPAddress:
Object data = altName.get(1);
if (data instanceof String) {
hostNameList.add(((String)data));
}
break;
default:
}
}
}
System.out.println("Parsed hostNames: " + String.join(", ", hostNameList));
} catch(CertificateParsingException | IOException e) {
System.err.println("Can't parse hostNames from this cert.");
e.printStackTrace();
}
return hostNameList.toArray(new String[hostNameList.size()]);
}
Note: The accepted answer checks for byte[], but won't compile on my system. I found some other examples using byte[] by calling new ASN1InputStream((byte[])data).readObject();, but I have no certificate to test it with, so I've removed it from my example.

Encrypt RDP password with Java

I've already tried the another solutions from SO, such as:
String password ="pwd";
WinCrypt.DATA_BLOB pDataIn = new WinCrypt.DATA_BLOB(password.getBytes(Charset.forName("UTF-16LE")));
WinCrypt.DATA_BLOB pDataEncrypted = new WinCrypt.DATA_BLOB();
System.out.println(Crypt32.INSTANCE.CryptProtectData(pDataIn, "psw",
null, null, null, WinCrypt.CRYPTPROTECT_UI_FORBIDDEN, pDataEncrypted));
StringBuffer epwsb = new StringBuffer();
byte[] pwdBytes= new byte [pDataEncrypted.cbData];
pwdBytes=pDataEncrypted.getData();
Formatter formatter = new Formatter(epwsb);
for ( final byte b : pwdBytes ) {
formatter.format("%02X", b);
}
System.out.println("password 51:b:"+ epwsb.toString());
or
Crypt32Util.cryptProtectData("12345".getBytes("UTF-16LE"), null, 0, "psw", null);
But all of them give different results for every time I run them, and they do not match the real password, that was saved by MSTSC or generated by RDP Password Hasher utility.
Does anyone know the solution, or CLI-utility that can encrypt password?
Here's my working solution (you need JNA platform, to get this working):
private static String ToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
Formatter formatter = new Formatter(sb);
for (byte b : bytes) {
formatter.format("%02x", b);
}
formatter.close();
return sb.toString();
}
private String cryptRdpPassword(String pass) {
try {
return ToHexString(Crypt32Util.cryptProtectData(pass.getBytes("UTF-16LE"), null, 0, "psw", null));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return "ERROR";
}
}

Categories