I'm a newcomer and beginner, because my English is not good, I will make a long story short, please help me.
A public key is Base64 decode and SHA256.
Use C# and Python (Python result is correct.)
Why do I get different results?
If you like, I hope to get the answer by C# code(my English is very poor.)
Thank you very much.
Same public key : MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0k9N59vMq/1BP6lwgyxVPeWj6EFTMW+wJqyl+vePi1vKzJBCXWPZ5Ls7PmNaTaAQ5TVC5WVoxveuvaYLGm514Y7EDTrL8BrPWcK73Gw7E/IQyfOC+/Mw6mBnANyWiVAu9qIi2/PWasA2J/XR97kfUfuM716NKUNzBmmju8pfyPu+ee9Zfh0fUclF0g48AJMZaw8g6SxiWnQ8XhABkMHXyqVio5cdt5omupDcZ17HHBXsP3KHNX5Tu8ZDrCbFH566p1WGjM6W2Wr2YffzC8WPyFTS/6eiAde5iVjS2VHqRkmgQvrH794kGUC7ZUitP7p6gYCvhdffqxLQslvga9cPNQIDAQAB
Base64 decode ==> SHA256
Python:
pubkey_der = base64.b64decode(pubKey)
sha = hashlib.sha256(pubkey_der).hexdigest()
for i in sha:
print(i),
print('\n'),
result:890e947269d4e6d9c73883157f65aa6f12e20ad0a05ff518b5f9cb43cea28b89
C#:
private void button_go2_Click(object sender, EventArgs e)
{
string b64 = DecodeBase64(pubKey);
string result = GetSHA256HashFromString(b64);
}
private static string DecodeBase64(string pubKey)
{
string decode = string.Empty;
byte[] bytes = Convert.FromBase64String(pubKey);
decode = Encoding.UTF8.GetString(bytes);
return decode;
}
public string GetSHA256HashFromString(string strData)
{
byte[] bytValue = System.Text.Encoding.UTF8.GetBytes(strData);
try
{
SHA256 sha256 = new SHA256CryptoServiceProvider();
byte[] retVal = sha256.ComputeHash(bytValue);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("GetSHA256HashFromString() fail,error:" + ex.Message);
}
}
result:1eb61f3f380bccf54e61e05cdbe6e14c3871c6c827b33dc03b2cf47c1fc0df4c
Related
I have this function in my C# code:
public static string ComputeHash(string input)
{
string hash = string.Empty;
using (System.Security.Cryptography.MD5 md5Hash = System.Security.Cryptography.MD5.Create())
try
{
// Convert the input string to a byte array and compute the hash.
byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
StringBuilder sb = new StringBuilder();
//Loop through each byte of the hashed data and format each one as a hexadecimal string.
for (int i = 0; i < data.Length; i++)
sb.Append(data[i].ToString("x2"));
hash = sb.ToString();
}
catch (Exception ex)
{
Logger.Error(ex);
}
return hash;
}
This is how I store my value in SQL Server:
lower(CONVERT(NVARCHAR(32), HashBytes('MD5', #partIdentifier), 2))
The result of the two values is completely different. Does anyone have an idea why? Or how could I solve it?
I am making backend system for mine game (server & client). I use following code to generate first part of signature (this one is corrupted one):
#example data
string Url = "https://example.com/api/test/example.php";
Dictionary<string, string> RequestBody = new Dictionary<string, string>() { { "example_value", "test" } };
string CreateFirstHash()
{
string Combined = "";
foreach(KeyValuePair<string, string> BodyPart in RequestBody)
{
Combined += BodyPart.Key + "-" + BodyPart.Value + ".";
}
string HashedCombined = Encryption.SHA1(Combined);
string EncodedUrl = Encryption.Base64Encode(this.Url);
string PlainText = HashedCombined + ":" + EncodedUrl + ":" + 'ACBANE8AX98FT7JY6YVWKAMTMJHMYH3E2C582FCYJBTQLU4UZVSJ2E67CPB7BG75NDASGS3BAMR34UVUZN2SSPCV35A8VJPKPPCGGVEH5U9JM47GLUKRZSH3T65MBVZ2RY78C69ZGMC7JG998HRBY6U9TLQH6JDCVRE5YAR8D3TUJ3H2LBE2C598M7VNDSME5WM2YX2449Q8Z923QWGPFLCXXXCC4CETTKUJ28RYSHN372WP2KCXH6V7ZNZNJRAE';
return Encryption.SHA256(PlainText);
}
Here is Encryption class:
using System;
using System.Security.Cryptography;
using System.Text;
public class Encryption
{
private static readonly Encoding enc = Encoding.UTF8;
public static string MD5(string input)
{
byte[] inputBytes = enc.GetBytes(input);
using(System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
foreach(byte hashByte in hashBytes)
{
sb.Append(hashByte.ToString("x2"));
}
return sb.ToString();
}
}
public static string SHA1(string input)
{
byte[] inputBytes = enc.GetBytes(input);
using(SHA1Managed sha = new SHA1Managed())
{
byte[] hashBytes = sha.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
foreach(byte hashByte in hashBytes)
{
sb.Append(hashByte.ToString("x2"));
}
return sb.ToString();
}
}
public static string SHA256(string input)
{
byte[] inputBytes = enc.GetBytes(input);
using (SHA256Managed sha = new SHA256Managed())
{
byte[] hashBytes = sha.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
foreach (byte hashByte in hashBytes)
{
sb.Append(hashByte.ToString("x2"));
}
return sb.ToString();
}
}
public static string SHA512(string input)
{
byte[] inputBytes = enc.GetBytes(input);
using (SHA512Managed sha = new SHA512Managed())
{
byte[] hashBytes = sha.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
foreach (byte hashByte in hashBytes)
{
sb.Append(hashByte.ToString("x2"));
}
return sb.ToString();
}
}
public static string HMAC512(string input, string secret)
{
byte[] inputBytes = enc.GetBytes(input);
byte[] secretBytes = enc.GetBytes(secret);
using(HMACSHA512 hmac = new HMACSHA512(secretBytes))
{
byte[] hashBytes = hmac.ComputeHash(inputBytes);
return BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
}
}
public static string Base64Encode(string input)
{
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
return Convert.ToBase64String(inputBytes);
}
}
Server validates data by making same hash, with the same data and finally checks if generated signature is equal to input one. This is server implementation for CreateFirstHash() function:
#example data
public $requestBody = array('example_value' => 'test');
public $url = 'https://example.com/api/test/example.php';
public $scope = 'game'; #this is not important, you can disregard it
private static function generateFirstHash($requestBody, $url, $scope)
{
$combined = "";
foreach ($requestBody as $key => $value)
{
$combined .= $key . '-' . $value . ".";
}
$combined = sha1($combined);
$encodedUrl = base64_encode($url);
$plainString = $combined . ':' . $encodedUrl . ':' . 'ACBANE8AX98FT7JY6YVWKAMTMJHMYH3E2C582FCYJBTQLU4UZVSJ2E67CPB7BG75NDASGS3BAMR34UVUZN2SSPCV35A8VJPKPPCGGVEH5U9JM47GLUKRZSH3T65MBVZ2RY78C69ZGMC7JG998HRBY6U9TLQH6JDCVRE5YAR8D3TUJ3H2LBE2C598M7VNDSME5WM2YX2449Q8Z923QWGPFLCXXXCC4CETTKUJ28RYSHN372WP2KCXH6V7ZNZNJRAE';
return hash('sha256', $plainString);
}
All data from input were the same (checked manually). This is list what was the same in debug (step by step):
Combined string: same
SHA-1 hash of combined string: same
Encoded URL: same
Plain text: same
Final SHA-256 hash: invalid
Can anyone knows what is wrong and how can I make this valid?
Edit 1
Added example input data.
Thanks for adding some sample data but your C#-code is not running directly as some functions are missing.
I run your PHP-code and could extract the input to the SHA256-function:
plainString: d4a1466c15dc46dd6f7533b172313660eab1aba5:aHR0cHM6Ly9leGFtcGxlLmNvbS9hcGkvdGVzdC9leGFtcGxlLnBocA==:ACBANE8AX98FT7JY6YVWKAMTMJHMYH3E2C582FCYJBTQLU4UZVSJ2E67CPB7BG75NDASGS3BAMR34UVUZN2SSPCV35A8VJPKPPCGGVEH5U9JM47GLUKRZSH3T65MBVZ2RY78C69ZGMC7JG998HRBY6U9TLQH6JDCVRE5YAR8D3TUJ3H2LBE2C598M7VNDSME5WM2YX2449Q8Z923QWGPFLCXXXCC4CETTKUJ28RYSHN372WP2KCXH6V7ZNZNJRAE
With this input the PHP-SHA256 is:
hash: dced08719b7da56f69f70204122a498f5eda5090ad6b5a90691eb73731cc4c15
Test the plainString-value with an online-tool (https://emn178.github.io/online-tools/sha256.html) gives the same result:
dced08719b7da56f69f70204122a498f5eda5090ad6b5a90691eb73731cc4c15
Last but not least I tested your C#-implementation of SHA256 after fixing the missing
byte[] inputBytes = **enc.GetBytes**(input);
and got the result:
dced08719b7da56f69f70204122a498f5eda5090ad6b5a90691eb73731cc4c15
So in the end - there is no difference in SHA256-results between C# and PHP.
The text ZIRT which i encrypt by base64 this way
public static string encrypt(string ToEncrypt)
{
return Convert.ToBase64String(Encoding.ASCII.GetBytes(ToEncrypt));
}
after encrypt the text becomes V2tsU1ZB and when i try to decrypt using the below function
public static string decrypt(string cypherString)
{
//return Encoding.ASCII.GetString(Convert.FromBase64String(cypherString));
byte[] data = Convert.FromBase64String(cypherString);
string decodedString = Encoding.UTF8.GetString(data);
return decodedString;
}
then i am getting this text WklSVA but it suppose to be ZIRT
Please tell me what is wrong in my code ?
I am giving more code which fail to decrypt text
private void button1_Click(object sender, EventArgs e)
{
string strTxt = "ZIRT";
string ss = EnryptString(strTxt);
string ss1 = EnryptString(ss);
}
public string DecryptString(string encrString)
{
byte[] b;
string decrypted;
try
{
b = Convert.FromBase64String(encrString);
decrypted = System.Text.ASCIIEncoding.ASCII.GetString(b);
}
catch (FormatException fe)
{
decrypted = "";
}
return decrypted;
}
public string EnryptString(string strEncrypted)
{
byte[] b = System.Text.ASCIIEncoding.ASCII.GetBytes(strEncrypted);
string encrypted = Convert.ToBase64String(b);
return encrypted;
}
There is double encoding of the strings that explain the incorrect result. You are also using different text encodings when encrypting and decrypting. ASCII vs UTF8, this should be the same.
The following example provides the result I would expect:
byte[] b = System.Text.ASCIIEncoding.UTF8.GetBytes("test abc");
string base64Encoded = Convert.ToBase64String(b);
b = Convert.FromBase64String(base64Encoded);
Console.WriteLine( System.Text.ASCIIEncoding.UTF8.GetString(b));
// "test abc"
As mentioned in the comments, this is not encryption, but encoding.
I need to generate a HMAC-SHA256 hash in a PCL (developing for Xamarin Forms) which doesn't support the .NET built-in HMAC/cryptography classes, so I'm working with BouncyCastle to implement my cryptography classes.
I need to generate a HMAC-SHA256 hash, but I haven't been able to find any example on Google, nor does BouncyCastle seem to have any documentation for this. Can anyone help me out?
Thanks to the solution here I came up with this code:
public class HmacSha256
{
public byte[] Hash(string text, string key)
{
var hmac = new HMac(new Sha256Digest());
hmac.Init(new KeyParameter(Encoding.UTF8.GetBytes(key)));
byte[] result = new byte[hmac.GetMacSize()];
byte[] bytes = Encoding.UTF8.GetBytes(text);
hmac.BlockUpdate(bytes, 0, bytes.Length);
hmac.DoFinal(result, 0);
return result;
}
}
Corresponding unit test (uses FluentAssertions):
[TestClass]
public class HmacSha256Tests
{
private readonly HmacSha256 _hmac = new HmacSha256();
[TestMethod]
public void Hash_GeneratesValidHash_ForInput()
{
// Arrange
string input = "hello";
string key = "test";
string expected = "F151EA24BDA91A18E89B8BB5793EF324B2A02133CCE15A28A719ACBD2E58A986";
// Act
byte[] output = _hmac.Hash(input, key);
string outputHex = BitConverter.ToString(output).Replace("-", "").ToUpper();
// Assert
expected.Should().Be(outputHex);
}
}
Using this PCL offshoot of BouncyCastle https://www.nuget.org/packages/BouncyCastle-PCL/1.0.0.6 it's really easy, in fact identical to the windows api.
public string ComputeHMAC(string message)
{
var keyBytes = Encoding.UTF8.GetBytes(Constants.API_KEY);
var messageBytes = Encoding.UTF8.GetBytes(message);
var hmac = new HMACSHA256(keyBytes);
byte[] result = hmac.ComputeHash(messageBytes);
return Convert.ToBase64String(result);
}
And a unit test using the actual .Net version:
[Test, AutoMoqData]
public void Hash_Algorithm_Correct (
[NoAutoProperties] HashMacService sut,
string message)
{
string expected;
var key = Encoding.UTF8.GetBytes(Constants.API_KEY);
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
expected = Convert.ToBase64String(hash);
}
var result = sut.ComputeHMAC(message);
Assert.That(result, Is.EqualTo(expected));
}
I was using PCLCrypto but it kept crashing on Xamarin iOS, this was much cleaner and could be unit tested, wheras PCLCrypto required the platform apis so had to be deployed to a device.
private static void CreateToken(string message, string key)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[]keyByte = encoding.GetBytes(key);
HMACSHA256 hmacsha = new HMACSHA256(keyByte);
byte[]messageBytes = encoding.GetBytes(message);
byte[]hashmessage = hmacsha.ComputeHash(messageBytes);
Console.WriteLine(ByteToString(hashmessage));
}
public static string ByteToString(byte[]buff) {
string sbinary = "";
for (int i = 0; i < buff.Length; i++) {
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
Above code saved my time while working for HMAC-SHA256, I hope this may help someone and here is the reference in detail http://billatnapier.com/security01.aspx
I believe when the EnterpriseLibrary tries to decrypt a RijndaelManaged encrypted string it expects the Initialization Vector to be prepended to the encrypted text. Currently with the code below. I can decrypt the message with out an exception, but I am getting weird characters like:
�猀漀椀搀㴀眀最爀甀戀攀☀甀琀挀㴀㈀ ⴀ ⴀ㈀吀㌀㨀㔀㈀㨀㌀
What do I need to do to make this work? Any help is greatly appreciated. Here is some of the code I have...
I have a C# application that decrypts data using the EnterpriseLibrary 4.1 (encryption: RijndaelManaged).
string message = "This encrypted message comes from Java Client";
Cryptographer.DecryptSymmetric("RijndaelManaged", message);
The client encryptes the message, implemented in Java.
public String encrypt(String auth) {
try {
String cipherKey = "Key as a HEX string";
byte[] rawKey = hexToBytes(cipherKey);
SecretKeySpec keySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String cipherIV = "xYzF5AqA2cKLbvbfGzsMwg==";
byte[] btCipherIV = Base64.decodeBase64(cipherIV.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec (btCipherIV));
byte[] unencrypted = StringUtils.getBytesUtf16(auth);
byte[] encryptedData = cipher.doFinal(unencrypted);
String encryptedText = null;
byte[] entlib = new byte[btCipherIV2.length + encryptedData.length];
System.arraycopy(btCipherIV, 0, entlib, 0, btCipherIV.length);
System.arraycopy(encryptedData, 0, entlib, btCipherIV.length, encryptedData.length);
encryptedText = new String(encryptedData);
encryptedText = Base64.encodeBase64String(encryptedData);
return encryptedText;
} catch (Exception e) {
}
return "";
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(
str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
I found the answer. The problem in the above code:
StringUtils.getBytesUtf16(auth);
Instead the Enterprise Library is using Little Endian byte order. The function I was using doesn't. Instead I should have used:
StringUtils.getBytesUtf16Le(auth);
This solved my problem. Thanks for anyone who took a loot at this. I appreciate it!