HMACSHA1 from C# To PHP - c#

I am trying to understand these line of code from C# (.Net) method to create a signature. However, I would like to do the same in PHP but not quite understand what it does in C#.
I wonder if any .net developer out there can help me to interpret the code below in 'English'?
Many thanks
HMAC hasher;
Byte[] utf8EncodedString = Encoding.UTF8.GetBytes(String.Format("{0}:{1}:{2}", MethodName, TimeStamp, AccessID));
hasher = HMACSHA1.Create();
hasher.Key = Encoding.UTF8.GetBytes(AccessKey);
Byte[] hashResult = hasher.ComputeHash(utf8EncodedString);
return Convert.ToBase64String(hashResult);
Here is my PHP code. Is this correct?
$signatureString = $methodName.':'.$timeStamp.':'.$accessID;
return hash_hmac('sha1', $signatureString, $accessKey, false);
Update: 30-05-2012
Just got it to work now
$signature = base64_encode(hash_hmac('sha1', $signatureString, $accessKey,true));

Answer on php.net for you http://www.php.net/manual/ru/function.hash-hmac.php#105099

Related

Apply HMAC SHA-512 algorithm using a secret key in python

I am trying to Apply HMAC SHA-512 algorithm using a secret key in python but I am not finding the correct way to sign.
I was able to do using nodejs and c# but not for python
in nodejs
return crypto.createHmac('sha512', new Buffer(secretString, 'base64')).update(new Buffer(stringToSign)).digest('base64');
in c#
byte[] secretkeyBytes = Encoding.UTF8.GetBytes(apiSecret);
byte[] inputBytes = Encoding.UTF8.GetBytes(stringToSign);
using (var hmac = new HMACSHA512(secretkeyBytes))
{
byte[] hashValue = hmac.ComputeHash(inputBytes);
signature = System.Convert.ToBase64String(hashValue);
}
but in python I am not figuring a way to do that.
I already tried:
b_secret_string=base64.b64encode(secret_string.encode('utf-8'))
hash = hmac.new(base64.b64encode(b_secret_string),'',sha512)
hash.update(string_to_sign.encode('utf-8'))
signature = base64.b64encode(hash.digest())
and
hashed = hmac.new(str(secret_string.encode('utf-8')),'',sha512)
hashed.update(string_to_sign.encode('utf-8'))
signature = base64.b64encode(hashed.digest())
but it is not working. If possible can someone give me a light? I really appreciate it.
UPDATE:
Also tried with the following:
string_to_sign = string_to_sign.encode('utf-8')
secret_string = secret_string.encode('utf-8')
hash = hmac.new(secret_string, string_to_sign, hashlib.sha512)
signature = base64.b64encode(hash.digest())
tried using hexdigest() too:
signature = base64.b64encode(hash.hexdigest())
if someone wants to test it. Should return the same as this code in nodejs.
var crypto = require('crypto');
a = new Buffer('PRIVATE_KEY', 'base64');
hash = crypto.createHmac('sha512', a)
stringToSign = 'Stack OverFlow Funtime';
hash.update(new Buffer(stringToSign));
console.log(hash.digest('base64'));
$ node example.js
ugmH0VdttdAxGdpzNJnaNn1KlVS4wBzoK//dsPuvK65Zsl8FgT+3aLGnsEubThlv5/3chfyMmsUH//LdS1MXqg==
I found a way to do the same in python. Answering here if someone pass for the same issue in future.
hmac_key = base64.b64decode(secret_string)
signature = hmac.new(hmac_key, string_to_sign, hashlib.sha512)
signature_b64 = signature.digest().encode('base64')
signature_lines = signature_b64.splitlines()
signature_b64 = ''.join(signature_lines)
How about:
import hashlib
print hashlib.sha512('some string').hexdigest()

Verifying Amazon SNS signatures in C#

