How to guarantee to the specific endianness for hash computing? - c#

There is the function for sha256 computing:
static string GetHash(string input)
{
byte[] bytes = Encoding.UTF8.GetBytes(input); //1
SHA256 SHA256 = SHA256Managed.Create();
byte[] hashBytes = SHA256.ComputeHash(bytes); //2
var output = BitConverter.ToString(hashBytes); //3
return output;
}
It gets utf8-bytes from c# string, next it computes hash and returns one as string.
I'am confusing about BitConverter. Its ToString(byte[]) method depends on machine architecture (liitle/big endian). My purpose is providing specific endianess (big-endian) for output string.
How can I do it?
I think it can be like:
byte[] bytes = Encoding.UTF8.GetBytes(input); //1
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes)
}
//..
But I dont' know how UTF8.GetBytes works (UTF8.GetBytes docs doesn't contains anything about endianness). Is it depending on endianness also? If so I suppose it is right way to reverse array after 1 step, is it?

I think it doesn't matter here because UTF-8 is byte oriented as stated here :
Isn’t on big endian machines UTF-8's byte order different than on little endian machines? So why then doesn’t UTF-8 require a BOM?

Related

Decrypt using public key, RSA and Bouncy castle

I need to decrypt a signature hash using RSA. I've got a hexadecimal string of 288 characters long which is a general public key from an institution. It represents hexadecimal bytes, so 144 bytes total.
The first 8 bytes are the so called CAR. Which is used for identification. The next 128 bytes are the Modulus N. And the next 8 bytes are the exponent E.
I've never worked with cryptography before so go easy on me. I'm using C# and the Bouncy Castle library for the decryption algorithms. Now, If I understand correctly, a 1024 bit modulus and 64 bits exponent is not strange. I currently have this bit of code:
public byte[] rsa_decrypt(byte[] data)
{
var N = PublicKey.ToCharArray().Slice(16,256);
var E = PublicKey.ToCharArray().Slice(272,16);
RsaEngine rsa = new RsaEngine();
Org.BouncyCastle.Math.BigInteger modulus = new Org.BouncyCastle.Math.BigInteger(new string(N).Insert(0,"00"),16);
Console.WriteLine(modulus);
Org.BouncyCastle.Math.BigInteger exponent = new Org.BouncyCastle.Math.BigInteger(new string(E).Insert(0,"00"),16);
Console.WriteLine(exponent);
RsaKeyParameters x = new RsaKeyParameters(false,modulus,exponent);
var eng = new Pkcs1Encoding(new RsaEngine());
eng.Init(false,x);
return eng.ProcessBlock(data,0,data.Length);
}
The Slice<T>(this T[],offset,length) method is just a small thing I wrote to cut arrays in pieces, nothing special and it works. The insertion of the "00" in the string is because the string could otherwise be interpreted as unsigned I believe.
When I run this code I get the exception
Unhandled exception. Org.BouncyCastle.Crypto.InvalidCipherTextException: block incorrect at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(Byte[] input, Int32 inOff, Int32 inLen) at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.ProcessBlock(Byte[] input, Int32 inOff, Int32 length)
Obviously I'm doing something wrong. Can anybody tell me what I'm doing wrong, why I'm doing it wrong, and most preferably, what I should be doing. Again, never worked with crypto algorithms or this library ever before.

Roundtrip Unicode conversion returns different Byte[] array

