PHP utf8 variable encoding (HMAC Key -> C# Server) - c#

I'm trying to create a PHP client wrapper to talk to a .NET API. What I have is working but I am new to PHP development and what I have now looks like it may not work 100% of the time.
C# code I am trying to replicate:
private static void HMAC_Debug()
{
Console.WriteLine("Secret Key (Base64): 'qCJ6KNCd/ASFOt1cL5uq2TUYcRjplpYUy7QdUmvaCTs='");
var secret = Convert.FromBase64String("qCJ6KNCd/ASFOt1cL5uq2TUYcRjplpYUy7QdUmvaCTs=");
Console.WriteLine("Value To Hash (UTF8): 'MyHashingValue©'");
var value = Encoding.UTF8.GetBytes("MyHashingValue©");
using (HMACSHA256 hmac = new HMACSHA256(secret))
{
byte[] signatureBytes = hmac.ComputeHash(value);
string requestSignatureBase64String = Convert.ToBase64String(signatureBytes);
Console.WriteLine("Resulting Hash (Base64): '{0}'", requestSignatureBase64String);
}
Console.ReadLine();
}
My PHP Equiv:
$rawKey = base64_decode("qCJ6KNCd/ASFOt1cL5uq2TUYcRjplpYUy7QdUmvaCTs=");
// $hashValArr = unpack("C*", utf8_encode("MyHashingValue©"));
//
// $hashVal = call_user_func_array("pack", array_merge(array("C*"), $hashValArr));
$hashVal = "MyHashingValue©";
$raw = hash_hmac("sha256", $hashVal, $rawKey, TRUE);
$rawEnc = base64_encode($raw);
echo $rawEnc;
These two snippets produce the same Base64 output, but I am relying on the string variables in PHP being default encoded to UTF8 - is this a correct assumption or is there something more stable I can do?
You can see from the commented out PHP lines I attempted to manually encode it to UTF8 then extract out the ASCII bytes for the PHP HMAC function but it didn't produce the same output as the c# code.
Thanks
Marlon

Which version of PHP are you using?
In general you cannot rely on the encoding being UTF-8. In fact it might be possible that you just stored the file as UTF-8 (I guess without BOM) but older PHP versions (as far as I know before PHP 7) are not capable to work natively with unicode, they just read it as ASCII / Extended ASCII.
That said, if you do not manipulate the string it is possible that your example works because you are just processing the bytes that are stored in the variable. And if this byte sequence happend to be a UTF-8 encoded string at the time you inserted it into your source code it stays that way.
If you get the string from an abritrary source you should make sure which encoding is used and consider the multibyte string processing functions of PHP, which can work with different encodings [1].
[1] http://us2.php.net/manual/en/ref.mbstring.php

Related

Send UTF-8 string from Android to C#

I've been trying to accomplish a simple text transmission from my Android app to my C# server (asmx server), sending the simplest string - and for some reason it never works. My Android code is as following (assume that the variable 'message' holds the string as received from an EditText, which is UTF-16 as far as I'm concerned):
httpClient = new DefaultHttpClient();
HttpPost post = new HttpPost(POST_MESSAGE_ADDRESS);
byte[] messageBytes = message.getBytes("utf-8");
builder.addPart("message", new StringBody(messageBytes.toString()));
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
So I get something simple for my message, say a 10 bytes array. In my server, I have a function set to that specific address; its code is:
string message = HttpContext.Current.Request.Form["message"];
byte[] test = System.Text.Encoding.UTF8.GetBytes(message);
Now after that line the byte array ('test') has the exact same value as the result of the ToString() function I called in the app. Question is, how do I convert it to normal UTF-8 text to display?
Note: I have tried sending the string normally as a string content, but as far as I understood the default coding is ASCII so I got a lot of question marks.
Edit: Now I'm looking for some conversions solutions and trying them, but my question is also if there's a simpler way to do that (perhaps BinaryBody in the android, or different coding?)
Problem is in following lines:
byte[] messageBytes = message.getBytes("utf-8");
builder.addPart("message", new StringBody(messageBytes.toString()));
First you are transforming your UTF-16 string message into UTF-8 encoded messageBytes only to convert them back to UTF-16 string in next line. And there you are using StringBody constructor that will use ASCII encoding as default.
You should replace those lines with:
builder.addPart("message", new StringBody(message, Charset.forName("UTF-8")));

Converting Coldfusion encryption code to C# (again)