I have an ASP.NET endpoint where I receive Amazon SNS messages. I want to verify the signatures I receive along with those messages and have followed the guide at http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.example.java.html trying to match the Java code in C#. Here's what I have so far (I'm only interested in validating notifications, not subscription confirmations):
private X509Certificate2 cert;
// cert is from constructor...
private bool IsValidMessageSignature(AmazonMessage msg)
{
// Verify the signature
var rsa = (RSACryptoServiceProvider)cert.PublicKey.Key;
var msgBytes = GetMessageBytes(msg);
var signedBytes = Convert.FromBase64String(msg.Signature);
return rsa.VerifyData(msgBytes, CryptoConfig.MapNameToOID("SHA1"), signedBytes);
}
private byte[] GetMessageBytes(AmazonMessage msg)
{
// Construct message string
var sb = new StringBuilder();
sb.AppendLine("Message");
sb.AppendLine(msg.Message);
sb.AppendLine("MessageId");
sb.AppendLine(msg.MessageId);
if (msg.Subject != null)
{
sb.AppendLine("Subject");
sb.AppendLine(msg.Subject);
}
sb.AppendLine("Timestamp");
sb.AppendLine(msg.Timestamp);
sb.AppendLine("TopicArn");
sb.AppendLine(msg.TopicArn);
sb.AppendLine("Type");
sb.AppendLine(msg.Type);
return Encoding.UTF8.GetBytes(sb.ToString());
}
The rsa.VerifyData() step returns false. I have built the example in Java as well, and here it works fine with the same message I'm trying to validate, and the same certificate that I'm using for C#.
Here's where the two programs differ as far as I can see. The C# GetMessageBytes byte-array returns 637 bytes, while the Java equivalent getMessageBytesToSign returns 627 bytes. Unfortunately I cannot post the message contents here for security reasons. My Java setup uses the windows-1252 charset by default, but even if I change the C# encoding to that the byte-array is still 637 in size. I'm not that experienced with encodings and the differences between C# and Java so I don't know if it's of any importance though.
Any ideas as to how my C# should be changed?
Amazon.SimpleNotificationService.Util.Message.ParseMessage(SNS_MESSAGE).IsMessageSignatureValid()
The Java code ends lines with \n. The C# version (StringBuilder.AppendLine()) uses \r\n.
It worked for me this way:
var sb = new StringBuilder();
sb.Append("Message\n");
sb.Append(notificationWrapper.Message).Append("\n");
sb.Append("MessageId\n");
sb.Append(notificationWrapper.MessageId).Append("\n");
if (notificationWrapper.Subject != null)
{
sb.Append("Subject\n");
sb.Append(notificationWrapper.Subject).Append("\n");
}
sb.Append("Timestamp\n");
sb.Append(notificationWrapper.Timestamp).Append("\n");
sb.Append("TopicArn\n");
sb.Append(notificationWrapper.TopicArn).Append("\n");
sb.Append("Type\n");
sb.Append(notificationWrapper.Type).Append("\n");
return Encoding.UTF8.GetBytes(sb.ToString());

Salt and MD5 in c#

So I have a website for my game
This is an exert of the php that I am using.
$Login = strtolower(trim($Login));
$Pass = strtolower(trim($Pass));
$Repass = strtolower(trim($Repass));
$Salt = $Login.$Pass;
$Salt = md5($Salt);
$Salt = "0x".$Salt;
But now I am faced with an issue that I cant seem to work out. I need to be able to do this encryption through C# WinForms for a client side Launcher(Register, Play Game etc etc)
For the life of me I cant figure out how to make the same binary as it makes in php.
I have tried loads but just cant crack it.
Many thanks if you can help
Though your example code confuses the actual question, I think I have a solution for your actual problem.
I've had the same problem with that md5() medthod, converting some PHP code into C# a while back. Here's what I came up with:
private static string CalculateChecksum(string inputString)
{
var md5 = new MD5CryptoServiceProvider();
var hashbytes = md5.ComputeHash(Encoding.UTF8.GetBytes(inputString));
var hashstring = "";
foreach(var hashbyte in hashbytes)
hashstring += hashbyte.ToString("x2");
return hashstring;
}
There may be a neater solution, but that there is working for me and at the time I was in a hurry.
Anyway, it gives you strings like A48EDF06 ... as you would expect from php's md5()

Md5 Password in AS3

