Creating custom length password in Rijndael Cryptography Algorithm - c#

I'm using c# for implementing Rijndael algorithm to encrypt/decrypt files. Below is my code:
private void EncryptFile(string inputFile, string outputFile, string password)
{
try
{
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password.ToString());
string cryptFile = outputFile;
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
catch
{
}
}
Now, the thing is that, the function works only if password length is a multiple of 8. that is, if the password length is 8,16,32, etc., then it works else not.

Simply taking the password and getting its Unicode representation in bytes makes pretty terrible key. Please don't do that! The correct way to go is to use a salted hash as a key -- that is, take a salt, a password, and mix them together with a hash function.
To derive a key from a variable-length password, use PBKDF2. PBKDF2 is designed to make brute forcing slower when the attacker has fast access to the data.
string password = ...;
byte[] salt = ...;
int keyLength = 32;
byte[] key;
using(var pbkdf = new Rfc2898DeriveBytes(password, salt))
{
key = pbkdf.GetBytes(keyLength);
}
If you need something which uses less CPU, HMAC will work but also be faster to brute force:
using(var hmac = new HMACSHA256())
{
hmac.Key = salt;
key = hmac.ComputeHash(Encoding.UTF8.GetBytes(password));
}
Note that there exists hardware now which can very effectively attack PBKDF2 so this won't do much to help against a determined attacker with resources. If this is important to you, branching out of the .NET base classes and using a more modern algorithm like scrypt might be preferred.

Pseudo Code =>
string passwordFlagLength(string password)
{
int count = 1
for (int i = 0 to 31)
{
if (password.length == count) return password;
if (password.length < count) return password + new string("x", count - password.length);
count = count * 2
}
}
This takes a password and makes it length 1, 2, 4, 8, etc... up to a 31 bit value.(int w/out negative)
if the value is already a proper flag size number, it uses it, otherwise it fills in the rest with "x"
--> Note: I agree with everyone elses comments regarding better was to do security/issues, I just posted this, because the immediate issue posted was due to a string size not being a base 2 bit value. I also just applied the count which I forgot in my original code

Related

Need help creating IsValidPassword for PBKDF2 in C#

