AES do I need to split my decoded message to chunks - c#

I have a picture and I want to encrypt it using AES, do I need to split it to chunks? (because if I get a key with the size of 256 bits and my message is bigger, if I xor them, most of the message will remain the decoded message, so how will that help?)
if yes, how do I go about doing that?

AES is not XOR encrpytion and you do not need to block
// this could also just be a byte array
string original = "Here is some data to encrypt!";
using (Aes myAes = Aes.Create())
{
// Encrypt the string to an array of bytes.
byte[] encrypted = EncryptStringToBytes_Aes(original,
myAes.Key, myAes.IV);
// Decrypt the bytes to a string.
string roundtrip =
DecryptStringFromBytes_Aes(encrypted,
myAes.Key, myAes.IV);
}

Related

How to properly hash a password

I want to re-create the MyBB hashing process so I can use its database to authenticate users on a 3rd party app (written on C#).
MyBB uses:
md5(md5($salt).password)
My problem is that the result I get on C# is nowhere similar to the one MyBB gets.
What I've done on C#:
public string HashPass(string password, string salt)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] saltHash =md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(salt));
string passwordAndSalt = password + System.Text.Encoding.ASCII.GetString(saltHash);
byte[] finalHash = md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(passwordAndSalt));
string final = System.Text.Encoding.ASCII.GetString(finalHash);
return final;
}
The result I get from using that function for password "Test123" and salt "0fYR6mEE" (gathered from MyBB db) is: "??R?????s??" while the actual result should look like "VaHffsyzJeEa4dB3bbMWeUlJObAfN5I9rf1CuNRXCa6xPJTzXL".
Most likely I'm missing something obvious, sorry about that.
There are unknowns here. Which encoding does MyBB use to the password bytes? It could be ASCII, ANSI, or UTF8 or it could get the string bytes directly, i.e., without encoding. So I will write it partly as pseudo code
byte[] passwordBytes = GetBytes(password); // Where you have to define GetBytes
byte[] saltBytes = System.Convert.FromBase64String(salt); // Assuming it is given as base64
// Merge the password bytes and the salt bytes
var mergedBytes = new byte[passwordBytes.Length + saltBytes.Length];
Array.Copy(passwordBytes, mergedBytes, passwordBytes.Length);
Array.Copy(saltBytes, 0, mergedBytes, passwordBytes.Length, saltBytes.Length);
var md5 = new MD5CryptoServiceProvider();
byte[] finalHash = md5.ComputeHash(mergedBytes);
string final = System.Convert.ToBase64String(finalHash);
Note that I'm merging the password bytes and the salt bytes, not the password string and the salt string. Then the MD5 it taken only once from these merged bytes.
But I'm not sure what md5(md5($salt).password) does. Is md5() returning the the hash as base64 string already? Maybe you would have to convert the salt from base64 to bytes[], then get the MD% hash, convert it into a base64 string and then concatenate it with the password string. Then get the bytes from this combined string, do the hash again and convert the result to a base64 string again.
You would have to dig deeper into the source code of MyBB to be sure.

Convert Aes.Key to SecureString in C#

How do I convert Aes.Key to a secureString ? I am doing a byte[] -> string -> securestring. I am facing a different problem.
When converting the key, in byte[], to string and back to byte[] I get a different byte[]. What is the problem with the code ?
Aes aes = Aes.Create();
aes.GenerateIV();
aes.GenerateKey();
byte[] byteKey1 = aes.Key;
string sKey = Encoding.UniCode.GetString(byteKey);
byte[] byteKey2= Encoding.UniCode.GetBytes(sKey);
"byteKey1" and "byteKey2" are sometimes different. They are equal if I use Encoding.Default but that has problems when different machines have different default encoding.
How do I convert the Key in byte[] to SecureString and back to byte[] ?
Thanks.
Never use text encoding (e.g., Unicode or ASCII) on binary data like a cryptographic key or ciphertext. Encoding is intended for textual representations, and the implementation can change the binary contents as permitted by the encoding.
Instead, use Convert.ToBase64String and Convert.FromBase64String to convert binary text into a form that can be encoded in a textual format.
The following code will illustrate byteKey2 and byteKey will be identical.
string sKey = Convert.ToBase64String(byteKey);
byte[] byteKey2= Convert.FromBase64String(sKey);
bool equal = byteKey.SequenceEqual(byteKey2); // will be true

C# use SHA1 to hash string into byte array

I'm using SHA1 to encrypt some values like password.
This is my code:
String passwd = Membership.GeneratePassword(10, 2);
SHA1 sha = new SHA1CryptoServiceProvider();
byte [] password = sha.ComputeHash(passwd);
But VS returns error, because passwd is a string.
I have to store the password in a byte array, so is there a way to solve this?
String passwd = Membership.GeneratePassword(10, 2);
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(passwd);
SHA1 sha = new SHA1CryptoServiceProvider();
byte [] password = sha.ComputeHash(bytes);
Note that SHA1 does not encrypt data but hash them instead. Encrypted data can be decrypted. Hash algorithms are one way.
Use an Encoding to convert the string to a byte array
var bytes= Encoding.UTF8.GetBytes(passwd);
var password = sha.ComputeHash(bytes);

Hashing and GetString/GetBytes issue