I'm tinkering with RSA signing of data.
I'm using a plaintext string, which i convert to byte array. i then generate private certificate, sign the byte array and then generate public key.
next i'm using the same byte array to verify the signature.
but i want to convert signature, in between steps, to the string - idea is to append it later on to the file that's being signed.
static void TestSigning(string privateKey)
{
string data = "TEST_TEST-TEST+test+TEst";
Console.WriteLine("==MESSAGE==");
Console.WriteLine(data);
byte[] dataByte = Encoding.Unicode.GetBytes(data);
using (var rsa = new RSACryptoServiceProvider())
{
rsa.FromXmlString(privateKey);
var publicKey = rsa.ToXmlString(false);
byte[] signature = rsa.SignData(dataByte, CryptoConfig.MapNameToOID("SHA512"));
string signatureString = Encoding.Unicode.GetString(signature);
byte[] roundtripSignature = Encoding.Unicode.GetBytes(signatureString);
Console.WriteLine("==TEST==");
Console.WriteLine(signature.Length.ToString());
Console.WriteLine(roundtripSignature.Length.ToString());
using (var checkRSA = new RSACryptoServiceProvider())
{
checkRSA.FromXmlString(publicKey);
bool verification = checkRSA.VerifyData(
dataByte,
CryptoConfig.MapNameToOID("SHA512"),
roundtripSignature);
Console.WriteLine("==Verification==");
Console.WriteLine(verification.ToString());
Console.ReadKey();
}
}
}
now here's the fun part
if i use UTF8 encoding i get byte arrays of different length
256 is the original size
484 is the roundtrip
UTF7 returns different sizes too
256 vs 679
both ASCII and Unicode return proper sizes 256 vs 256.
i've tried using
var sb = new StringBuilder();
for (int i = 0; i < signature.Length; i++)
{
sb.Append(signature[i].ToString("x2"));
}
to get the string. I'm then using Encoding.UTF8.GetBytes() method
this time i get the sizes of:
256 vs 512
if i remove the format from toString() i get:
256 vs 670
signature verification alwayas failed.
it works fine if i use 'signature' instead of roundtripSignature.
my question: Why, despite using same encoding type i get different byte arrays and strings? shouldn't this conversion be lossless?
Unicode isn't a good choice because, at minimum, \0, CR, LF, <delete>, <backspace> (and the rest of the control codes) can mess things up. (See an answer about this for Encrypt/Decrypt for more).
As #JamesKPolk said, you need to use a suitable binary-to-text encoding. Base64 and hex/Base16 are the most common, but there are plenty of other viable choices.

How to encrypt a guid into equal length string in C#?