Having the hardest time trying to create a PBKDF2 valid password checker. The PBKDF2 code comes from a SharpHash project; https://github.com/ron4fun/SharpHash. The Class is: SharpHash/SharpHash.Tests/KDF/PBKDF2_HMACTests.cs
The example shows how to implement it but does not have any examples on how to verify the hash afterwards. I managed to tried several different "IsValidPassword" is one of the methods, but none of them seem to work. Each and every one of them the result is false no matter what values I add to the PBKDF2 or IsValidPassword methods. I also tried changing to a hex and also base64 but got the same results; it failed.
I even replaced Rfc2898DeriveBytes.
Does anyone have any experience with PBKDF2 password verification. This would be application based, not website based. IDE environment Visual Studios 2019 - C#.
Thank you.
public void TestOne()
{
IPBKDF2_HMAC PBKDF2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash, Password, Salt, 100000);
byte[] Key = PBKDF2.GetBytes(64);
PBKDF2.Clear();
string ActualString = Converters.ConvertBytesToHexString(Key, false);
Assert.AreEqual(ExpectedString, ActualString);
}
public bool IsValidPassword(string password, string hashPass)
{
bool result = false;
// Extract the bytes
byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
// Get the salt
byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
Array.Copy(hashBytes, 0, salt, 0, 20);// Doesn't matter what values and here; same issue… False
// Compute the hash on the password the user entered
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000);
byte[] hash = pbkdf2.GetBytes(64);
// compare the results
for (int i = 0; i < 20; i++) // If I go to 64 I get an error
{
if (hashBytes[i + 20] != hash[i])
{
return false;
}
}
return true;
}
// Replaced Rfc2898DeriveBytes
public bool IsValidPassword(string password, string hashPass)
{
bool result = false;
IHash hash1 = HashFactory.Crypto.CreateSHA1();
// Extract the bytes
byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
byte[] Password = Encoding.ASCII.GetBytes(password);
// Get the salt
byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
Array.Copy(hashBytes, 0, salt, 0, 20); // Doesn't matter what values and here; same issue… False
// Compute the hash on the password the user entered
var pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, 100000); // Replaced Rfc2898DeriveBytes
byte[] Key = pbkdf2.GetBytes(64);
pbkdf2.Clear();
string test = Converters.ConvertBytesToHexString(Key, false); // Taking a peek
string test2 = Encoding.ASCII.GetString(hashBytes); // Taking a peek
// compare the results
for (int i = 0; i < 20; i++)
{
if (hashBytes[i + 20] != Key[i])
{
return false;
}
}
return true;
}
taking a quick look at this, the issue you are encountering is simply a misrepresentation of the data contents involved.
password is a base256 based data while hashPass is a base16 based data.
You have to use the appropriate conversion routine when converting hashPass to byte[].
To do that, simply use this method found in the Converters class too.
byte[] hashBytes = Converters.ConvertHexStringToBytes(hashPass);
Do note that I assumed that your password is in base256 (since you didn't specify this in the question) so you can leave it as it is.
The only change you need to make is the one I described above.
Well, I suppose this will help someone else down the road apiece. I had to do some serious searching and banging my head up against the wall because this was my first attempt at PBKDF2 to come up with a functional verification method that isn't included with the SharpHash project. Just so that anyone reading this would understand what my problem was. The code generated the password with no issues whatsoever. However, there was no function in the code project that actually verified the password using the salt, generated password and iteration.
The code provided is the simple version because I have also added overloads to the methods that I don't need to post. This method has default settings whereas one of the overloads allows for complete customization of the hash algorithm, salt and iteration. Each of these I had tested and they worked as expected.
Hope this helps someone. :-)
private static Int32 Salt256bit { get; } = 256 / 8; // 256 bits = 32 Bytes
public static string GetHashPBKDF2Password(string password)
{
// Notes:
// Create a 32-byte secure salt and the same size of the key. This 32-byte produces 256 bits key output.
// Add the same 32-byte size to the pbkdf2.GetBytes.
// KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC hashes these values using the crypto SHA presented.
// Double the hashBytes bytes then add the salt and pbkdf2.GetBytes value.
// Copy each of the 32-bytes to the hashBytes bytes from the hashed salt and hashed value.
//
byte[] Password = Encoding.Unicode.GetBytes(password);
string hashPass = string.Empty;
// Create the salt value with a cryptographic PRNG
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[ByteSize]); // 32 Bytes = 256 bits.
// Create the KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC and get the hash value using the SHA presented.
// I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
IHash sha = HashFactory.Crypto.CreateSHA1();
IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(sha, Password, salt, Pbkdf2Iterations);
byte[] hash = pbkdf2.GetBytes(ByteSize); // 32 Bytes = 256 bits.
// Double the size of the byte array to include the "pbkdf2.GetBytes" and salt.
Int32 g = hash.Length + salt.Length;
byte[] hashBytes = new byte[g];
// Combine the salt and password bytes.
Array.Copy(salt, 0, hashBytes, 0, ByteSize);
Array.Copy(hash, 0, hashBytes, ByteSize, ByteSize);
// Turn the combined salt+hash into a string for storage
hashPass = Convert.ToBase64String(hashBytes);
return hashPass;
}
public static bool ValidatePBKDF2Password(string password, string hashPass)
{
try
{
byte[] Password = Encoding.Unicode.GetBytes(password);
bool result = true;
// Extract the bytes
byte[] hashBytes = Convert.FromBase64String(hashPass);
// Get the salt
byte[] salt = new byte[32];
Array.Copy(hashBytes, 0, salt, 0, 32);
// Compute the hash on the password that user entered.
// I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
IHash hash1 = HashFactory.Crypto.CreateSHA1();
IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, Pbkdf2Iterations);
byte[] hash = pbkdf2.GetBytes(32);
// compare the results
for (int i = 0; i < 32; i++)
{
if (hashBytes[i + 32] != hash[i])
{
result = false;
}
}
return result;
}
catch (Exception)
{
return false;
}
}
How to use: string GeneratedHash = PBKDF2Helper.GetHashPBKDF2Password("password");
Results: hv6t8N4rrVSKYFm80cCoVUEiUk2o11xLBc6lJb5kBXKTcwcKwl9dZwSdce01X0bi8BBhJY/QGGnNVAcR7ZhSvQ==
Verify Paword: Boolean tester = PBKDF2Helper.ValidatePBKDF2Password("password", GeneratedHash);
txtVerificationResults.Text = tester.ToString();

When merging two arrays, the first array gets shorter by 1