Once again I'm tasked with converting ColdFusion code used for a single sign-on to C# and am running short on time. This one is completely different than my question that was answered here, so I'm back to being in over my head.
The original ColdFusion code was executed in a <cfscript> tag. I've replaced the src and pwd variables with abbreviated placeholders just to obscure their actual values:
//create a key to be used
src="xxx";
pwd="abc";
// Base64 Decoding the key
base64Decoder = createObject("java", "sun.misc.BASE64Decoder");
desKeyData = base64Decoder.decodeBuffer(pwd);
// Initialize the constructor of DESedeKeySpec with private key
KeySpec=createObject("java", "javax.crypto.spec.DESedeKeySpec");
KeySpec=KeySpec.init(desKeyData);
// Generate the secret key using SecretKeyFactory
keyFac=createObject("java", "javax.crypto.SecretKeyFactory").getInstance("DESede");
secretKey =keyFac.generateSecret(KeySpec);
// Get CIPHER OBJ ready to use
decodecipher = createObject("java", "javax.crypto.Cipher").getInstance("DESede/ECB/PKCS5Padding");
decodecipher.init(2, secretKey);
encodecipher = createObject("java", "javax.crypto.Cipher").getInstance("DESede/ECB/PKCS5Padding");
encodecipher.init(1, secretKey);
stringBytes = toString(src).getBytes("UTF8");
raw = encodecipher.doFinal(stringBytes);
// Base64Encoding of generated cipher
cipherText=ToBase64(raw);
I also have a document from the other party that outlines the steps for creating the single sign-on as follows:
Creating the encrypted token
Create the plain text (this corresponds to the variable src above, and that part I've done successfully in C#)
Pad the plain text
Decode the key (the key corresponds to the variable pwd above, and must be base 64 decoded; I think I've successfully gotten up to this point as well.)
Perform the encryption (use the decoded key obtained above and the plain text to do the encryption)
Encode the cipher text (url encoded)
I have the BouncyCastle libraries installed and am trying to make use of those, but I'm stuck on the actual encryption step. So far the beginning of my C# conversion looks like this (once again the token and key have abbreviated placeholders to obscure the actual values):
//steps omitted here to create src string
string token = "xxx";
string key = "abc";
byte[] decodedKeyBytes = Convert.FromBase64String(key);
I know that's not a whole lot to go on, but I've tried so many things that haven't worked that I've lost track. Eventually when I get to the piece where I'm initializing the cipher, I assume I need something like this:
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DesEdeEngine());
Thanks very much for any suggestions/examples.
Update:
Thanks to the very helpful answer below, I was able to get this working using the following code:
string token = "xxx";
string key = "abc";
byte[] base64DecodedKeyBytes = Convert.FromBase64String(key);
byte[] inputBytesToken = System.Text.Encoding.UTF8.GetBytes(token);
// initialize for EBC mode and PKCS5/PKCS7 padding
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DesEdeEngine());
KeyParameter param = new KeyParameter(base64DecodedKeyBytes);
cipher.Init(true, param);
// encrypt and encode as base64
byte[] encryptedBytesToken = cipher.DoFinal(inputBytesToken);
string tokenBase64 = System.Convert.ToBase64String(encryptedBytesToken);
This one is completely different
Not so much ;-) You already answered your own question.
Do not let the java code throw you. Ignoring some unused variables, it is doing exactly the same thing as encrypt() on your other thread - except with "TripleDES" instead of "Blowfish". encrypt() hides a lot of the complexity, but internally it is does the same thing - using those same java classes FWIW. That means you can use the same C# code. As you already guessed, you just need to swap out the crypto engine:
....
// initialize for EBC mode and PKCS5/PKCS7 padding
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DesEdeEngine());
...
Update:
Just to elaborate a bit, when you use encrypt( someUTF8String, base64Key, algorithm, encoding), CF performs the same steps as your java code internally:
Decodes the key from base64, and creates a KeySpec object for the given algorithm, ie
// Base64 Decoding the key
// CF may use a different decoder, but the overall process is the same
base64Decoder = createObject("java", "sun.misc.BASE64Decoder");
....
secretKey =keyFac.generateSecret(KeySpec);
Next it extracts the UTF-8 bytes of the plain text, ie
stringBytes = toString(src).getBytes("UTF8");
CF then creates a cipher, which pads and encrypts the plain text, ie:
encodeCipher = createObject("java", "javax.crypto.Cipher").getInstance(algorithm);
encodeCipher.init(1, secretKey); // 1 - ENCRYPT_MODE
raw = encodeCipher.doFinal(stringBytes);
Finally, CF encodes the encrypted bytes as base64, ie:
cipherText=ToBase64(raw);
So as you can see, the java code and encrypt do exactly the same thing.

Encoding problem between C# TCP server and Java TCP Client