I have a problem recreating a password that's hashed in C#. In an online project when a user do the registration process his password is save after passing for this function:
private static string ToMD5Hash(string inputString)
{
using (MD5 md5 = MD5.Create())
{
byte[] data = Encoding.Unicode.GetBytes(inputString);
byte[] hash = md5.ComputeHash(data);
return Convert.ToBase64String(hash);
}
}
I'm working on an offline version that at some point will do a sync with the online version and I can't reproduce the same results on AS3 (Adobe Air). For example the password "1234" after passing to the C# code will be "DwN1hMmef9T0+MWVUPj1Bw==".
Can someone help me out?
My AS3 code is like this:
private function encode():void
{
var ba:ByteArray = new ByteArray();
ba.writeMultiByte("1234","unicode");
var str:String = MD5.hash(ba.toString());
var ba2:ByteArray = new ByteArray();
ba2.writeMultiByte(str.toString(),"unicode");
var encoder:Base64Encoder = new Base64Encoder();
encoder.encodeUTFBytes(ba2.toString());
trace(encoder.toString());
}
When I do the ba.writeMultiByte("1234","unicode"); I get exactly the same ByteArray as in the C# but when I do the MD5.hash(ba.toString()); the new ByteArray is different.
So it looks like it may be a bug in as3corelib's implementation of writing the bits to the digest ByteArray.
It seemingly writes them in big endian format, rather than little endian. Or more specifically, it writes the bits as a collection of 4 integers rather than a collection of bytes, and in the process it mangles the byte order of the bits (which is why you are seeing different Base64 results -- the bytes are in a different order).
You can address this bug by adding on line 184 of MD5.as, in as3corelib, insert the following one line of code:
digest.endian = Endian.LITTLE_ENDIAN;
Also make sure you add an import at the top of the file for import flash.utils.Endian. I've created a public gist of the changes available here
Then it should generate the same byte order as c#, and then it should Base64 encode the same way. I verified it using the following as3 function:
private function encode():void
{
var ba:ByteArray = new ByteArray();
ba.endian = Endian.BIG_ENDIAN
ba.writeMultiByte("1234","unicode");
var str:String = MD5.hashBytes(ba);
var encoder:Base64Encoder = new Base64Encoder();
encoder.encodeBytes(MD5.digest);
trace(encoder.toString()); // DwN1hMmef9T0+MWVUPj1Bw==
}
Look at this.
Be aware that the original download mentioned in that site has a few bugs, so that you have to use the corrected vesion that you can find in the same post.
If you're using AS3CoreLib, do it this way:
Different MD5 with as3corelib.

Problem verifying in C# what was signed in Java (RSA)

I was hoping I might get some help here so that I might finally solve this frustrating problem.
On the java side of things they sign with the following code:
public static void main(String[] args) throws Exception {
if (args.length < 2)
printInfoAndExit();
String cmd = args[0];
Security.addProvider(new BouncyCastleProvider());
Signature signature = Signature.getInstance("SHA1withRSA", "BC");
if ("sign".equalsIgnoreCase(cmd)) {
String pemFileName = args[1];
String dataFileName = args[2];
byte[] data = readFile(dataFileName);
FileReader fr = new FileReader(new File(pemFileName));
PEMReader pemReader = new PEMReader(fr);
KeyPair keyPair = (KeyPair) pemReader.readObject();
fr.close();
signature.initSign(keyPair.getPrivate());
signature.update(data);
byte[] signatureBytes = signature.sign();
writeFile(signatureBytes, dataFileName + ".signed");
String encoded = Base64.encode(signatureBytes);
writeFile(encoded.getBytes(), dataFileName + ".signed.base64");
} else {
printInfoAndExit();
}
}
When I receive the data I have their public key and try to verify with the following C# code:
public static bool Verify(String msg, String signature, String publicKey)
{
RsaKeyParameters remotepubkey = GetRsaPublicKey(publicKey);
ISigner signer = SignerUtilities.GetSigner("SHA1withRSA");
signer.Init(false, remotepubkey);
byte[] sigBytes = Convert.FromBase64String(signature);
byte[] msgBytes = Encoding.Default.GetBytes(msg);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
return signer.VerifySignature(sigBytes);
}
This is not working!! I can however verify the data with openssl:
openssl dgst -sha1 -verify public_key.pem -signature data.txt.signed data.txt
The question is, what am I missing to make this work?
NOTE: I don't have a problem with the keys, that is working correctly but somehow there is a difference between how java and .net works with RSA?
**Edit 1 : **In this particular scenario all I had to do was change the GetSigner to
ISigner signer = SignerUtilities.GetSigner("RSA");
Could someone tell me the difference between SHA1withRSA and RSA?
The problem was actually solved on the Java side. They had some issues with their side of things.
You could have an encoding problem with your message data. You've converted the original file data into a unicode string, and are trying to convert it back to raw bytes. Depending on the encoding of the file, and if it's even text at all, your msgBytes could be different from the actual file contents.
Read the raw bytes from the file instead of a string. You don't show the code for actually reading the file data, but I assume you're reading it as text.

Categories