I am working on a rest call to an asp.net web service and was provided sample code in C#. I am having trouble converting the following function
public static string ComputeHash(string hashedPassword, string message)
{
var key = Encoding.UTF8.GetBytes(hashedPassword.ToUpper());
string hashString;
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
hashString = Convert.ToBase64String(hash);
}
return hashString;
}
So far this is the draft php equivalent, is there anything specific I should be taking into account when converting between the two? Ignore any formatting am just trying to keep variable names the same for now for sanity. I can't seem to get these to come out to be the same.
function ComputeHash($hashedPassword, $message)
{
$key = utf8_encode(strtoupper($hashedPassword));
$hashString=hash_hmac('sha256',utf8_encode($message),$key,True);
$hashString = base64_encode($hashString);
return $hashString;
}
EDIT
Thanks to comments below I am able to get both functions doing the same.
Now the issue I have is around the input message
In C# this comes out like this
"GET\n03 August 2022 14:57:27.569500\n/api/member\nuserName=tom.woodforde#redox-software.co.uk";
If I feed the same into the function below the output is different.
This is how the function is built in C# to generate the message
private const String _newLineChar = "\n";
private static String CreateMessage(String method, String dateUTC, String apiModule, String data)
{
return method + _newLineChar + dateUTC + _newLineChar + apiModule + _newLineChar + data;
}
In PHP this is my equivalent
function CreateMessage($method, $dateUTC, $apiModule, $data){
$newLineChar = "\\n";
$message= $method.$newLineChar.$dateUTC.$newLineChar.$apiModule.$newLineChar.$data;
return $message;
}
I can feed in the exact same string but get a different result from the encryption and I am assuming it must be because of \n
Related
I have a signature created using metamask and the personal_sign RPC method.
Now I want to verify this signature in my C# backend.
In order to do so I have found the Nethereum library.
I have written the below code trying to verify the signature (for now I have used 'test' as the signed message).
public void VerifySignature(string signatureString, string originalMessage)
{
string msg = "\x19Ethereum Signed Message:\n" + originalMessage.Length + originalMessage;
byte[] msgHash = new Sha3Keccack().CalculateHash(Encoding.UTF8.GetBytes(msg));
EthECDSASignature signature = MessageSigner.ExtractEcdsaSignature(signatureString);
EthECKey key = EthECKey.RecoverFromSignature(signature, msgHash);
bool isValid = key.Verify(msgHash, signature);
}
Now the isValid comes back as true. However, if I use key.GetPublicAddress() this address is different than my own public address, so I assume I'm doing something wrong. Can anyone explain to me what, or correct if I'm wrong?
NOTE:
If instead of
EthECKey testKey = EthECKey.RecoverFromSignature(signature, msgHash);
I use
EthECKey testKey = EthECKey.RecoverFromSignature(signature, msgHash, new BigInteger(1));
(I'm using the main network to sign which is chain 1)
I get an error saying "recId should be positive", not sure if this is related but I thought it's worth mentioning.
UPDATE:
Managed to fix this by changing the msg string to use "\x19" + "Ethereum ..." instead of "\x19Ethereum ...", \x19E results in a different character, and results in a different message hash.
The Ethereum address and the public key are different. The Ethereum address is the last 20 bytes of the hash of the public key (see https://ethereum.org/en/developers/docs/accounts/ and https://github.com/Nethereum/Nethereum/blob/master/src/Nethereum.Signer/EthECKey.cs#L201).
I am trying to reproduce the result of a PHP pack('H40',$string) function.
So far i got good results but slightly different.
Here is what i tried
PHP Code
<?php
function test(){
$packed = pack('H40',"42d5abcd859afd2cc0f6b6f8cc2a9cd41f66a120");
return $packed;
}
echo test();
?>
C# Code:
private void test(){
string result = PackH40("42d5abcd859afd2cc0f6b6f8cc2a9cd41f66a120");
}
private string PackH40(string input)
{
string result = string.Empty;
input = input.Replace("-", " ");
byte[] hashBytes = new byte[input.Length / 2];
for (int i = 0; i < hashBytes.Length; i++)
{
hashBytes[i] = Convert.ToByte(input.Substring(i * 2, 2), 16);
}
return Encoding.UTF8.GetString(hashBytes);
}
The results look similar in browser but if you write them to a file they are not equal.
So far i tried every Encoding for the C# output and nothing.
What am i doing wrong?
Edit:
I tried the approach in
Trying to reproduce PHP's pack("H*") function in C# the issue is similar and in this case did not help me.
Resolved: Major problem was that i wanted to 'see' the data and compare it. I was terribly wrong! Converted all to byte[] and it worked like a charm !
I have written two method called-MakeHash and CompareHash on my .NET Core application. Now with MakeHash I am able to successfully converting SHA1 code but the problem is the way I am trying to compare hash code is always returns false. That means the CompareHash method is unable to compare plain code and SHA1 codes. Can you tell me how I can fix CompareHash so it will able to compare between plain text and SHA1 hash code? What am I doing wrong in CompareHash method? Thanks in advance
public static string MakeHash(string str)
{
// generate a 128-bit salt using a secure PRNG
byte[] salt = new byte[128 / 8];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(salt);
}
// derive a 256-bit subkey (use HMACSHA1 with 10,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
password: str,
salt: salt,
prf: KeyDerivationPrf.HMACSHA1,
iterationCount: 10000,
numBytesRequested: 256 / 8));
return hashed;
}
public static bool CompareHash(string plainString, string hashString)
{
if (MakeHash(plainString)==hashString)
{
return true;
}
else
{
return false;
}
}
Well, if you need some quick solution without storing salt on your database then you can give a try with the code below. This works for me. But this is highly recommended to use salt and match between them. Because it's about security you should be careful and put some more effort into it. My example is just to provide you an idea, not for production usage.
public static string MakeHash(string value)
{
return Convert.ToBase64String(
System.Security.Cryptography.SHA256.Create().ComputeHash(Encoding.UTF8.GetBytes(value))
);
}
public static bool CompareHash(string plainString, string hashString)
{
if (MakeHash(plainString) == hashString)
{
return true;
}
else
{
return false;
}
}
I am using MD5 hashing first time, I am trying to create a token to secure my web-services. I have found three different md5 hashing method for Android, IOS and C#. Before I call any webservice, I create a token and send it as a parameter. Then, when I get the token in service side, I create a token with the same algorithm in C# too and compare those two tokens. If the tokens are the same, I permit to the process. If not, I throw an exeption. My problem is, tokens are always different. I suppose that the difference of md5 creation methods causes this problem.
MD5 method in the C# code:
public static string MD5(string stringToEncrypted)
{
// step 1, calculate MD5 hash from input
var md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(stringToEncrypted);
byte[] hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
var sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}
In Swift Code:
extension String
{
var md5: String!
{
let str = self.cStringUsingEncoding(NSUTF8StringEncoding)
let strLen = CC_LONG(self.lengthOfBytesUsingEncoding(NSUTF8StringEncoding))
let digestLen = Int(CC_MD5_DIGEST_LENGTH)
let result = UnsafeMutablePointer<CUnsignedChar>.alloc(digestLen)
CC_MD5(str!, strLen, result)
var hash = NSMutableString()
for i in 0..<digestLen
{
hash.appendFormat("%02x", result[i])
}
result.destroy()
return String(format: hash)
}
}
In Android Code:
public static final String md5(final String stringToEncrypted)
{
final String MD5 = "MD5";
try
{
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest.getInstance(MD5);
digest.update(stringToEncrypted.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuilder hexString = new StringBuilder();
for (byte aMessageDigest : messageDigest)
{
String h = Integer.toHexString(0xFF & aMessageDigest);
while (h.length() < 2)
h = "0" + h;
hexString.append(h);
}
return hexString.toString();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
return "";
}
In Android using: h = "0" + h;
In IOS using: hash.appendFormat("%02x", result[i])
In C# using: sb.Append(hash[i].ToString("X2"));
Do these differences cause this problem ?
Thank you for your answers,
Best regards
Code example from SO Answer
func doSha256(#dataIn:NSData) -> NSData {
var shaOut: NSMutableData! = NSMutableData(length: Int(CC_SHA256_DIGEST_LENGTH));
CC_SHA256(dataIn.bytes, CC_LONG(dataIn.length), UnsafeMutablePointer<UInt8>(shaOut.mutableBytes));
return shaOut;
}
Obviously just change the constants for other hash methods.
If you want another format, say Base64 or hex put those conversions in a wrapper method that calls this method. It is better not to co-mingle methods, allow each to do a single thing. (Single Responsibility Principle) It also allows for easier testing and debugging.
I have two methods "EncodePassword" and "DecodePassword" as the following:
// Pass the password as a string, then return the encoded password
string EncodePassword(string password)
{
return Convert.ToBase64String(Encoding.UTF8.GetBytes(password));
}
// Pass the encoded password, then return that as a string
string DecodePassword(string password)
{
return Encoding.UTF8.GetString(Convert.FromBase64String(password));
}
The EncodePassword method works perfectly, but DecodePassword method don't!
So for example when I try to encode "testpassword", the result is "dGVzdHBhc3N3b3Jk", but when I try to decode "dGVzdHBhc3N3b3Jk", the result is some of question marks like this "��-��,�".
So what is the problem please?
the code works as expected. there must be a problem with loading the string in the first place - or you mess up encoding when processing the generated string.
[TestMethod]
public void EncodeAndDecodePwd()
{
const string pwd = "testpassword";
string encodedPassword = EncodePassword(pwd);
string decodedPassword = DecodePassword(encodedPassword);
string decodedPassword2 = DecodePassword("dGVzdHBhc3N3b3Jk");
Assert.AreEqual(pwd, decodedPassword);
Assert.AreEqual(pwd, decodedPassword2);
Assert.AreEqual(encodedPassword, "dGVzdHBhc3N3b3Jk");
}
BR