i'm facing some encoding issue which i'm not able to find the correct solution.
I have a C# TCP server, running as a window service which received and respond XML, the problem comes down when passing special characters in the output such as spanish characters with accents (like á,é,í and others).
Server response is being encoded as UTF-8, and java client is reading using UTF-8. But when i print its output the character is totally different.
This problem only happens in Java client(C# TCP client works as expected).
Following is an snippet of the server code that shows the encoding issue:
C# Server
byte[] destBytes = System.Text.Encoding.UTF8.GetBytes("á");
try
{
clientStream.Write(destBytes, 0, destBytes.Length);
clientStream.Flush();
}catch (Exception ex)
{
LogErrorMessage("Error en SendResponseToClient: Detalle::", ex);
}
Java Client:
socket.connect(new InetSocketAddress(param.getServerIp(), param.getPort()), 20000);
InputStream sockInp = socket.getInputStream();
InputStreamReader streamReader = new InputStreamReader(sockInp, Charset.forName("UTF-8"));
sockReader = new BufferedReader(streamReader);
String tmp = null;
while((tmp = sockReader.readLine()) != null){
System.out.println(tmp);
}
For this simple test, the output show is:
ß
I did some testing printing out the byte[] on each language and while on C# á output as:
195, 161
In java byte[] read print as:
-61,-95
Will this have to do with the Signed (java), UnSigned (C#) of byte type?.
Any feedback is greatly appreciated.
To me this seems like an endianess problem... you can check that by reversing the bytes in Java before printing the string...
which usually would be solved by including a BOM... see http://de.wikipedia.org/wiki/Byte_Order_Mark
Are you sure that's not a unicode character you are attemping to encode to bytes as UTF-8 data?
I found the below has a useful way of testing to see if the data in that string is ccorrect UTF-8 before you send it.
How to test an application for correct encoding (e.g. UTF-8)

Encode URL from C#, decrypt URL in PHP (extra characters being added somehow)

I have read so many topics on this very subject by now, I can't understand where the issue could possibly lie. I am encrypting part of a URL from a C# winform application. I then want to read in the URL using php and decrypt the url (all using base-64). I do have some code to shrae:
Code to encrypt URL (C#):
public static string Base64Encode(string str)
{
byte[] encbuff = Encoding.UTF8.GetBytes(str);
return System.Web.HttpServerUtility.UrlTokenEncode(encbuff);
}
Decrypt a section of the URL:
Base64Encode("CND0311J4S68CCU Ver. F.0BHPQOEM - f");
Returns:
Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY1
Code to decrypt URL (PHP):
echo base64_decode("Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY1");
Returns:
CND0311J4S68CCU Ver. F.0BHPQOEM - f5
So, where is the extra "5" at the end of the return coming from? I cannot figure this out for the life of me, quite frustrating as you could imagine.
I appreciate any help with this - as well as any suggestions!
Thank you,
Evan
"CND0311J4S68CCU Ver. F.0BHPQOEM - f"
encoded as base64 is not:
Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY1
Probably something else is adding the 1 at the end, because
echo base64_decode("Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY");
gives you what you're looking for. And that something adding it is in fact System.Web.HttpServerUtility.UrlTokenEncode. The issue is the following (from MSDN):
This (System.Web.HttpServerUtility.UrlTokenEncode) does not use a standard encoding. It encodes with - and _ characters which is standard. It also removes the = signs. But rather than simply removing them (they're not necessary to decode the string), it replaces them with a digit (0, 1, 2) indicating the number of = signs that were removed.
So go for it (Demo):
<?php
$urltoken = "Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY1";
echo urltoken_decode($urltoken);
function urltoken_decode($token)
{
return base64_decode(substr($token, 0, -1));
}
The function is pretty rough and could be improved to actually deal with it more specifically (Demo2):
function urltoken_decode($token)
{
$len = strlen($token);
if (!$len)
return $token;
$digit = $token[$len-1];
if (!in_array($digit, range(0,2)))
{
throw InvalidArgumentException(sprintf('Invalid end digit (%s).', $digit));
}
return base64_decode(substr($token, 0, -1));
}
Interesting - when I encode "CND0311J4S68CCU Ver. F.0BHPQOEM - f" at this site (using JavaScript) it encodes as "Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY". If I decode "Q05EMDMxMUo0UzY4Q0NVIFZlci4gRi4wQkhQUU9FTSAtIGY1" I get the extra 5 on the end. Apparently the problem is on the encoding end - maybe try outputting the value you're encoding just before it's passed to the base64 encoder to make sure it's exactly what you think it is?

MD5 or other Encryption in Silverlight C#

I'm looking to encrypt a password field for use in a login system, therefore I would like to match encryption to make sure the user has entered the correct details.
For some reason Security.Cryptography doesn't have the MD5 services in Silverlight so I'm left looking for a different method.
I had used this before:
public string Md5Encrypt(string originalPassword)
{
//Declarations
Byte[] originalBytes;
Byte[] encodedBytes;
MD5 md5;
//Instantiate MD5CryptoServiceProvider, get bytes for original password and compute hash (encoded password)
md5 = new MD5CryptoServiceProvider();
originalBytes = ASCIIEncoding.Default.GetBytes(originalPassword);
encodedBytes = md5.ComputeHash(originalBytes);
//Convert encoded bytes back to a 'readable' string
return BitConverter.ToString(encodedBytes);
}
But doesn't work now.
Can anyone give me a simple example for a working encryption method in Silverlight C#
Thanks
You can simply use Using HashLib in silverlight: http://hashlib.codeplex.com/ (look inside the HashLib.HashFactory.HashCryptoNotBuildIn namespace)
Also BouncyCastle.Crypt 1.7 release has a Silverlight 2.0 and above build where most crypto/hashing functions are available: http://www.bouncycastle.org/csharp/
And finally to your rescue, Mono source code is always here to rescue you: https://github.com/mono/mono/blob/master/mcs/class/corlib/System.Security.Cryptography/SHA512Managed.cs which you can copy any cypto code to your project if it targets .NET 2.0 or above.

Categories