I have a password which I hash with SHA256. Then I have a salt which looks like that:
AAAAAAAAAAAAAAAAAAAAAA==
At the end of the process both of them are byte-arrays which I then merge into a new byte-array.
My PROBLEM is that while merging the password with the salt, my hashed password gets shorter by one character at the end.
Expected output:
uIxnpgdBQpSPJrqwYucIOeyOyqyCv7HbBfd74ovoxjI=AAAAAAAAAAAAAAAAAAAAAAAAA==
Output:
uIxnpgdBQpSPJrqwYucIOeyOyqyCv7HbBfd74ovoxjIAAAAAAAAAAAAAAAAAAAAAAAAA==
As you can see there is a = missing after the l.
My Method:
public static byte[] HashPassword(byte[] passwordToHash)
{
byte[] hInput;
byte[] hSalt = GetSalt();
using(SHA256 sh = SHA256.Create())
{
hInput = sh.ComputeHash(passwordToHash);
}
byte[] SaltedPw = new byte[(hInput.Length+ 1 ) + (hSalt.Length + 3)];
Array.Copy(hInput,0, SaltedPw, 0,hInput.Length);
Array.Copy(hSalt, 0, SaltedPw, hInput.Length, hSalt.Length);
return SaltedPw;
}
public static byte[] GetSalt()
{
byte[] salt = new byte[16];
return salt;
}
How can I prevent the shortening of my password?
You are doing it wrong. You must not add the salt to the hashed password. You must add the salt to the plain password and then hash. The point is to make the hash of a current or short password unrecognizable.
The base 64 encoding is only applied to the final result to allow storing the password hash as string. Therefore, you will never have to merge base 64 strings. Base 64 strings are padded with = at the end to get a length which is a multiple of 4. Therefore you will never see a = in the middle.
public static string GetHashedPassword(string plainPassword, byte[] salt)
{
byte[] passwordBytes = GetBytes(plainPassword);
// Merge the password bytes and the salt bytes
var mergedBytes = new byte[passwordBytes.Length + salt.Length];
Array.Copy(passwordBytes, mergedBytes, passwordBytes.Length);
Array.Copy(salt, 0, mergedBytes, passwordBytes.Length, salt.Length);
// Now hash password + salt
byte[] hash;
using (var sha = SHA256.Create()) {
hash = sha.ComputeHash(mergedBytes);
}
return Base64Encode(hash);
}
You will also need this:
public static string Base64Encode(byte[] bytes)
{
return System.Convert.ToBase64String(bytes);
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
Create random salt bytes for each password and store the salt as a separate piece of information together with the hashed password. Like this, every password gets a different salt. This makes Pre-computed dictionary attack/Rainbow table attack infeasible. The salt does not need to be encrypted. You probably will want to store it as base 64 string as well. To get the salt bytes again you will need Convert.FromBase64String().

Encrypt a file with Rijndael algorithm

I found this code in a website
private void EncryptFile(string inputFile)
{
string password = #"myKey123"; // Your Key Here
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(password);
string cryptFile = inputFile + ".enc";
FileStream fsCrypt = new FileStream(cryptFile, FileMode.Create);
RijndaelManaged RMCrypto = new RijndaelManaged();
CryptoStream cs = new CryptoStream(fsCrypt,
RMCrypto.CreateEncryptor(key, key),
CryptoStreamMode.Write);
FileStream fsIn = new FileStream(inputFile, FileMode.Open);
int data;
while ((data = fsIn.ReadByte()) != -1)
cs.WriteByte((byte)data);
fsIn.Close();
cs.Close();
fsCrypt.Close();
}
I have two problems with it. First one is the password part. I have a function which generates random strings:
public string CreatePassword(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890*!=?&/";
StringBuilder res = new StringBuilder();
Random rnd = new Random();
while (0 < length--){
res.Append(valid[rnd.Next(valid.Length)]);
}
return res.ToString();
}
When I edit the code like this:
string password = CreatePassword(8);
It works. But when I increase the password size (like 10) I get this error:
An unhandled exception of type 'System.Security.Cryptography.CryptographicException' occurred in mscorlib.dll
Is there way to increase password lenght? Or can we consider it safe with 8 lenght?
Other question:
my output file is inputFile + ".enc" When I delete ".enc" Part I got "this file using by another process" error. How can write encrypted one to original one?
RijndaelManaged has rules. Below command used for preparing algorithm:
RMCrypto.CreateEncryptor(key, key)
First param is secret key and it must be 128, 192, or 256 bits. Second param is IV. In given example, key and IV used as same. Password text convert to byte with unicode so it is length 16 byte = 128 bit. So if you use different size then rule you get error.
You can check below article much better:
Encrypting & Decrypting a String in C#

C# & Lua MD5 Hashing

I am having some issues trying to match an MD5 encryption with salt from Lua to C#. Meaning, I have it hashing and salting the account password in Lua, but I need to match that exact same encryption in C# as I am developing a website in C# that needs to use the same database and accounts as the Lua script.
I've tried for quite some time now trying to match them, but no matter what I do I can't seem to get it right.
Lua hash:
if (string.len(cpypassword) ~= 64) then
password = md5(Newsalt .. password)
local result = mysql:query("SELECT username FROM accounts WHERE username='" .. username .. "'")
if (mysql:num_rows(result)>0) then
local insertid = mysql:query_insert_free("UPDATE accounts SET password='" .. mysql:escape_string(password) .. "' WHERE username='".. mysql:escape_string(username) .."'")
triggerClientEvent(client, "accounts:login:attempt", client, 1, "Password changed!\nThank you." )
end
end
I've tried a variety of different ways to do MD5 hash in C#, but none of them matches, so here I am now, asking you for suggestions.
Thank you in advance.
EDIT:
Lua function generates this as an example:
CFA62AA942A84781B1C101D6D583B641
Same example generated in C# with the C# hashing:
DSqwG/W1LNbHsCEkHNAUpg==
C# code (just one of the things I tried, I found much simpler ones, but this is the latest one I tried, just copied out of a tutorial)
public class Encryption
{
public static string EncryptorDecrypt(string securityCode, string key, bool encrypt)
{
byte[] toEncryptorDecryptArray;
ICryptoTransform cTransform;
// Transform the specified region of bytes array to resultArray
MD5CryptoServiceProvider md5Hasing = new MD5CryptoServiceProvider();
byte[] keyArrays = md5Hasing.ComputeHash(Encoding.UTF8.GetBytes(securityCode));
md5Hasing.Clear();
TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider() { Key = keyArrays, Mode = CipherMode.ECB, Padding = PaddingMode.PKCS7 };
if (encrypt == true)
{
toEncryptorDecryptArray = Encoding.UTF8.GetBytes(key);
cTransform = tdes.CreateEncryptor();
}
else
{
toEncryptorDecryptArray = Convert.FromBase64String(key.Replace(' ', '+'));
cTransform = tdes.CreateDecryptor();
}
byte[] resultsArray = cTransform.TransformFinalBlock(toEncryptorDecryptArray, 0, toEncryptorDecryptArray.Length);
tdes.Clear();
if (encrypt)
{ //if encrypt we need to return encrypted string
return Convert.ToBase64String(resultsArray, 0, resultsArray.Length);
}
//else we need to return decrypted string
return Encoding.UTF8.GetString(resultsArray);
}
}
The code you provided for C# is not generating an MD5 hash; instead it is hashing the securityCode and using it as a key for TripleDES.
Take a look at this blog post (copied relevant bits out):
public string 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);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
return sb.ToString();
}

