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.
Related
I use AES to creature HMAC signatures for API calls and while I understand what nonces are and why they're important, I'm a little confused on where exactly they're meant to be implemented.
I had the idea of using the nonce to alter a client's secret key to generate a new single-use key to sign calls that could otherwise be easily exploited with replay attacks.
The basic premise is the User, who gets a secret key when they log in, calls a setup API procedure which creates and returns a transactionID and a new nonce. The user then combines their own secret key and the nonce to sign the TransactionID and a few other things. The server then tries to match this signature using the currently active nonce for that user.
The server automatically clears old nonces and overwrites them when new setup calls are made so the user must always follow this paired sequence (you can't just reuse the second call, since the old nonce will have been deleted and the server will no longer accept this signature).
If this is the valid way to use nonces, how do I combine them with the client's keys to get a valid Secret key?
I generate AES providers this way:
private static AesCryptoServiceProvider GetProvider(byte[] key, byte[] IV)
{
AesCryptoServiceProvider result = new AesCryptoServiceProvider();
result.BlockSize = 128;
result.KeySize = 256;
result.Mode = CipherMode.CBC;
result.Padding = PaddingMode.PKCS7;
result.IV = IV;
result.Key = key;
return result;
}
I use AES-256 so my keys are always 32 Bytes long. But if I want to create a new key using a nonce, I can't simply concatenate them since the resulting string would no longer be 32 bytes.
Should I concatenate and then use a fixed-length hash function to get the result back into a 32-byte length? Or is there an AESCryptoServiceProvider constructor/method that automatically handles nonces I'm missing?
Or am I just supposed to append nonces in plaintext into the signature and let the server read them separately and check them directly?
There are many ways to solve this. The easiest would be to use hashing. You can use HMAC or even HKDF.
SessionKey = HMAC_SHA256(SecretKey, Nonce)
Be sure to use the user's SecretKey only for deriving other keys. If you want to use this derivation for different things, then you need to bind the uses into the key:
SessionKey = HMAC_SHA256(SecretKey, "Encryption".Concat(Nonce))
SessionToken = HMAC_SHA256(SecretKey, "Token".Concat(Nonce))
This is just pseudo-code. Here are some examples of actual HMAC in C#.
I'm trying to implement SHA256-RSA digital signatures and I'm confused with the terminology and implementation in C#.
AFAIK, "signing a file" is to generate the hash of a file, and then encrypt that hash. I've also heard the phrase "signing the hash". Is this the same thing? Or is this hashing a hash and then encrypting hash'?
Here's the code in question:
public void SignatureTest(byte[] data, X509Certificate2 cert)
{
var sha256 = new SHA256CryptoServiceProvider();
var rsa = (RSACryptoServiceProvider)cert.PrivateKey;
var hashOfData = sha256.ComputeHash(data);
var encryptedHash = rsa.Encrypt(hashOfData, false);
var encryptedHashOAEP = rsa.Encrypt(hashOfData, true);
var signedHash = rsa.SignHash(hashOfData, "SHA256");
//Shouldn't one of these be true?
var false1 = CompareAsBase64Str(encryptedHash, signedHash);
var false2 = CompareAsBase64Str(encryptedHashOAEP, signedHash);
//This is the one that actually matches
var true1 = CompareAsBase64Str(signedHash, rsa.SignData(data, sha256));
}
public bool CompareAsBase64Str(byte[] b1, byte[] b2)
{
return (Convert.ToBase64String(b1) == Convert.ToBase64String(b2));
}
Here's what MSDN says on RSACryptoServiceProvider:
SignHash() Computes the signature for the specified hash value by encrypting it with the private key.
Encrypt() Encrypts data with the RSA algorithm.
Shouldnt SignHash(hash) and Encrypt(hash) be the same?
You need to separate concerns, this will help you understand the terminology.
Any arbitrary blob of data can be hashed and/or encrypted in any combination.
Hash means: use a cryptographic algorithm to generate a value that is irreversible (that is, simply by knowing algorithm and hash you are unable to reconstitute original data) and consistent (that is, given the same data and algorithm, the value of the hash produced is always the same).
Encrypt means: use a cryptographic algorithm to encipher data (altogether or in blocks) with a given key (a key can be symmetric or asymmetric).
Sign means: Hash the data and Encrypt the hash with a given key. Then, given the pair (for asymmetric) or same (for symmetric) key, a consumer can validate that:
hash is matching, that means the data has not been altered in transit
hash did come from the source that at least has the pair key (for asymmetric) or same key (for symmetric)
The answer given by zaitsman is a good explanation of the topics related to your questions and I think should be the accepted answer, but just to help tie it back to your specific question of why encrypting the hash doesn't give you the same result as signing the hash (the rsa.SignHash(hashOfData, "SHA256") in your code):
Signing a hash doesn't just encrypt the hash data -- it also encrypts the name (or some identifier) of the hashing algorithm used to generate the hash along with it. Without that, the receiver wouldn't know what algorithm to use when computing their own hash (of the message being sent) to compare with the one they just decrypted in order to verify the authenticity of the message (which, of course, is the whole point).
When you encrypted the hash yourself (with rsa.Encrypt(hashOfData, false) and rsa.Encrypt(hashOfData, true)), you only encrypted the hash data and not the combination of hash data and algorithm identifier ("SHA256" in your code). In other words, you encrypted different data, so you got different (encrypted) results.
The reason the return value of that SignHash call does match the value returned by rsa.SignData(data, sha256) is that the latter method does the same thing, except it does the hashing and hash signing as one operation, so you don't have to compute the hash as a separate step if you don't need it for any purpose other than signing it.
From RSACryptoServiceProvider.SignData Method on MSDN:
Computes the hash value of the specified data and signs it.
Also see: Why does SignHash need to know what hash algorithm was used?
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.
This question already has an answer here:
Vb.net Decrypt sha512 hash
(1 answer)
Closed 8 years ago.
I encrypt the password by following code
HashAlgorithm hashAlgorithm = null;
hashAlgorithm = new SHA512CryptoServiceProvider();
try
{
byte[] byteValue = Encoding.UTF8.GetBytes(source);
byte[] hashValue = hashAlgorithm.ComputeHash(byteValue);
StringBuilder sb = new StringBuilder();
for (int i = 0; i <= hashValue.Length - 1; i++)
{
sb.AppendFormat("{0:x2}", hashValue[i]);
}
return Convert.ToString(sb);
}
catch
{
throw;
}
after that I saved it in database.
now I want to retrieve actual password by decrypting it. please help me
You hash a password and you don't encrypt it. That being said you cannot decrypt it.
Taken from here
Encryption transforms data into another format in such a way that only
specific individual(s) can reverse the transformation. It uses a key,
which is kept secret, in conjunction with the plaintext and the
algorithm, in order to perform the encryption operation. As such, the
ciphertext, algorithm, and key are all required to return to the
plaintext.
while
Hashing serves the purpose of ensuring integrity, i.e. making it so
that if something is changed you can know that it’s changed.
Technically, hashing takes arbitrary input and produce a fixed-length
string that has the following attributes:
The same input will always produce the same output.
Multiple disparate inputs should not produce the same output.
It should not be possible to go from the output to the input.
Any modification of a given input should result in drastic change to the hash.
Hashing is used in
conjunction with authentication to produce strong evidence that a
given message has not been modified. This is accomplished by taking a
given input, encrypting it with a given key, hashing it, and then
encrypting the key with with the recipient’s public key and signing
the hash with the sender’s private key.
then what can I use with which I can convert output to input?
You should decrypt your data and not hash them. Encrypting and Decrypting data is a big subject. A good starting point is to read this. Generally, you have two types of encryoption, symmetric and assymmetric. So initially, read about them and then choose the one you think is suits your needs. Then try to implement it. You will make use of algorithms that are already implemented in .NET and can be used instantiating objects of the corresponding classes and calling specific methods.
However, I have to make a note here. Usually, we hash the passwords and we don't encrypt them. This is more secure. Taken from here:
Though hashing and encryption both provide valuable capabilities, for
the vast majority of situations, there is only one right option for
storing user passwords for an online application: hashing. This is a
one-way function in which a hashed value cannot be reversed to obtain
the original input value (i.e., the password). Symmetric encryption is
based on the use of an encryption key and is a reversible operation.
Anyone possessing the key can decrypt an encrypted value to obtain the
original value.
I want to use encryption algorithm available in .Net Security namespace, however I am trying to understand how to generate the key, for example AES algorithm needs 256 bits, that 16 bytes key, and some initialization vector, which is also few bytes.
Can I use any combination of values in my Key and IV? e.g. all zeros in Key and IV are valid or not? I know the detail of algorithm which does lots of xors, so zero wont serve any good, but are there any restrictions by these algorithms?
Or Do I have to generate the key using some program and save it permanently somewhere?
I want to store data in database after encryption, the secure profile data like username, password, phone number etc, and the key will be available to database user mentioned in connection string only, and to the administrator.
You really ought to do this the correct way :)
1) Use a securely generated random IV
2) Use a securely generated random key
3) Don't use ECB mode - EVER
AesManaged aes = new AesManaged();
aes.GenerateKey();
aes.GenerateIV();
The code above will correctly and securely generate a random IV and random key for you.
Sounds like you need to read into the Rfc2898DeriveBytes class.
Rfc2898DeriveBytes.GetBytes();
It has a method(above) that allows you to tailor the size of byte arrays that are fed into the .Key and .IV properties on a symmetric encryption algorithm, simply by feeding an int value. The MS official 70-536 book suggests doing this pro-grammatically by dividing the KeySize property / 8.
I.e TripleDes or AESManaged. Whatever you use, the algorithm itself will have some pre-reqs that will need meeting first. I.e satisfying the key size conditions. The RunTime will automatically fill the properties and fields and etc the best and most strongest values for you. But the IV and Key needs to come from you. This how you can do the following:
RijndaelManaged myAlg = new RiRijndaelManaged();
byte[] salt = Encoding.ASCII.GetBytes("Some salt value");
Rfc2898DeriveBytes key = new Rfc2898DeriveBytes("some password", salt);
myAlg.Key = key.GetBytes( myAlg.KeySize / 8);
myAlg.IV = key.GetBytes( myAlg.BlockSize / 8);
// myAld should now fully set-up.
Above you can see what I mean by doing it pro-grammatically, as it should pretty much
do it all for you, without you even really having to bat an eye-lid as to meeting it's pre-reqs.
The Microsoft 70-536 book states that the .Key properties expect the byte arrays you supply
to them in bytes and not bits. The RFC class works in bytes where as an algorithms KeySize property works in bits. 1 byte = 8 bits. Can you see where this is going ... ?
This should give you an idea as to why the above sample peice of code is done the way it is! I studied it and it makes pretty darn good sense to me!
The above answer should allow you to create your algorithm object with supplied password and a static salt value that can be hard code at both ends. Only thing you need to do is worry about how you going to make sure that the byte arrays stored at .Key and .IV are safely transported to a recipient so that can successfully decrypt the message you encrypted. By safely reconstructing the same algorithm object.
OBTW:
AESManaged has a keysize req': 128Bits = 16 Bytes !!!
(8*8 = 64, 64Bit / 8bits per Byte = 8 Bytes) Therefore
64*2 = 128Bit, 8*2, ==> 16bytes key size !
256Bit = 32Bytes !!!!
According to the 70-536 official training kit book, Aes is limited to having keysize of 128bits in size. 256bits,192 and 128 key size for example can be used with the Rijndael class.
You could on the other hand completely forget all that crap and simply use .GenerateKey and GenerateIV methods instead to save you all the hassle of sorting out a pre-shared and agreed password and static salt values. Your only concern is figuring out a way of storing and retrieving the key and IV byte arrays. Binary Formatter? .
If you are using encryption to exchange data then you will need a key exchange protocol, but you don't make one yourself instead use one off-the-shelf like TLS or SSL.
If you use encryption to store data then you generate the IV using CryptGenRandom (or its .net equivalent RandomNumberGenerator.GetBytes) and save it along the document (in clear, no need to protect the IV). You never write down the key, the key is provided by the user. Usualy you derive the key from a password phrase using CryptDeriveKey, or its .Net equivalent PasswordDeriveKey.CryptDeriveKey.
Update
To store a secret in the database that is available only to the user and an administrator you need to use 3 keys:
one to encrypt the data with (call it the DK key)
one user key to encrypt the DK key (call it UK)
one administrator key to encrypt the DK key (call it AK)
In theory you encrypt the data with DK and then encrypt the DK with UK and save it, and encrypt the DK with AK and save it. This way the user can use again the UK to decrypt the DK and then decrypt the data, and the administrator can use the AK to decrypt the DK and then decrypt the data. The big problem is the fact that the system is always automated, so the system needs access to the administrator's key which means is not truly a persnal key of the administrator, but instead is a system key (it cannot be used for purposes of non-repudiation for instance).
As a heads up, knowledge of what IV is or how to use AES from C# and how cryptography algorithm work will get you exactly 0 (zero) traction in solving this kind of problems. The issue is never what IV and key to use, the issue is always key provisioning. For actual crypto operations, just use the built-in support from the database, see Cryptography in SQL Server. I can easily argue that the only facility you need is TDE (Transparent Data Encryption) to protect against accidental loss of media.
Generate a random letters / hex code in a specific length.
This function (taken from here) return a random key in a specific length:
private static string CreateSalt(int size)
{
//Generate a cryptographic random number.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
// Return a Base64 string representation of the random number.
return Convert.ToBase64String(buff);
}
Use System.Security.Cryptography.RandomNumberGenerator to generate random bytes:
var rnd = new System.Security.Cryptography.RandomNumberGenerator.Create();
var key = new byte[50];
rnd.GetBytes(key);
It really depends on what you ned to do with the key.
If the key is to be generated by the computer (and can be any random value) I generally take a SHA256 of a couple GUIDs. This is about as random as you're going to get without a hardware random number generator.
You can use keys with all 0s but obviously it won't be very secure.