I have the below code to hash/store/retrieve data for passwords but my first unit test and it fails.
I beleive its the Encoding causing the problem because when GetBytes is called it returns byte[38], byte[36] when it should be 20 I think.
I have to convert to string as I'm storing it in a database.
Any ideas? Thanks
[Fact]
public void EncryptDecryptPasswordShouldMatch()
{
string password = "password";
string passwordKey = string.Empty;
string passwordSalt = string.Empty;
Helpers.CreatePasswordHash(password, out passwordSalt, out passwordKey);
Assert.True(Helpers.PasswordsMatch(passwordSalt, passwordKey, password));
}
public static bool PasswordsMatch(string passwordSalt, string passwordKey, string password)
{
byte[] salt = Encoding.UTF8.GetBytes(passwordSalt);
byte[] key = Encoding.UTF8.GetBytes(passwordKey);
using (var deriveBytes = new Rfc2898DeriveBytes(password, salt))
{
byte[] newKey = deriveBytes.GetBytes(20); // derive a 20-byte key
if (!newKey.SequenceEqual(key))
return false;
}
return true;
}
public static void CreatePasswordHash(string password, out string passwordSalt, out string passwordKey)
{
// specify that we want to randomly generate a 20-byte salt
using (var deriveBytes = new Rfc2898DeriveBytes(password, 20))
{
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20); // derive a 20-byte key
passwordSalt = Encoding.UTF8.GetString(salt);
passwordKey = Encoding.UTF8.GetString(key);
}
}
Use Base64 to encode binary values to string, it can deal with arbitrary byte sequences. UTF-8 is for transforming between unicode text and bytes and not every valid sequence of bytes is valid for UTF-8. Use Utf-8 to turn the password(which is text) to bytes, but use Base64 for salt and hash.
Convert.ToBase64String and Convert.FromBase64String should do the trick.
Some additional notes:
Your terminology is really weird, don't call the hash key, call it hash.
I'd concatenate the hash and salt in your CreatePasswordHash function, so the caller doesn't have to bother with having two separate values.
Something like return Base64Encode(salt)+"$"+Base64Encode(hash) then use string.Split in the verification function.
It's recommended to use a constant time comparison to verify, but it seems unlikely your timing side-channel can actually be exploited.
Your iteration count is pretty low. I recommend increasing it to 10000.
Modify your code to use the Convert.FromBase64String method:
byte[] salt = Convert.FromBase64String(passwordSalt);
byte[] key = Convert.FromBase64String(passwordKey);
Modify your code to use the Convert.ToBase64String method:
passwordSalt = Convert.ToBase64String(salt);
passwordKey = Convert.ToBase64String(key);
UTF8 is not a way to turn any random bytes into a string. It is for encoding text; not just any bytes are valid UTF8 encoded values. You could use Base64 to and from conversions. Note that base64-encoded strings will take up ~4/3 times the characters of the raw bytes. Here's an example:
byte[] salt = deriveBytes.Salt;
byte[] key = deriveBytes.GetBytes(20); // derive a 20-byte key
passwordSalt = Convert.ToBase64String(salt);
passwordKey = Convert.ToBase64String(key);
And later:
byte[] salt = Convert.FromBase64String(passwordSalt);
byte[] key = Convert.FromBase64String(passwordKey);

Why isn't my PHP SHA256 hash equivalent to C# SHA256Managed hash

Why aren't these the same?
php:
$hash = hash('sha256', $userData['salt'] . hash('sha256', $password) );
c#
public static string ComputeHash(string plainText, string salt)
{
// Convert plain text into a byte array.
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] saltBytes = Encoding.UTF8.GetBytes(salt);
SHA256Managed hash = new SHA256Managed();
// Compute hash value of salt.
byte[] plainHash = hash.ComputeHash(plainTextBytes);
byte[] concat = new byte[plainHash.Length + saltBytes.Length];
System.Buffer.BlockCopy(saltBytes, 0, concat, 0, saltBytes.Length);
System.Buffer.BlockCopy(plainHash, 0, concat, saltBytes.Length, plainHash.Length);
byte[] tHashBytes = hash.ComputeHash(concat);
// Convert result into a base64-encoded string.
string hashValue = Convert.ToBase64String(tHashBytes);
// Return the result.
return hashValue;
}
C# is outputting a base64 ecoded string, and PHP is outputting a number in hex. A better comparison might be to pass the parameter true to the end of the hash function of PHP and base64 the result:
$hash = base64_encode(
hash('sha256', $userData['salt'] . hash('sha256', $password), true )
);
Because they're different. Your C# code encodes the computed hash in Base64 encoding at the end. PHP just returns a string of hexadecimal digits.
First suspect:
Encoding.UTF8.GetBytes(plainText);
C# uses UTF-8, your PHP probably doesn't, but you could be lucky if you use strictly letters from the US-ASCII subset.
Second suspect:
Convert.ToBase64String(tHashBytes);
There's nothing about Base64 in your PHP.
Since PHP will give you a hex-encoded result, you should switch to Hex in your C#, too. See this answer for solutions.
Well I'm no C# programmer, but one thing that leaps out at me is this:
// Convert result into a base64-encoded string.
string hashValue = Convert.ToBase64String(tHashBytes);
Are you base64-encoding the final output in C#? Because you're not in PHP...
C#
string toHash = "abcdefg";
SHA256Managed hash = new SHA256Managed();
byte[] signatureData = hash.ComputeHash(new UnicodeEncoding().GetBytes(toHash));
string hashResult = System.Convert.ToBase64String(signatureData);
PHP
print base64_encode(hash("sha256",mb_convert_encoding("abcdefg","UTF-16LE"),true));
Write like top code,They are the same
C#
string toHash = "abcdefg";
SHA256Managed hash = new SHA256Managed();
byte[] signatureData = hash.ComputeHash(new UnicodeEncoding().GetBytes(toHash));
string hashResult = System.Convert.ToBase64String(signatureData);
PHP
print base64_encode(hash("sha256",mb_convert_encoding("abcdefg","UTF-16LE"),true));
Works for me.

Categories