I need to encrypt a guid and the encrypted string length should be 32 char max, not more than that. Please suggest me an encryption method available in C# for that.
I was using AES in CFB mode, as in Code Project, but that is producing 64 char long.
Well, a GUID is inherently 16 bytes of data... so that's what you should encrypt. That's a single block in AES. As per Reid's comment, the exact size of the output will depend on how you've configured things, but to convert the result into text, you'll probably want to use base64 if you need ASCII text with a fairly minimal size.
Base64 allows you to use 24 bytes to produce a 32 character result - so you should try different padding/cipher modes until you find one where the output is 24 bytes or less, if this 32 character requirement is a "hard" one (and you need ASCII; if you don't need ASCII then there's a lot more room to play...)
If a GUID is 16 bytes (I'll take that as a given) then you can simply do a single AES ECB mode encrypt without padding of the plaintext (i.e. the GUID). You can then convert to hexadecimals. That will with 100% certainty result in a 32 character result.
Note that ECB does not use an IV, which means that you can distinguish different GUID's from each other (as each GUID will be mapped to exactly one ciphertext). But the ciphertext should otherwise simply be identical to the security of the used block cipher and key.
public class EncryptGUI
{
private Aes aes;
public EncryptGUI (byte[] key)
{
aes = Aes.Create ();
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.None;
aes.Key = key;
}
public String encryptUID (byte[] guid)
{
ICryptoTransform aesDecryptor = aes.CreateDecryptor ();
byte[] result = aesDecryptor.TransformFinalBlock (guid, 0, guid.Length);
return ToHex (result);
}
public static string ToHex (byte[] data)
{
StringBuilder hex = new StringBuilder (data.Length * 2);
foreach (byte b in data)
hex.AppendFormat ("{0:x2}", b);
return hex.ToString ();
}
public static void Main (string[] args)
{
byte[] key = new byte[16];
EncryptGUI main = new EncryptGUI (key);
byte[] guid = new byte[16];
Console.Out.WriteLine (main.encryptUID (guid));
}
}

Write T-SQL functionality in .NET

I have this bit of t-sql code
set #UrlHash = convert(bigint, hashbytes('MD5', #Url))
I wonder if I can write a function in C# which returns me the exact same hash as the line above without going to SQL.
Is it possible?
Requirement is that C# MUST created exact same hash.
The select
SELECT CONVERT(BIGINT, HASHBYTES('MD5', 'http://stackoverflow.com'))
will yield the following result:
-3354682182756996262
If you now try to create a MD5 hash in C#
MD5 md5 = MD5.Create();
byte[] textToHash = Encoding.UTF8.GetBytes("http://stackoverflow.com");
byte[] result = md5.ComputeHash(textToHash);
long numeric = BitConverter.ToInt64(result, 0);
numeric will be 8957512937738269783.
So what's the issue (besides the fact that a MD5 hash is 128-bit and BIGINT/long is just 64-bit)?
It's an endian issue (the bytes are in the wrong order). Let's fix it using the BitConverter class and reverse the bytes as needed:
MD5 md5 = MD5.Create();
byte[] textToHash = Encoding.UTF8.GetBytes("http://stackoverflow.com");
byte[] result = md5.ComputeHash(textToHash);
if (BitConverter.IsLittleEndian)
Array.Reverse(result);
long numeric = BitConverter.ToInt64(result, 0);
numeric is now -3354682182756996262 as you want.
You should use MD5 class, here is the example from http://blogs.msdn.com/b/csharpfaq/archive/2006/10/09/how-do-i-calculate-a-md5-hash-from-a-string_3f00_.aspx, with output as int 64 :
public int64 CalculateMD5Hash(string input)
{
// step 1, calculate MD5 hash from input
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
byte[] hash = md5.ComputeHash(inputBytes);
return BitConverter.ToInt64(hash, 0);
}
Isn't an MD5 hash standard? Can't you use a standard MD5 C# implementation? What about using the code in here?

How to retrieve IV from an Encrypted string, then decrypt that string using AES128

I know very little about Encryption, but my goal is to essentially decrypt strings. I have been given the AES(128) key.
However, I must retrieve the IV from the Encrypted string, which is the first 16 bits.
Heres the doc for salesforce for more information (if what i explained was incorrect)
Encrypts the blob clearText using the specified algorithm and private
key. Use this method when you want Salesforce to generate the
initialization vector for you. It is stored as the first 128 bits (16
bytes) of the encrypted blob
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_classes_restful_crypto.htm (encryptWithManagedIV)
For Retrieving the IV I've tried something like this (I don't believe it's right though):
public string retrieveIv()
{
string iv = "";
string input = "bwZ6nKpBEsuAKM8lDTYH1Yl69KkHN1i3XehALbfgUqY=";
byte[] bytesToEncode = Encoding.UTF8.GetBytes(input);
for(int i = 0; i <= 15; i++){
iv += bytesToEncode[i].ToString(); ;
}
return iv;
}
(Just ignore the fact that the input is hardcoded and not parameterized; easier for testing purposes)
Then use the Best answer from this question to decrypt the string
The IV shouldn't be expressed as a string - it should be as a byte array, as per the AesManaged.IV property.
Also, using Encoding.UTF8 is almost certainly wrong. I suspect you want:
public static byte[] RetrieveIv(string encryptedBase64)
{
// We don't need to base64-decode everything... just 16 bytes-worth
encryptedBase64 = encryptedBase64.Substring(0, 24);
// This will be 18 bytes long (4 characters per 3 bytes)
byte[] encryptedBinary = Convert.FromBase64String(encryptedBase64);
byte[] iv = new byte[16];
Array.Copy(encryptedBinary, 0, iv, 0, 16);
return iv;
}

Categories

Resources