Is it possible to "calculate" a valid password string when the Key and the IV (as strings) for a RijndaelManaged-Key are known?
No it should not be possible. It depends which key derivation function
you use, but usually password and salt are repeatably hashed with MD5 or SHA1 so virtually impossible.
Related
RijndaelManaged is an algorithm while AES is the standard. When referring to AES256, does that mean the key length I'm using with RijndaelManaged must be 256 characters?
If I have a key like this:
key = "mytestkey";
which is only 9 characters, does that mean I'm using AES9?
Aes/Rijndael key sizes are in bits, not characters; AES256 uses a 256-bit key. You must give it a key that is exactly 256 bits. The AES standard and Rijndael only accept key sizes that are either 128, 192, or 256 bits.
You should not interchange AES and Rijndael. The AES standard is derived from Rijndael, but they are not exactly the same. If you wish to use AES, use AES for all operations; if you wish to use Rijndael, use Rijndael for all operations.
"mytestkey" cannot directly be a key to AES256 nor a similar Rijndael mode; it is not 256 bits long. In order to use it as a key, you'll have to transform it into a block of bytes that is 256 bits long.
If you're working with passwords, one typical means to do this is with key stretching, using hash algorithms such as PBKDF2 or Scrypt. PBKDF stands for "Password-based key derivation function", which is basically exactly what you're doing - deriving a key from a password.
Theoretically you could also just hash the password with SHA256 (which always has a 256-bit output) and use that 256-bit block as the key to AES; doing so is unwise from a security standpoint because it is relatively easy to precompute SHA hashes of passwords.
Please keep in mind that if you use a password that has very little entropy, then the security of your encryption suffers - the time it'll take for someone to guess the key could be short. "mytestkey" has at most ~42 bits of entropy - you're only using lower case letters, so 26 values per place, and there are 9 places (9 characters). Thus the number of bits theoretically needed to stores this is log_2( 26^9 ) = 42.3. In this circumstance, you'd be using AES256 with a key that has only ~42 bits of entropy.
I should note that the advice given here is an incomplete treatment of how to turn passwords into keys, from a security perspective. If you want to better understand how to properly generate keys from passwords, I suggest you start with some reading such as the Password Storage Cheat Sheet at owasp.org.
I'm writing an encryption sequence for sensitive data in our database.
Currently I'm taking a GUID based on the UserId, and putting that through a hash. Then, I run the hash through a Rfc2898DeriveBytes to get Key and IV which I use to encrypt the data using the Rijndael function.
My code looks like this:
var salt = new byte[] { 1, 2, 23, 234, 37, 48, 134, 63, 248, 4 };
const int iterations = 1000;
using (var rfc2898DeriveBytes = new Rfc2898DeriveBytes(GenerateHash("2525"), salt, iterations)) {
_key = rfc2898DeriveBytes.GetBytes(32);
_iv = rfc2898DeriveBytes.GetBytes(16);
}
I then pass the _key and _iv along to decrypt or encrypt the data.
My goal is to have each user always have access to their unique key through every session. That being said, what can be randomized and still maintain this function? Do I always have to use the same salt and the same IV to get the data I want?
Rfc2898DeriveBytes is an implementation of PBKDF2. Obviously RFC 2898 is a reference to the standard where this Password Based Key Derivation Function has been defined. Note that the standard is broader than just the KDF; it's full title is "PKCS #5: Password-Based Cryptography Specification, Version 2.0".
PBKDF2 is a successor of PKCS#5 v1 which defined PBKDF / PBKDF1. The 1 was only added after PBKDF2 came into being. The class PasswordDeriveBytes is an implementation of PBKDF1. It should not be used anymore because both the KDF is outdated but also because Microsoft screwed up the implementation severely; it may repeat output keying material if more than the output of the underlying hash - SHA-1 so 20 bytes - is requested.
Besides being used as KDF, PBKDF2 can also be used as password hashing function, where the hash instead of the password is stored in a database. That way passwords can be verified, while the password cannot easily be retrieved even if the hash data is retrieved by an adversary. This is described in the followup RFC 8018 which contains the 2.1 version of the protocol.
Internally, PBKDF2 is just a repetition of a hash function over the password and salt. The iteration count is the work factor; it specifies how much work you (and adversaries) have to do before one hash is calculated. The salt makes sure that rainbow table attacks are impossible, and that identical passwords (of different users) don't lead to the same hash.
Due to a design error which requires the full amount of work to be repeated if more than one hash output is required, it is not recommended to request more data from it than the output of the hash function. In that case it is better to use another method to expand the output keying material (bytes), e.g. HKDF-Expand.
Observations on the code in the question:
The GenerateHash method is spurious, Rfc2898DeriveBytes will do this for you;
You should use something less predictable than a UID to create a key; the data should not be directly available to an attacker as this would completely defeat the purpose of PBKDF2;
If you want to use the same set of UID + salt + iterations for multiple encryption operations, then you should generate a random IV and prepend it to the ciphertext, having a non-random IV completely defeats the purpose of the IV;
You can change the salt to get multiple keys, but you would have to go through the PBKDF2 function for each and every encryption.
Just a general hint, only use the resulting key to encrypt data specific keys created out of a secure random function. Then you don't even need to bother about an IV, and you may be able to "re-encrypt" by decrypting the data specific key, and encrypting that with a new key.
Hi i am using the MD5 encyrption in my asp.net website where it stores the passwords to the database using the MD5 encryption.so when i want to login using the credentials entered during the registration of the user i am having trouble comparing the existing password from the database to the current one which i entered to login.As the stored password is in the ecrypted form i am confused how to compare the encrypted format to the text format ?
I am using the Sqlserver as my database.
In addition to what #Jason said... I like salting the password.
public static string CreateSalt(int byteSize)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[byteSize];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
public static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd = FormsAuthentication.HashPasswordForStoringInConfigFile(saltAndPwd, "sha1");
return hashedPwd;
}
when the user is intially created, here is the process
Create the salt => CreateSalt(16)
Create the hash with the password and salt => CreatePasswordHash(passwordEntered, salt)
Store the hashed password and salt
next time the user logs in, validate the stored credentials against what they have entered into the login form
=> string enteredPasswordHash = CreatePasswordHash(enteredPassword, saltFromDatabase)
the compare against what is in the database
=> if(passwordHashInDatabase != enteredPasswordHash) => wrong login credentials
Hope this helps someone...
MD5 is a one way hash, so the password in the database cannot be converted back to plain text. Instead you have to convert the plain text password (the one entered in the login form) to cypher text using the MD5 hash algorithm.
To compare the MD5 hashes you would need to query the database based on the User Name enter in the login and return the known MD5 hash and the salt (if there is one). Then hash the given password with the known salt. You can then compare the two hashes for a match.
If you are definitely storing the password in an encrypted state, then you only need to encrypt their plaintext password (using the same key) and compare it to the database value. Apples to apples. When encrypted using the same key and algorithm, it will always encrypt and decrypt to the same value.
If this doesn't appear to be working correctly, I would guess that you are not using the same key that you used when you first stored the value in the database. Double-check and make sure that the key you encrypt with is exactly the same as the key you decrypt with. Typically, many of us will use a machine or user-level certificate as a key, to ensure that the value isn't tampered with or changed.
If (instead) you are using MD5 to hash the password, then it's not actually encrypted. Hashing totally munges the plaintext value and you will never get it back. It's the safest and smartest way to store passwords. You merely hash the plaintext into an encoded value and save it to the database -- then, you compare against that hashed value any time the user logs in.
I'm hoping you are hashing and not encrypting. It's definitely a best practice when it comes to password storage. It's very easy to implement and will save you headaches if you're ever audited.
Good luck!
I want to save userid and password in a MySql database for my WinForms project. One of my friends told me that this is not secure; I should encrypt and save that. I don't know about encryption.
How can I do this?
Usually passwords are not stored in database at all. Instead hash of the password is stored. You can take a look at SHA156 class for example.
There are plenty articles in the web on how to hash passwords.
For example Storing Passwords - done right!
Note that your friend is telling you to encrypt it, which is different from storing a hash (computed using a cryptographic hash function) in the table.
If you encrypt and store it, you will be able to retrieve the password if you have the key.
If you store a secure hash of a password, you can tell if a string is the same as the password or not by hashing the string and comparing the hash in the table.
I did a search and found this answer from another SO question which explains in greater detail why you should be using a hash (of a secure variety) as opposed to encrypting the password.
Last but not least, whether encrypting or secure hashing, be sure to use a publicly tested libraries and not to "roll your own".
When using encypion one needs to choose an algorithum (method of encryption) for the data. When storing user credentials one generally creates and stores a hash of the information rather than encrypting it. The advantage of using a hash over encryption is that a hash is non-reversible, so the original data can not be recovered.
The process for creating a hash is:
Create a salt value (explained below)
Append the salt value to the password
Hash this string
Store the salt value and the hash value in the database
Then when you want to validate the credentials later:
Take the password value entered by the user and append the salt to it
Hash the string from step 1
Compare it with the password stored in the database. If the stored hash and the hash from step 2 match, the user has entered the correct password, otherwise the password is incorrect
Hashes and Salts
A salt value is a value unique to each user that gets appended to sensitive values such as user names and passwords before they are stored. The reason salts are used with hashes is to make it more difficult to generate lists of hashed values used in brute force attacks against the database.
Code Samples
Generating a Salt & Hash
private void EncryptPassword(string userPassword)
{
//Performs hashing using SHA256 algorithum
SHA256Managed hash = new SHA256Managed();
RNGCryptoServiceProvider random = new RNGCryptoServiceProvider();
byte[] saltBytes = new byte[32]; // 32 bytes = 256-bit salt.
//Fill saltBytes with cryptographically strong random values.
random.GetBytes(saltBytes);
//Get a byte representation of the password because the hash function
//works with byte arrays.
byte[] passwordBytes = Encoding.UTF8.GetBytes(userPassword);
byte[] hashInput = new byte[passwordBytes.Length + saltBytes.Length];
//Append the contents of the passwordBytes and hashBytes arrays to create
//the input to the hash function (value to be hashed)
passwordBytes.CopyTo(hashInput, 0);
saltBytes.CopyTo(hashInput, passwordBytes.Length);
//Compute (generate) a hashed representation of the input value.
byte[] hashValue = hash.ComputeHash(hashInput);
//Hashes are often stored as strings in databases.
//Hashes should be stored using Base64 encoding.
string hashString = Convert.ToBase64String(hashValue);
string saltString = Convert.ToBase64String(saltBytes);
//store hashString and saltString in database.
}
Authenticating a User
private bool AuthenticateUser(string userName, string password)
{
SHA256 hash = new SHA256Managed();
//Convert hash and salts from Base64/
byte[] storedHash = Convert.FromBase64String("Hash Value from the database");
byte[] storedSalt = Convert.FromBase64String("Salt from Database");
//Append salt to user password and hash the result
byte[] attemptedPasswordBytes = Encoding.UTF8.GetBytes(password);
byte[] hashInput = new byte[attemptedPasswordBytes.Length + storedSalt.Length];
attemptedPasswordBytes.CopyTo(hashInput, 0);
storedSalt.CopyTo(hashInput, attemptedPasswordBytes.Length);
byte[] attemptedHash = hash.ComputeHash(hashInput);
//Check whether the password entered by the user matches the stored hash.
return attemptedHash == storedHash;
}
well a very simple solution is to use varbinary datatype which will store password in binary format and unreadable for other ..
If you want more security then you need to use encrytion provided my sql server itself like 128bit encryption for that u need to create asyymetric key then encrypt it with that
You could encrypt the username and password using fronthand that is C# and store that value in the database. On retrieval you have to decrypt it for matching. Have a look at this link.
When I use C# to implement the AES symmetric encryption cipher, I noticed:
PasswordDeriveBytes derivedPassword = new PasswordDeriveBytes(password, saltBytesArray, hashAlgorithmName, numPasswordIterations);
Why do I need to use a hashing algorithm for AES encryption? Aren't they separate? Or is the hashing algorithm only used to create a secure key?
The AES algorithm doesn't use a hashing algorithm internally does it?
PasswordDeriveBytes isn't part of AES. It implements an algorithm to derive encryption keys from a password. The algorithm involves the usage of a hash algorithm.
PasswordDeriveBytes is used to derived a symmetric key as well as the IV you are going to use for encryption/decryption. The PasswordDeriveBytes would take an passkey (password in your case), append the salt (saltBytesArray in your case) and hash it (with the algorithm you provided, e.g. SHA or MD5) 'n' many times (numPasswordIterations in your case) and give you the resulatant byte array.
This method is only used to derive the key, this has got nothing to do with encryption decryption per say.