HMAC-SHA256 - how to? - java

I am doing HMAC-SHA256 in Android. Here is the following code :
String baseString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI2NjU0MjA5MGE2NGJhYWU0MzI4NGFiYTY0MmNkNWJmNmFlNzdkNjFhIiwiYXVkIjoiaHR0cHM6Ly9hcHAuaWZvcm1idWlsZGVyLmNvbS9leHphY3QvYXBpL29hdXRoL3Rva2VuIiwiZXhwIjoxNTEwNDMyMzcyLCJpYXQiOjE1MTA0MzE3NzJ9";
String clientSecret = "167edb4d9c3e603131619ae4a92c76307e3f9631";
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new
SecretKeySpec(clientSecret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
String jwtSignature =
Base64.encodeToString(sha256_HMAC.doFinal(baseString.getBytes("UTF-8")), Base64.NO_WRAP);
Log.d("JWT-SIGNATURE", jwtSignature);
I get the JWT-SIGNATURE value as 2nFaU/7jcc99jTWCO0VLriN/fiLwqi/ap7eeuVhhal4=
Instead the correct JWT-SIGNATURE value should be 2nFaU_7jcc99jTWCO0VLriN_fiLwqi_ap7eeuVhhal4
There are few characters that are not correct i.e. "/" and a "=" at the end.Can someone kindly help me out.

The encoding you need to use is a variant of Base64 encoding called base64url.
From wikipedia:
Using standard Base64 in URL requires encoding of '+', '/' and '='
characters into special percent-encoded hexadecimal sequences ('+'
becomes '%2B', '/' becomes '%2F' and '=' becomes '%3D'), which makes
the string unnecessarily longer.
For this reason, modified Base64 for URL variants exist, where the '+'
and '/' characters of standard Base64 are respectively replaced by '-'
and '_', so that using URL encoders/decoders is no longer necessary
and have no impact on the length of the encoded value, leaving the
same encoded form intact for use in relational databases, web forms,
and object identifiers in general. Some variants allow or require
omitting the padding '=' signs to avoid them being confused with field
separators, or require that any such padding be percent-encoded. Some
libraries will encode '=' to '.'.

Related

Why is java returning encoded values different

I am not quite sure why does java return %27+ for special characters in the name.
For example, the value I am trying to encode was "Mc' Donald". Its encoding to "Mc%27+Donald" when it should be "Mc%27%20Donald". reason why I replaced in the first place is db has ' instead of ' so replacing and encoding again.
lastName = URLEncoder.encode(lastName.replace("'", "'"), "UTF-8");
In HTML encoding, + is a valid replacement for SPACE (%20) as well.

Encode to UTF-8. Encode character eg. ö to ö

I want to encode a string in Android to UTF-8. For example this string:
Grüne Ähren beißen Flöhe
to
Grüne Ãhren beiÃen Flöhe
But no matter what I do I encode ü to ü or ü to %C3%BC (online often called 'raw URL encode').
Found solutions to convert to byte[] or URI.toASCIIString(). But non of them work for me.
UPDATE
I am participating in the eBay partner network and try to concat a searchword to my partner url.
The people of eBay must use a wrong character set, as UTF-8 URL encoded string don't work.
A searchword with UTF-8 URL encoding
(Grüne Ähren beißen Flöhe
to
Gr%C3%BCne%20%C3%84hren%20bei%C3%9Fen%20Fl%C3%B6he)
comes out to this result in the eBay searchbox:
If I encode my searchword with ISO_8859_1 it works (Grüne Ãhren beiÃen Flöhe):
Thank you very much community
What you essentially want is to convert a String to it's byte representation according to UTF-8 and interpret these bytes using a different Charset, such as ISO-8859-1.
This is usually the cause of many problems. You want to intentionally do what most developers do incorrectly (or they simply ignore the problems of charsets).
Since you just need this to work, use this piece of code:
byte[] bytes = "Grüne Ähren beißen Flöhe".getBytes("UTF-8");
String result = new String(bytes, "ISO-8859-1");
see it at work here.

Base64 encode gives different result on linux CentOS terminal and in Java

I am trying to generate some random password on Linux CentOS and store it in database as base64. Password is 'KQ3h3dEN' and when I convert it with 'echo KQ3h3dEN | base64' as a result I will get 'S1EzaDNkRU4K'.
I have function in java:
public static String encode64Base(String stringToEncode)
{
byte[] encodedBytes = Base64.getEncoder().encode(stringToEncode.getBytes());
String encodedString = new String(encodedBytes, "UTF-8");
return encodedString;
}
And result of encode64Base("KQ3h3dEN") is 'S1EzaDNkRU4='.
So, it is adding "K" instead of "=" in this example. How to ensure that I will always get same result when using base64 on linux and base64 encoding in java?
UPDATE: Updated question as I didn't noticed "K" at the end of linux encoded string. Also, here are few more examples:
'echo KQ3h3dENa | base64' => result='S1EzaDNkRU5hCg==', but it should be 'S1EzaDNkRU5h'
echo KQ3h3dENaa | base64' => result='S1EzaDNkRU5hYQo=', but it should be 'S1EzaDNkRU5hYQ=='
Found solution after few hours of experimenting. It seems like new line was added to the string I wanted to encode. Solution would be :
echo -n KQ3h3dEN | base64
Result will be the same as with java base64 encode.
Padding
The '==' sequence indicates that the last group contained only one byte, and '=' indicates that it contained two bytes.
In theory, the padding character is not needed for decoding, since the number of missing bytes can be calculated from the number of Base64 digits. In some implementations, the padding character is mandatory, while for others it is not used.
So it depends on tools and libraries you use. If base64 with padding is the same as without padding for them, there is no problem. As an insurance you can use on linux tool that generates base64 with padding.
Use withoutPadding() of Base64.Encoder class to get Base64.Encoder instance which encodes without adding any padding character at the end.
check the link :
https://docs.oracle.com/javase/8/docs/api/java/util/Base64.Encoder.html#withoutPadding

Uri encode everything, including unreserved characters

I need to match my server's signing base for oauth, which percent encodes everything before signing.
Using Uri.encode rather than Urlencoder.encode( base, UTF-8) encodes whitespace and +'s correctly, however I also need the unreserved characters ("_-!.~'()*") encoded.
Its not too hard to write my own utility for them, but it would be nice if the manual change wasn't necessary. Is there already a utility for this?
Turns out only a few characters needed extra encoding. For the masses:
public static String encode(String base){
String encoded = Uri.encode(base);
encoded = encoded.replace("(", "%28");
encoded = encoded.replace(")", "%29");
encoded = encoded.replace("!", "%21");
encoded = encoded.replace("\'", "%27");
encoded = encoded.replace("*", "%2A");
return encoded;
}

urlencode() the 'asterisk' (star?) character

I'm testing PHP urlencode() vs. Java java.net.URLEncoder.encode().
Java
String all = "";
for (int i = 32; i < 256; ++i) {
all += (char) i;
}
System.out.println("All characters: -||" + all + "||-");
try {
System.out.println("Encoded characters: -||" + URLEncoder.encode(all, "utf8") + "||-");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
PHP
$all = "";
for($i = 32; $i < 256; ++$i)
{
$all = $all.chr($i);
}
echo($all.PHP_EOL);
echo(urlencode(utf8_encode($all)).PHP_EOL);
All characters seem to be encoded in the same way with both functions, except for the 'asterisk' character that is not encoded by Java, and translated to %2A by PHP. Which behaviour is supposed to be the 'right' one, if any?
Note: I tried with rawurlencode(), too - no luck.
It is okay to have a * in a URL, (but it is also okay to have it in its encoded form).
RFC1738: Uniform Resource Locators (URL) states the following:
Reserved:
[...]
Usually a URL has the same interpretation when an octet is
represented by a character and when it encoded. However, this is not
true for reserved characters: encoding a character reserved for a
particular scheme may change the semantics of a URL.
Thus, only alphanumerics, the special characters "$-_.+!*'(),", and
reserved characters used for their reserved purposes may be used
unencoded within a URL.
On the other hand, characters that are not required to be encoded
(including alphanumerics) may be encoded within the scheme-specific
part of a URL, as long as they are not being used for a reserved
purpose.
Wikipedia suggests that * is a reserved character when it comes to URIs, and that it must be encoded if not used for the reserved purpose. According to RFC3986, pages 12-13:
URIs include components and subcomponents that are delimited by
characters in the "reserved" set. These characters are called
"reserved" because they may (or may not) be defined as delimiters by
the generic syntax, by each scheme-specific syntax, or by the
implementation-specific syntax of a URI's dereferencing algorithm.
If data for a URI component would conflict with a reserved
character's purpose as a delimiter, then the conflicting data must be
percent-encoded before the URI is formed.
reserved = gen-delims / sub-delims
gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "#"
sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
/ "*" / "+" / "," / ";" / "="
(The fact that the URL RFC still allows the * character to go unencoded is that is doesn't have a reserved purpose i URLs, and as such doesn't have to be encoded. So wether you have to encode it or not depends on what sort of URI you're creating.)
Javadoc of URLEncoder refers to the HTML specification:
This class contains static methods for converting a String to the application/x-www-form-urlencoded MIME format. For more information about HTML form encoding, consult the HTML specification.
HTML4 is quite unclear regarding this question and refers to RFC1738, which is quoted by aioobe:
Control names and values are escaped. Space characters are replaced by '+', and then reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric characters are replaced by '%HH', a percent sign and two hexadecimal digits representing the ASCII code of the character. Line breaks are represented as "CR LF" pairs (i.e., '%0D%0A').
However, HTML5 directly states that * should not be encoded:
If the character isn't in the range U+0020, U+002A, U+002D, U+002E, U+0030 to U+0039, U+0041 to U+005A, U+005F, U+0061 to U+007A
Replace the character with a string formed as follows:
...
Otherwise
Leave the character as is.

Categories

Resources