md5 hash confusion

My company uses the following algorithm to hash passwords before store it in the database:
public static string Hash(string value)
{
byte[] valueBytes = new byte[value.Length * 2];
Encoder encoder = Encoding.Unicode.GetEncoder();
encoder.GetBytes(value.ToCharArray(), 0, value.Length, valueBytes, 0, true);
MD5 md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(valueBytes);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
stringBuilder.Append(hashBytes[i].ToString("x2"));
}
return stringBuilder.ToString();
}
To me it sounds like a trivial md5 hash, but when I tried to match a password (123456) the algorithm gives me ce0bfd15059b68d67688884d7a3d3e8c, and when I use a standard md5 hash it gives me e10adc3949ba59abbe56e057f20f883e.
A iOS version of the site is being build, and the users needs to login, the password will be hashed before sent. I told the iOS team to use a standard md5 hash, but of course it don't worked out.
I can't unhash the password and hash it again using the standard md5 (of course), and I don't know what exactly tell to the iOS team, in order to get the same hash.
Any help?
You need to use the same encoding on both ends (probably UTF8).
If you replace your code with
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes("123456"));
, you'll get e10adc3949ba59abbe56e057f20f883e.
You need to use UTF8 instead of Unicode. The following code works exactly like the PHP md5() function:
public static string md5(string value)
{
byte[] encoded = ASCIIEncoding.UTF8.GetBytes(value);
MD5CryptoServiceProvider md5Provider = new MD5CryptoServiceProvider();
byte[] hashCode = md5Provider.ComputeHash(encoded);
string ret = "";
foreach (byte a in hashCode)
ret += String.Format("{0:x2}", a);
return ret;
}

Categories

Resources