Looking for a way to do the following in C# from a string.
public static String sha512Hex(byte[] data)
Calculates the SHA-512 digest and returns the value as a hex string.
Parameters:
data - Data to digest
Returns:
SHA-512 digest as a hex string
private static string GetSHA512(string text)
{
UnicodeEncoding UE = new UnicodeEncoding();
byte[] hashValue;
byte[] message = UE.GetBytes(text);
SHA512Managed hashString = new SHA512Managed();
string encodedData = Convert.ToBase64String(message);
string hex = "";
hashValue = hashString.ComputeHash(UE.GetBytes(encodedData));
foreach (byte x in hashValue)
{
hex += String.Format("{0:x2}", x);
}
return hex;
}
Would System.Security.Cryptography.SHA512 be what you need?
var alg = SHA512.Create();
alg.ComputeHash(Encoding.UTF8.GetBytes("test"));
BitConverter.ToString(alg.Hash).Dump();
Executed in LINQPad produces:
EE-26-B0-DD-4A-F7-E7-49-AA-1A-8E-E3-C1-0A-E9-92-3F-61-89-80-77-2E-47-3F-88-19-A5-D4-94-0E-0D-B2-7A-C1-85-F8-A0-E1-D5-F8-4F-88-BC-88-7F-D6-7B-14-37-32-C3-04-CC-5F-A9-AD-8E-6F-57-F5-00-28-A8-FF
To create the method from your question:
public static string sha512Hex(byte[] data)
{
using (var alg = SHA512.Create())
{
alg.ComputeHash(data);
return BitConverter.ToString(alg.Hash);
}
}
Got this to work. Taken from here and modified a bit.
public static string CreateSHAHash(string Phrase)
{
SHA512Managed HashTool = new SHA512Managed();
Byte[] PhraseAsByte = System.Text.Encoding.UTF8.GetBytes(string.Concat(Phrase));
Byte[] EncryptedBytes = HashTool.ComputeHash(PhraseAsByte);
HashTool.Clear();
return Convert.ToBase64String(EncryptedBytes);
}
Better memory management:
public static string SHA512Hash(string value)
{
byte[] encryptedBytes;
using (var hashTool = new SHA512Managed())
{
encryptedBytes = hashTool.ComputeHash(System.Text.Encoding.UTF8.GetBytes(string.Concat(value)));
hashTool.Clear();
}
return Convert.ToBase64String(encryptedBytes);
}
Related
I want to hash given byte[] array with using SHA1 Algorithm with the use of SHA1Managed.
The byte[] hash will come from unit test.
Expected hash is 0d71ee4472658cd5874c5578410a9d8611fc9aef (case sensitive).
How can I achieve this?
public string Hash(byte [] temp)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
}
}
For those who want a "standard" text formatting of the hash, you can use something like the following:
static string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
// can be "x2" if you want lowercase
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
}
This will produce a hash like 0C2E99D0949684278C30B9369B82638E1CEAD415.
Or for a code golfed version:
static string Hash(string input)
{
var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input));
return string.Concat(hash.Select(b => b.ToString("x2")));
}
For .Net 5 and above, the built-in Convert.ToHexString gives a nice solution with no compromises:
static string Hash(string input)
{
using var sha1 = SHA1.Create();
return Convert.ToHexString(sha1.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
public string Hash(byte [] temp)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(temp);
return Convert.ToBase64String(hash);
}
}
EDIT:
You could also specify the encoding when converting the byte array to string as follows:
return System.Text.Encoding.UTF8.GetString(hash);
or
return System.Text.Encoding.Unicode.GetString(hash);
This is what I went with. For those of you who want to optimize, check out https://stackoverflow.com/a/624379/991863.
public static string Hash(string stringToHash)
{
using (var sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(stringToHash)));
}
}
You can "compute the value for the specified byte array" using ComputeHash:
var hash = sha1.ComputeHash(temp);
If you want to analyse the result in string representation, then you will need to format the bytes using the {0:X2} format specifier.
Fastest way is this :
public static string GetHash(string input)
{
return string.Join("", (new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input))).Select(x => x.ToString("X2")).ToArray());
}
For Small character output use x2 in replace of of X2
I'll throw my hat in here:
(as part of a static class, as this snippet is two extensions)
//hex encoding of the hash, in uppercase.
public static string Sha1Hash (this string str)
{
byte[] data = UTF8Encoding.UTF8.GetBytes (str);
data = data.Sha1Hash ();
return BitConverter.ToString (data).Replace ("-", "");
}
// Do the actual hashing
public static byte[] Sha1Hash (this byte[] data)
{
using (SHA1Managed sha1 = new SHA1Managed ()) {
return sha1.ComputeHash (data);
}
I have a javascript backend that use CryptoJS to generate a hash, I need to generate the same hash on C# Client but can't reproduce the same result than javascript.
The backend code are this:
function generateHash (str, cypherkey) {
return CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(str, CryptoJS.enc.Base64.parse(cypherkey)))
}
console.log(generateHash("testString", "UTI5dVozSmhkSE1zSUhsdmRTZDJaU0JtYjNWdVpDQnBkQ0VnUVhKbElIbHZkU0J5WldGa2VTQjBieUJxYjJsdUlIVnpQeUJxYjJKelFIZGhiR3hoY0c5d0xtTnZiUT09"))
And print: "FwdJUHxt/xSeNxHQFiOhmPDRh73NFfuWK7LG6ssN9k4="
Then when I try to do the same on my C# client with this code:
public static string generateHash(string str, string cypherkey)
{
var keyenc = new System.Text.ASCIIEncoding();
byte[] keyBytes = keyenc.GetBytes(cypherkey);
var key = BitConverter.ToString(keyBytes);
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(key);
byte[] messageBytes = encoding.GetBytes(str);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hashmessage);
}
}
Print other result: "SiEjJASvYWfO5y+EiSJAqamMcUyBSTDl5Sy1zXl1J/k="
The problem are on the process to convert to Base64 the cypherkey, probably it's wrong.
Anyone know how can solve this?
Greetings and a lot of thanks ^^
I haven't seen the source of CryptoJs so there are assumptions here (from method names, encoding, etc):
public static string generateHash(string str, string cypherkey)
{
// based on CryptoJS.enc.Base64.parse
byte[] keyBytes = System.Convert.FromBase64String(cypherkey);
using (var hmacsha256 = new HMACSHA256(keyBytes))
{
byte[] hashmessage = hmacsha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(str));
return Convert.ToBase64String(hashmessage);
}
}
Result:
FwdJUHxt/xSeNxHQFiOhmPDRh73NFfuWK7LG6ssN9k4=
Hth
I use this code (found here c sharp helper aes encryption) to encrypt a string and the encrypted string I want to save to a file.
#region "Encrypt Strings and Byte[]"
// Note that extension methods must be defined in a non-generic static class.
// Encrypt or decrypt the data in in_bytes[] and return the result.
public static byte[] CryptBytes(string password, byte[] in_bytes, bool encryptAES)
{
// Make an AES service provider.
AesCryptoServiceProvider aes_provider = new AesCryptoServiceProvider();
// Find a valid key size for this provider.
int key_size_bits = 0;
for (int i = 4096; i > 1; i--)
{
if (aes_provider.ValidKeySize(i))
{
key_size_bits = i;
break;
}
}
Debug.Assert(key_size_bits > 0);
Console.WriteLine("Key size: " + key_size_bits);
// Get the block size for this provider.
int block_size_bits = aes_provider.BlockSize;
// Generate the key and initialization vector.
byte[] key = null;
byte[] iv = null;
byte[] salt = { 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xF1, 0xF0, 0xEE, 0x21, 0x22, 0x45 };
MakeKeyAndIV(password, salt, key_size_bits, block_size_bits, out key, out iv);
// Make the encryptor or decryptor.
ICryptoTransform crypto_transform;
if (encryptAES)
{
crypto_transform = aes_provider.CreateEncryptor(key, iv);
}
else
{
crypto_transform = aes_provider.CreateDecryptor(key, iv);
}
// Create the output stream.
using (MemoryStream out_stream = new MemoryStream())
{
// Attach a crypto stream to the output stream.
using (CryptoStream crypto_stream = new CryptoStream(out_stream,
crypto_transform, CryptoStreamMode.Write))
{
// Write the bytes into the CryptoStream.
crypto_stream.Write(in_bytes, 0, in_bytes.Length);
try
{
crypto_stream.FlushFinalBlock();
}
catch (CryptographicException)
{
// Ignore this exception. The password is bad.
}
catch
{
// Re-throw this exception.
throw;
}
// return the result.
return out_stream.ToArray();
}
}
}
// String extensions to encrypt and decrypt strings.
public static byte[] EncryptAES(this string the_string, string password)
{
System.Text.ASCIIEncoding ascii_encoder = new System.Text.ASCIIEncoding();
byte[] plain_bytes = ascii_encoder.GetBytes(the_string);
return CryptBytes(password, plain_bytes, true);
}
public static string DecryptAES(this byte[] the_bytes, string password)
{
byte[] decrypted_bytes = CryptBytes(password, the_bytes, false);
System.Text.ASCIIEncoding ascii_encoder = new System.Text.ASCIIEncoding();
return ascii_encoder.GetString(decrypted_bytes);
}
public static string CryptString(string password, string in_string, bool encrypt)
{
// Make a stream holding the input string.
byte[] in_bytes = Encoding.ASCII.GetBytes(in_string);
using (MemoryStream in_stream = new MemoryStream(in_bytes))
{
// Make an output stream.
using (MemoryStream out_stream = new MemoryStream())
{
// Encrypt.
CryptStream(password, in_stream, out_stream, true);
// Return the result.
out_stream.Seek(0, SeekOrigin.Begin);
using (StreamReader stream_reader = new StreamReader(out_stream))
{
return stream_reader.ReadToEnd();
}
}
}
}
// Convert a byte array into a readable string of hexadecimal values.
public static string ToHex(this byte[] the_bytes)
{
return ToHex(the_bytes, false);
}
public static string ToHex(this byte[] the_bytes, bool add_spaces)
{
string result = "";
string separator = "";
if (add_spaces) separator = " ";
for (int i = 0; i < the_bytes.Length; i++)
{
result += the_bytes[i].ToString("x2") + separator;
}
return result;
}
// Convert a string containing 2-digit hexadecimal values into a byte array.
public static byte[] ToBytes(this string the_string)
{
List<byte> the_bytes = new List<byte>();
the_string = the_string.Replace(" ", "");
for (int i = 0; i < the_string.Length; i += 2)
{
the_bytes.Add(
byte.Parse(the_string.Substring(i, 2),
System.Globalization.NumberStyles.HexNumber));
}
return the_bytes.ToArray();
}
#endregion // Encrypt Strings and Byte[]
With the code above you will get a list byte with this function it wil be converted to a list char
// Return a string that represents the byte array
// as a series of hexadecimal values separated
// by a separator character.
public static string ToHex(this byte[] the_bytes, char separator)
{
return BitConverter.ToString(the_bytes, 0).Replace('-', separator);
}
I get my data from a list of strings encrypt them like this and want to write them to a file
var encryptedLines = (from line in output
select Helper.ToHex(Encryption.EncryptAES(line, symKey),' ').ToList());
but File.WriteAllLines(fileWrite, encryptedLines); always give me the exception form the title or if i write result it of course just writes down System.Collections.Generic.List`1[System.Char] because it doesnt realy convert the datatype to list string
That beeing said I dont understand why I cant just write all lines of chars to a file?
I tried .ToString() or var result = encryptedLines.Select(c => c.ToString()).ToList();
You may either convert your char list to char array or convert the char list to a string using
listOfChars.Aggregate("", (str, x) => str + x);
The second approach is not recommended as it has a quadratic complexity (check the comments on this answer)
UPDATE:
After the comments by Mr. Lee I checked back again and I find this to be way more efficient:
listOfChars.Aggregate(new StringBuilder(""), (str, x) => str.Append(x));
I want to hash given byte[] array with using SHA1 Algorithm with the use of SHA1Managed.
The byte[] hash will come from unit test.
Expected hash is 0d71ee4472658cd5874c5578410a9d8611fc9aef (case sensitive).
How can I achieve this?
public string Hash(byte [] temp)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
}
}
For those who want a "standard" text formatting of the hash, you can use something like the following:
static string Hash(string input)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(input));
var sb = new StringBuilder(hash.Length * 2);
foreach (byte b in hash)
{
// can be "x2" if you want lowercase
sb.Append(b.ToString("X2"));
}
return sb.ToString();
}
}
This will produce a hash like 0C2E99D0949684278C30B9369B82638E1CEAD415.
Or for a code golfed version:
static string Hash(string input)
{
var hash = new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input));
return string.Concat(hash.Select(b => b.ToString("x2")));
}
For .Net 5 and above, the built-in Convert.ToHexString gives a nice solution with no compromises:
static string Hash(string input)
{
using var sha1 = SHA1.Create();
return Convert.ToHexString(sha1.ComputeHash(Encoding.UTF8.GetBytes(input)));
}
public string Hash(byte [] temp)
{
using (SHA1Managed sha1 = new SHA1Managed())
{
var hash = sha1.ComputeHash(temp);
return Convert.ToBase64String(hash);
}
}
EDIT:
You could also specify the encoding when converting the byte array to string as follows:
return System.Text.Encoding.UTF8.GetString(hash);
or
return System.Text.Encoding.Unicode.GetString(hash);
This is what I went with. For those of you who want to optimize, check out https://stackoverflow.com/a/624379/991863.
public static string Hash(string stringToHash)
{
using (var sha1 = new SHA1Managed())
{
return BitConverter.ToString(sha1.ComputeHash(Encoding.UTF8.GetBytes(stringToHash)));
}
}
You can "compute the value for the specified byte array" using ComputeHash:
var hash = sha1.ComputeHash(temp);
If you want to analyse the result in string representation, then you will need to format the bytes using the {0:X2} format specifier.
Fastest way is this :
public static string GetHash(string input)
{
return string.Join("", (new SHA1Managed().ComputeHash(Encoding.UTF8.GetBytes(input))).Select(x => x.ToString("X2")).ToArray());
}
For Small character output use x2 in replace of of X2
I'll throw my hat in here:
(as part of a static class, as this snippet is two extensions)
//hex encoding of the hash, in uppercase.
public static string Sha1Hash (this string str)
{
byte[] data = UTF8Encoding.UTF8.GetBytes (str);
data = data.Sha1Hash ();
return BitConverter.ToString (data).Replace ("-", "");
}
// Do the actual hashing
public static byte[] Sha1Hash (this byte[] data)
{
using (SHA1Managed sha1 = new SHA1Managed ()) {
return sha1.ComputeHash (data);
}
I have following code that works fine when I use a four letter word as input, E.g. “Test”. When the input is not a multiple of 4, it fails E.g. “MyTest”.
Eexception: Invalid length for a Base-64 char array.
QUESTIONS
Is it guaranteed that the encrypted result will be always compatible to a Unicode string (without any loss). If yes I can use UTF encoding instead of Base64? What's the difference between UTF8/UTF16 and Base64 in terms of encoding
How can add padding so that we get correct result (after decryption) even if the input is not a multiple of 4?
MAIN PRGORAM
class Program
{
static void Main(string[] args)
{
string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
string inputValue = "MyTest";
string keyValue = valid128BitString;
byte[] byteValForString = Convert.FromBase64String(inputValue);
EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
EncryptResult encyptedValue = new EncryptResult();
string resultingIV = "4uy34C9sqOC9rbV4GD8jrA==";
if (String.Equals(resultingIV,result.IV))
{
int x = 0;
}
encyptedValue.IV = resultingIV;
encyptedValue.EncryptedMsg = result.EncryptedMsg;
string finalResult = Convert.ToBase64String(Aes128Utility.DecryptData(encyptedValue, keyValue));
Console.WriteLine(finalResult);
if (String.Equals(inputValue, finalResult))
{
Console.WriteLine("Match");
}
else
{
Console.WriteLine("Differ");
}
Console.ReadLine();
}
}
AES Crypto UTILITY
public static class Aes128Utility
{
private static byte[] key;
public static EncryptResult EncryptData(byte[] rawData, string strKey)
{
EncryptResult result = null;
if (key == null)
{
if (!String.IsNullOrEmpty(strKey))
{
key = Convert.FromBase64String((strKey));
result = Encrypt(rawData);
}
}
else
{
result = Encrypt(rawData);
}
return result;
}
public static byte[] DecryptData(EncryptResult encryptResult, string strKey)
{
byte[] origData = null;
if (key == null)
{
if (!String.IsNullOrEmpty(strKey))
{
key = Convert.FromBase64String(strKey);
origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
}
}
else
{
origData = Decrypt(Convert.FromBase64String(encryptResult.EncryptedMsg), Convert.FromBase64String(encryptResult.IV));
}
return origData;
}
private static EncryptResult Encrypt(byte[] rawData)
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
aesProvider.Key = key;
aesProvider.Mode = CipherMode.CBC;
aesProvider.Padding = PaddingMode.PKCS7;
aesProvider.IV = Convert.FromBase64String("4uy34C9sqOC9rbV4GD8jrA==");
using (MemoryStream memStream = new MemoryStream())
{
CryptoStream encStream = new CryptoStream(memStream, aesProvider.CreateEncryptor(), CryptoStreamMode.Write);
encStream.Write(rawData, 0, rawData.Length);
encStream.FlushFinalBlock();
EncryptResult encResult = new EncryptResult();
encResult.EncryptedMsg = Convert.ToBase64String(memStream.ToArray());
encResult.IV = Convert.ToBase64String(aesProvider.IV);
return encResult;
}
}
}
private static byte[] Decrypt(byte[] encryptedMsg, byte[] iv)
{
using (AesCryptoServiceProvider aesProvider = new AesCryptoServiceProvider())
{
aesProvider.Key = key;
aesProvider.IV = iv;
aesProvider.Mode = CipherMode.CBC;
aesProvider.Padding = PaddingMode.PKCS7;
using (MemoryStream memStream = new MemoryStream())
{
CryptoStream decStream = new CryptoStream(memStream, aesProvider.CreateDecryptor(), CryptoStreamMode.Write);
decStream.Write(encryptedMsg, 0, encryptedMsg.Length);
decStream.FlushFinalBlock();
return memStream.ToArray();
}
}
}
}
DTO
public class EncryptResult
{
public string EncryptedMsg { get; set; }
public string IV { get; set; }
}
REFERENCES:
How to create byte[] with length 16 using FromBase64String
Getting incorrect decryption value using AesCryptoServiceProvider
If you are encrypting, then encoding Base64 for me doesn't add anything useful, instead it brings the problems you face.
As for the padding, a solution i have seen is to create a new byte[] that is indeed a multiple of 4 and copy the source byte[] to that new byte[].
So, something like this:
if (rawdata.Length % 16 !=0)
{
newSource = new byte[source.Length + 16 - source.Length % 16];
Array.Copy(source, newSource, source.Length);
}
Base64 is a way of representing binary values as text so that you do not conflict with common control codes like \x0A for newline or \0 for a string terminator. It is NOT for turning typed text in to binary.
Here is how you should be passing the text in and getting it back out. You can replace UTF8 with whatever encoding you want, but you will need to make sure the Encoding.Whatever.GetBytes is the same encoding as the Encoding.Whatever.GetString
class Program
{
static void Main(string[] args)
{
string valid128BitString = "AAECAwQFBgcICQoLDA0ODw==";
string inputValue = "MyTest";
string keyValue = valid128BitString;
//Turns our text in to binary data
byte[] byteValForString = Encoding.UTF8.GetBytes(inputValue);
EncryptResult result = Aes128Utility.EncryptData(byteValForString, keyValue);
EncryptResult encyptedValue = new EncryptResult();
//(Snip)
encyptedValue.IV = resultingIV;
encyptedValue.EncryptedMsg = result.EncryptedMsg;
string finalResult = Encoding.UTF8.GetString(Aes128Utility.DecryptData(encyptedValue, keyValue));
Console.WriteLine(finalResult);
if (String.Equals(inputValue, finalResult))
{
Console.WriteLine("Match");
}
else
{
Console.WriteLine("Differ");
}
Console.ReadLine();
}
}