C# HttpUtility.UrlEncode vs Java URLEncoder.encode inconsistencies - java

I have a key(12345#678!9) which I need to encode on 2 applications, one C# one Java.
C#
var key = "12345#678!9";
var enc = HttpUtility.UrlEncode(key, Encoding.UTF8);
Console.WriteLine(enc);
The output here is 12345%23678!9
Java
var key = "12345#678!9";
var enc = java.net.URLEncoder.encode(key, StandardCharsets.UTF_8.toString);
System.out.println(enc)
The output here is 12345%23678%219
As you can see the two encoded values are different, the Java code is encoding the '!' as %21 where the C# code is not.
I cant change the key nor can I change the C# code.
So a solution will need to be on the Java side.
Is there a Java the equivalent of the C# method HttpUtility.UrlEncode?
Are they other options aside from java.net.URLEncoder.encode that I could use?
Thanks in advance

Related

Transforming a Java UUID object to a .NET GUID string

In a Java method that receives a java.util.UUID Object, I would like to display this object as a string in the .NET/C# format (CSUUID).
Currently I am only able to display it in the Java format (JUUID) :
static String GetStringFromUuid (java.util.UUID myUuid){
return myUuid.toString();
}
Current output: "46c7220b-1f25-0118-f013-03bd2c22d6b8"
Desired output: "1f250118-220b-46c7-b8d6-222cbd0313f0"
Context:
The UUID is stored in MongoDB and is retrieved with the Java ETL program Talend (tMongoDBInput component).
In the Java program, the method already receives the UUID as a java.util.UUID Object (I do not have directly access to the BinData in the program).
I need to display the UUID in the C# format since other programs already display the UUIDs with the C# format.
In case it might be useful, the example data is stored in MongoDB like this:
BinData(3,"GAElHwsix0a41iIsvQMT8A==")
I need a solution in Java.
Guid is represented by 16 bytes. For various reasons, both Java and .NET do not just print those bytes in order when you call toString. For example, if we look at base-64 encoded guid from your question:
GAElHwsix0a41iIsvQMT8A==
In hex form it will look like this:
18-01-25-1f-0b-22-c7-46-b8-d6-22-2c-bd-03-13-f0
Java toString produces this (if we format as above):
46-c7-22-0b-1f-25-01-18-f0-13-03-bd-2c-22-d6-b8
.NET ToString produces this:
1f-25-01-18-22-0b-46-c7-b8-d6-22-2c-bd-03-13-f0
If you look at this for some time - you will notice that both java and .NET strings represent the same 16 bytes, but positions of those bytes in output string are different. So to convert from java representation to .NET you just need to reorder them. Sample code (I don't know java, so probably it could be done in a better way, but still should achieve the desired result):
static String GetStringFromUuid (java.util.UUID myUuid){
byte[] bytes = new byte[16];
// convert uuid to byte array
ByteBuffer bb = ByteBuffer.wrap(bytes);
bb.putLong(myUuid.getMostSignificantBits());
bb.putLong(myUuid.getLeastSignificantBits());
// reorder
return String.format("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
bytes[4],bytes[5],bytes[6],bytes[7],
bytes[2],bytes[3],bytes[0],bytes[1],
bytes[15],bytes[14],bytes[13],bytes[12],
bytes[11],bytes[10],bytes[9],bytes[8]);
}
We can just keep the GUID as string, if the c# function is receiving the string and it needs to be displayed or sent to some service as string
Just in case if you want to parse it.
You can use the link for GUID parsing logic example
For creating new GUID in C#, use
var guid = System.Guid.NewGuid();
var guidString = guid.ToString();
For creating new UUID in Java, use
UUID uuid = java.util.UUID.randomUUID();
String uuidString = uuid.toString();

How to get UTF-8 conversion for a string

Frédéric in java converted to Frédéric.
However i need to pass the proper string to my client.
How to achieve this in Java ?
Did tried
String a = "Frédéric";
String b = new String(a.getBytes(), "UTF-8");
However string b also contain same value as a.
I am expecting string should able to store value as : Frédéric
How to pass this value properly to client.
If I understand the question correctly, you're looking for a function that will repair strings that have been damaged by others' encoding mistakes?
Here's one that seems to work on the example you gave:
static String fix(String badInput) {
byte[] bytes = badInput.getBytes(Charset.forName("cp1252"));
return new String(bytes, Charset.forName("UTF-8"));
}
fix("Frédéric") == "Frédéric"
The answer is quite complicated. See http://www.joelonsoftware.com/articles/Unicode.html for basic understanding.
My first suggestion would be to save your Java file with utf-8. Default for Eclipse on Windows would be cp1252 which might be your problem. Hope I could help.
Find your language code here and use that.
String a = new String(yourString.getBytes(), YOUR_ENCODING);
You can also try:
String a = URLEncoder.encode(yourString, HTTP.YOUR_ENCODING);
If System.out.println("Frédéric") shows the garbled output on the console it is most likely that the encodings used in your sourcecode (seems to be UTF-8) is not the same as the one used by the compiler - which by default is the platform-encoding, so probably some flavor of ISO-8859. Try using javac -encoding UTF-8 to compile your source (or set the appropriate property of your build environment) and you should be OK.
If you are sending this to some other piece of client software it's most likely an encoding issue on the client-side.

Capicom and SHA1 - Help translating a java code to Delphi

I have a java application that signs a string using a certificate. It works encrypting the string it with SHA1. I am trying to translate the code to Delphi 2010, but I have no idea how to get it working the same way the java app does (using sha1). So far, I have found this:
Delphi 7 access Windows X509 Certificate Store
It does work, but it does not use sha1 and I get different results when I run the java app.
Java code
char[] pass = (char[]) null;
PrivateKey key = (PrivateKey) getKeyStore().getKey(alias, pass);
Certificate[] chain = getKeyStore().getCertificateChain(alias);
CertStore certsAndCRLs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(Arrays.asList(chain)), "BC");
X509Certificate cert = (X509Certificate) chain[0];
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSigner(key, cert, CMSSignedDataGenerator.DIGEST_SHA1);
gen.addCertificatesAndCRLs(certsAndCRLs);
CMSProcessable data = new CMSProcessableByteArray(conteudoParaAssinar);
CMSSignedData signed = gen.generate(data, true, "SunMSCAPI");
byte[] envHex = signed.getEncoded();
CertInfo certInfo = new CertInfo();
certInfo.Hash = new BigInteger(envHex).toString(16);
return certInfo;
Delphi Code
var
lSigner: TSigner;
lSignedData: TSignedData;
fs: TFileStream;
qt: integer;
ch: PChar;
msg : WideString;
content : string;
cert: TCertificate;
begin
cert := Self.GetCert;
content := 'test';
lSigner := TSigner.Create(self);
lSigner.Certificate := cert.DefaultInterface;
lSignedData := TSignedData.Create(self);
lSignedData.content := content;
msg := lSignedData.Sign(lSigner.DefaultInterface, false, CAPICOM_ENCODE_BASE64);
lSignedData.Free;
lSigner.Free;
EDIT
Based on the java code, should I get the cert info in binary format, apply sha1 on it and them convert it to hex? Is this the right order and the same thing the java code does? I can see some SHA1 constants in the capicom tlb as well as a hash class, maybe I should use those classes, but I dont know how.
We use DCPCrypt in some delphi apps that interface with our Java Tomcat App and are able to get SHA-256 compatible hashes. I suspect SHA1 is also easy.
Here's an example
function Sha256FileStreamHash(fs : TFileStream): String;
var
Hash: TDCP_sha256;
Digest: array[0..31] of byte; // RipeMD-160 produces a 160bit digest (20bytes)
i: integer;
s: string;
begin
if fs <> nil then
begin
fs.Seek(0, soFromBeginning);
Hash:= TDCP_sha256.Create(nil); // create the hash
try
Hash.Init; // initialize it
Hash.UpdateStream(fs,fs.Size); // hash the stream contents
Hash.Final(Digest); // produce the digest
s:= '';
for i:= 0 to 31 do
s:= s + IntToHex(Digest[i],2);
Result:= s; // display the digest
finally
Hash.Free;
end;
end;
end;
First, what makes you think you're not using SHA-1 ? I'm asking because CAPICOM's sign function only works with SHA-1 signature.
Second, how do you know that you're getting a different result ? Have you tried to validate the answer ? If yes, using what ?
Third, there is something that you MUST know about CAPICOM: the "content" property is a widestring. This has various implication, including the fact that all content will be padded to 16-bits. If your input data is of different size, you'll get a different result.
Based on the java code, should I get the cert info in binary format, apply sha1 on it and them convert it to hex?
No. You get an interface to an instance of a ICertificate object (or, more likely, ICertificate2) and you just use that directly. If you have the B64 encoded version of the certificate, you can create a new ICertificate instance and then call the ICertificate.Import method. The hash of the certificate itself is only used by the signing authority to sign that specific cert.
The hash algorythm is actually used during the data signature process: the library reads the data, creates a hash of that data (using SHA-1 in case of CAPICOM) and then digitally sign that hash value. This reduction is necessary because signing the whole data block would be far too slow and because, that way, you only have to carry the hash if you're using a hardware crypto system.
Is this the right order and the same thing the java code does?
Yes and no. The Java code does all the necessary steps in explicit details, something you don't have (and actually cannot) do with CAPICOM. It should result in compatible result, though.
It also has an additional step not related to the signature itself: I'm not sure what it does because it seems to create a dummy certificate information data and store the SHA-1 hash value of the signed CMS message and return the resulting instance. I suppose that it's a way the Java dev has found to pass the hash value back to the caller.
I can see some SHA1 constants in the capicom tlb as well as a hash class, maybe I should use those classes, but I dont know how.
The HashedData class is used to (surprise) hash data. It has the same limitation as Signeddata i.e. it only works on widestrings so compatibility with other frameworks is dodgy at best.
Final note: Windows offers access to much more comprehensive cryptographic functions through the CAPI group of functions. CAPICOM is only an interface to that library that is used (mostly) in script language (JavaScript on web pages, VB, etc). You should do yourself a favor and try using it instead of CAPICOM because there is a good chance you'll encounter something that you simply cannot do properly using CAPICOM. At that stage, you will have to rewrite part for all of your application using CAPI (or another library). So save time now and skip CAPICOM if you don't have a requirement to use it.

Java's new Base64(-1) in PHP?

I m trying to match java base64 code in php. But getting inconsistent result.
Java base64 encode
encMessage = URLEncoder.encode(new Base64(-1).encodeToString(encrypted),"UTF8");
Java decode
message = URLDecoder.decode(message,"utf8");
Above code java encode code return the string which i have to decode and decrypt in php
PHP base64 decode
$message = utf8_decode(urldecode($encrypted));
$message = base64_decode($message);
PHP encode
$encMessage = base64_encode($encrypted);
$encMessage = utf8_encode(urlencode($encMessage));
Results:
java:
KO%2F%2B%2Bzbp5z8oCdvZn62jb72kseT%2Bem8hYUZY0IuB9zo%3D
php:
KO%2F%2B%2Bzbp5z8oCdvZn62jb3CVVVXsV%2Bws2kDOmKK%2BPEc%3D
src : https://gist.github.com/944269
I had this problem between CSharp and Java, and found that URL encoding things was the culprit. What I did in my work around was basically re-encrypt the data with a newly generated public key until I got one that didn't need URL encoding. Not a great solution, but it works, it averages 2 tries to get it right, but I've seen it taking up to 15 tries to do it, either way we're still talking milliseconds, and it works reliably.
YMMV

NSData to Java String

I've been writing a Web Application recently that interacts with iPhones. The iPhone iphone will actually send information to the server in the form of a plist. So it's not uncommon to see something like...
<key>RandomData</key>
<data>UW31vrxbUTl07PaDRDEln3EWTLojFFmsm7YuRAscirI=</data>
Now I know this data is hashed/encrypted in some fashion. When I open up the plist with an editor (Property List Editor), it shows me a more "human readable" format. For example, the data above would be converted into something like...
<346df5da 3c5b5259 74ecf683 4431249f 711630ba 232c54ac 9bf2ee44 0r1c8ab2>
Any idea what the method of converting it is? Mainly I'm looking to get this into a Java String.
Thanks!
According to our friends at wikipedia, the <data> tag contains Base64 encoded data. So, use your favorite Java "Base64" class to decode (see also this question).
ps. technically, this is neither "hashed" nor "encrypted", simply "encoded". "Hashed" implies a one-way transformation where multiple input values can yield the same output value. "Encrypted" implies the need for a (usually secret) "key" to reverse the encryption. Base64 encoding is simply a way of representing arbitrary binary data using only printable characters.
After base64 decoding it you need to hex encode it. This is what PL Editor is showing you.
So...
<key>SomeData</key>
<data>UW31ejxbelle7PaeRAEen3EWMLojbFmsm7LuRAscirI=</data?
Can be represented with...
byte[] bytes = Base64.decode("UW31ejxbelle7PaeRAEen3EWMLojbFmsm7LuRAscirI=");
BigInteger bigInt = new BigInteger(bytes);
String hexString = bigInt.toString(16);
System.out.println(hexString);
To get...
<516df5aa 3c5b5259 74ecf683 4401259f 711630ba 236c59ac 9bb2ee44 0b1c8ab2>

Categories