I am looking to encrypt data. I want to generate encryption keys based on a password, and some moving value, like time. The goal is to have the key change, but have anyone that knows the password be able to decrypt. This is happening in C#. I am using the following code to hash the password.
private static string GetPasswordHash(string password)
{
TimeSpan span = (DateTime.UtcNow - new DateTime(1900, 1, 1));
string result = Convert.ToInt32(span.TotalHours).ToString();
result += password;
result += Convert.ToInt32(span.TotalDays).ToString();
result = Convert.ToBase64String(SHA256.Create().ComputeHash(Encoding.ASCII.GetBytes(result)));
return result;
}
I then use that hash, plus a salt to generate a key.
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(GetPasswordHash(password), salt);
rdb.IterationCount = 1000;
RijndaelManaged rm = new RijndaelManaged();
rm.KeySize = 256;
rm.Key = rdb.GetBytes(32);
rm.IV = rdb.GetBytes(16);
There seem to be issues with the way I am doing this. Some of the computers are in different timezones, or if the hour ticks as I send the data, or if the machines times are slightly off. Are there better suggestions?
The standard strategy is to just send the value (time, etc.) just be sent with the encryption key. Since the value you are using is public knowledge, it is fine if whoever first creates the password provides the "moving value" publicly. See Salt. What you are doing is not a new technique. You also seem to be using Key Strengthening.
You might just send the changing part (unencrypted) along with the encrypted data, so that anyone who knows the secret password can easily reconstruct the password used for encryption. Since the changing part is relatively easy to guess, it wouldn't make it much less secure.
You could find a scheme that generates the same moving value over a window of time, centered on the current time. Thus, if you choose a window of 12 hours, all computers 6 hours behind and 6 hours ahead of yours would generate the same encryption key.
Are you worried that a file with the same data encrypted with the same password looks the same?
You could use set the initialisation vector with the current time, and encrypt using your password.
To decrypt, you use the same IV value (so this has to be stored unencrypted with your file somewhere).
Password based key derivation is already implemented in .net. While I can't see anything wrong with your function GetPasswordHash() its always worth using library functions in crypto as they'll likely be better tested and small errors can completely destroy the security of a system. Here're two links, there are probably others too:
rfc2898derivebytes
passwordderivebytes
Related
I'd like to know if there is a standard code to generate a SHA256 hash using a key. I've come across several types of code, however, they don't generate the same output.
Code found at JokeCamp
private string CreateToken(string message, string secret)
{
secret = secret ?? "";
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return Convert.ToBase64String(hashmessage);
}
}
Here's another one that I found
private static string ComputeHash(string apiKey, string message)
{
var key = Encoding.UTF8.GetBytes(apiKey);
string hashString;
using (var hmac = new HMACSHA256(key))
{
var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(message));
hashString = Convert.ToBase64String(hash);
}
return hashString;
}
The code generated by both of these are different to what is generated by http://www.freeformatter.com/hmac-generator.html#ad-output
I'll be using the SHA256 for one of our external API's where consumers would hash the data and send it to us. So we just want to make sure we use a standard approach so that they send us the correct hash. Also, I would like to know if there are any well-known nugets for this. I've also tried to find a solution with Bouncy Castle, however, I couldn't find one that uses a key to hash.
The difference is because of the character encodings (ASCII vs UTF-8 in your examples). Note that the hashing algorithm takes an array of bytes, and you do the conversion from a string to that byte-array beforehand.
Your question "whats the standard code" probably hasnt an answer, id say that if you expect the input to contain content from just the ASCII character-space, go for that, if not go for UTF-8. Either way - communicate it to your users
If you want to look at it from a usability perspective and make it the optimal for your users - go for both. Hash the content both ways and check agains the users incoming hash, but it all depends on your evaluation on clock-cycles vs security vs usability (you can have two)
They are almost equivalent.
The difference is how the encoding for the string is established.
In the first portion of code it assumes ASCII, whereas in the second portion it assumes UTF-8. It is possible that the string used another encoding which is none of those.
But regardless of that, the idea is to understand what is the goal of this operation. The truly relevant things in this context are:
Given equal input, output should be the same
There should be no way to retrieve the plaintext only by knowing the output (within a reasonable amount of time)
After hashing, you no longer require the original input in plaintext.
A secure cryptographic hashing function (meaning not older functions like MD5) achieves that.
Then, if your data store where hashes are stored is compromised, the attacker would only have a hash which cannot be used to retrieved the original plaintext. This is why hashing is used rather than encryption, encryption is a reversible operation (through decryption).
Then, within the system, if you've made the decision to use one encoding, you need to keep that decision consistent across all components in your system so they can interoperate.
is possible decrypt this type of password generated by Meteor application.
My idea is to use the same credentials (email and password) for my application in C #
As noted in other answers, you cannot decrypt the passwords, but you can very well use the Meteor database to authenticate in a different system.
This is how to do it:
In your other system, first find libraries that provide SHA256 and bcrypt implementations.
Then take the password as entered by the user, and first compute a SHA256 digest hash from it.
Then feed this hash string to bcrypt using number of rounds = 10 (This is the Meteor default).
Now compare the result from bcrypt with the services.password.bcrypt from the MongoDB database of Meteor. If they match, the user provided the correct password.
For reference, the Meteor implementation is here. It is quite simple and well commented.
The very purpose of hashing and encrypting your password is to make decrypting them unpractical.
However, you can reuse the bcrypt(hash(password)) from your meteor app and check against it in another application, provided you use the same scheme.
Is that a bcrypt hash? It depends on the size of the key as Blowfish as a variable sized key. If it's 32 bits. Sure, you could do it with some serious computing power and a few hours. It it is a 128bit key, you'd be long long dead (and so would the universe as we know it) before it every finishes brute forcing. Blowfish does have a minor vulnerability for weak keys though. I would rethink your implementation.
I encountered a similar use case where I was writing a C# application that would validate users created through a Meteor.js application. The code I got to work was this (using System.Security.Cryptography and BCrypt.Net-Next):
string sha256_hash(string value) {
StringBuilder stringBuilder = new StringBuilder();
using (SHA256 hash = SHA256.Create()) {
Encoding enc = Encoding.UTF8;
Byte[] resultingHash = hash.ComputeHash(enc.GetBytes(value));
foreach (Byte b in resultingHash) {
stringBuilder.Append(b.ToString("x2"));
}
}
return stringBuilder.ToString();
}
// First compute SHA256 hash
string sha256hash = sha256_hash("my_password");
// Let BCrypt.Net rehash and check if it matches Meteor's hash
if (BCrypt.Net.BCrypt.Verify(sha256hash, dbPassword) == true) {
Console.WriteLine("Valid!");
}
This question already has answers here:
Hashing a SecureString in .NET
(4 answers)
Closed 7 years ago.
I believe I'm misunderstanding a fundamental part of SecureString. I understand that string's are immutable and there a password or sensitive data is found as clear text on the heap.
What I'm struggling to understand is, how do I use SecureString in a client application which needs to verify the hashed password in a database?
Here's my context:
I'm using a WPF client application.
I have a local SQL database (on the client's machine)
The passwords are hashed and stored in the database.
The user tries logging into to my WPF application
The PasswordBox control stores the password in a SecureString via the SecurePassword property.
Now what? How do I hash a SecureString WITHOUT casting it back into string first?
All the advise I've received so far is to write extension methods converting SecureString to String, hash it and then send it to db to verify. But this defeats the whole exercise!
Must I just accept that SecureString is useless in my mentioned context and use plain string?
SecureString is represented as a byte[] you could encode the bytes e.g. with bitconverter and save the result.
Furthermore SecureString is a encryption not a hash as it can be decrypted. (see below)
SecureString mainly meant to store sensitive data in memory.
If you have a service / website, this is not as important as the values which are stored in the database. These should never be plaintext, and imo not be decryptable by your or any administrator
Also i'm not sure wether another server could decrypt the strings, so you may have a problem when you change the server or have somekind of cluster scenario.
Especially for passwords would prefer using hash algorithms (e.g. SHA256) .
These can't be uncrypted (like the sum of the digits).
In the use case of a login funtionality you would encrypt the userinput and compare the hashs the user and and the one thats in the database. (details se below)
I would also suggest to add a dynamic criteria like the userid to the hashinput so that 2 user with same password would have different hashes.
With this strategy you don't have a risc with userpasswords and therefore if data gets leaked it wouldn't be a problem at this point.
Here an short overview of using hash algorithms
So ( if the securestring is given) first decrypt the SecureString
String SecureStringToString(SecureString value){
IntPtr valuePtr = IntPtr.Zero;
try{
valuePtr = Marshal.SecureStringToGlobalAllocUnicode(value);
return Marshal.PtrToStringUni(valuePtr);
}
finally{
Marshal.ZeroFreeGlobalAllocUnicode(valuePtr);
}
}
Than hash it for example with SHA256. From this post
using (SHA256 hash = SHA256Managed.Create()) {
Encoding enc = Encoding.UTF8;
//the user id is the salt.
//So 2 users with same password have different hashes.
//For example if someone knows his own hash he can't see who has same password
string input = userInput+userId;
Byte[] result = hash.ComputeHash(enc.GetBytes(input));
foreach (Byte b in result)
Sb.Append(b.ToString("x2")); //You could also use other encodingslike BASE64
}
Store this hashsum. Depending on your encoding it may looke like this:
ac5b208b4d35ec79fa7c14b7a31f9c80392cdab2bc58bc5b79bcfe64b044d899
in your database.
If the user signs on then create the hash from his input and compare it with the hash in the database. if they are equal then the password is correct.
Therefore you never need to have the plaintext user password anywhere stored.
If the client makes the hash then it should absolut should no where exist as a plaintext (except the textbox if it doesnt support the securestring)
PS: this is only one option. But the main thing is to never store plaintextpasswords anywhere. For best never know them and have no change to get them decrypted.
Another strategy would be to use asymmetric encryptions like RSA but this can become more complex. If you need help with that i would recommend a dedicated post on this.
Depending on your requirements and envionment most of the time hashsums should be an acceptable solution. (But thats not an legal advice as i'm not a lawyer)
At the time of registering
string crypt = CryptSharp.Crypter.Sha512.GenerateSalt();
crypt = txtspss.Text.Trim();
crypt = CryptSharp.Crypter.Sha512.Crypt(txtspss.Text, crypt);
At the time of login..
string cpass=dr["strUPass"].ToString();
bool matches = Crypter.CheckPassword(pass,cpass);
if (matches)
{....}
A salt is supposed to be unique. By doing this, someone trying to crack passwords has to do a separate compuation for each password, instead of being able to generate hashes for a million passwords and then check them against the entire stolen password database.
CryptSharp encodes passwords in Modular Crypt Format. Here's the design. Suppose the algorithm is A, the salt is B, and the hash is C. GenerateSalt writes AB, Crypt reads AB and generates C, returning ABC. Underneath, you see, CheckPassword is more or less equivalent to:
Crypter.Crypt(password, crypt) == crypt
Because Crypt reads only AB, if you pass it ABC, it's the same as passing it AB. This is how Crypt does double-duty both generating and checking password hashes.
At registration, GenerateSalt and Crypt, and at log-in, CheckPassword. Many people will tell you this or that about storing salts separately, etc. and this is good general advice, but Modular Crypt Format is designed so everything needed is stored in the same string. It's all taken care of for you.
Oh... Also, in your code, you have a bug. Your line in the middle isn't doing you any good. The following will work correctly:
string crypt = CryptSharp.Crypter.Sha512.GenerateSalt();
crypt = CryptSharp.Crypter.Sha512.Crypt(txtspss.Text.Trim(), crypt);
There is not enough code to say what exactly is wrong, but you should start by using the result of
CryptSharp.Crypter.Sha512.GenerateSalt()
because right now, you just dump it by overwriting the variable in the following line.
SHA512 is a Hashing algorithm, and to make it more secure against attacks like rainbow tables library methods optionally take a salt value.
The same salt value should be present when hashing and when comparing the hash of a new value, and in your code you don't seem to be doing that.
When registering a user; the Salt should be stored in the database and retrieved when logging in so it can be supplied to the CheckPassword function.
Currently writing my own AMF TcpSocketServer. Everything works good so far i can send and recieve objects and i use some serialization/deserialization code. Now i started working on the encryption code and i am not so familiar with this stuff.
I work with bytes , is DES-CBC a good
way to encrypt this stuff? Or are
there other more performant/secure
ways to send my data? Note that
performance is a must :).
When i call: ReadAmf3Object with the decrypter specified i get an: InvalidOperationException thrown by my ReadAmf3Object function when i read out the first byte the Amf3TypeCode isn't specified ( they range from 0 to 16 i believe (Bool, String, Int, DateTime, etc) ). I got Typecodes varying from 97 to 254? Anyone knows whats going wrong? I think it has something to do with the encryption part. Since the deserializer works fine w/o the encryption. I am using the right padding/mode/key?
I used: http://code.google.com/p/as3crypto/ as as3 encryption/decryption library. And i wrote an Async tcp server with some abuse of the threadpool ;)
Anyway here some code:
C# crypter initalization code
System.Security.Cryptography.DESCryptoServiceProvider crypter = new DESCryptoServiceProvider();
crypter.Padding = PaddingMode.Zeros;
crypter.Mode = CipherMode.CBC;
crypter.Key = Encoding.ASCII.GetBytes("TESTTEST");
AS3
private static var _KEY:ByteArray = Hex.toArray(Hex.fromString("TESTTEST"));
private static var _TYPE:String = "des-cbc";
public static function encrypt(array:ByteArray):ByteArray
{
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher(_TYPE, _KEY, pad);
pad.setBlockSize(mode.getBlockSize());
mode.encrypt(array);
return array;
}
public static function decrypt(array:ByteArray):ByteArray
{
var pad:IPad = new NullPad;
var mode:ICipher = Crypto.getCipher(_TYPE, _KEY, pad);
pad.setBlockSize(mode.getBlockSize());
mode.decrypt(array);
return array;
}
C# read/unserialize/decrypt code
public override object Read(int length)
{
object d;
using (MemoryStream stream = new MemoryStream())
{
stream.Write(this._readBuffer, 0, length);
stream.Position = 0;
if (this.Decrypter != null)
{
using (CryptoStream c = new CryptoStream(stream, this.Decrypter, CryptoStreamMode.Read))
using (AmfReader reader = new AmfReader(c))
{
d = reader.ReadAmf3Object();
}
}
else
{
using (AmfReader reader = new AmfReader(stream))
{
d = reader.ReadAmf3Object();
}
}
}
return d;
}
Define "secure."
DES is more secure than plain text, but due to it's 56-bit keysize, it's not usually used anymore. If you're protecting data against your family, or the casual ease dropper this might be okay.
If people are using DES these days, it's Triple DES which essentially runs DES, three times, on each datablock.
Now a days the symmetric encryption algorithm (which DES is) of choice is AES, which is like the spiritual successor to DES.
AES with a sufficiently large key of 256 (really 512 or higher now a days) is cryptographically secure for most applications.
The few caveats of AES are:
It's still restricted to US Export controls
The NSA can decrypt your information if they want to (yes
this is tin hat thinking)
Regarding your error, first try switching to AES, and see if you still get a problem.
Regarding AES:
Key selection is important, as well as key protection.
Key Selection
If you want to "password" protect your data, using AES, then you need to convert your password into an AES key. This is a common pitfall for many amateur computer security developers. Adobe essentially destroyed all the protection of AES in their PDF's by using an MD5 hash of the users password as the key. Needless to say, you're smarter than all of Adobe's engineers combined, so you won't make that mistake.
The proper way to generate a key from a password is using RFC2898 aka PBKD2 (password based key derivation function). .NET handily has a method that does this: Rfc2898DeriveBytes(). Essentially what this does is cryptographically securely hashes your password, with a supplied salt (more on this in a bit), a number of times, supplied by the user. This provides several layers to protect against brute force attacks against your password (assuming your key is large enough to prevent brute force attacks against it!)
Each iteration of PBKD2 takes a minuscule amount of time to run. The more interation you run (i think the recommend number is > 1000), the more computer time it takes. This time is still less than a human would recognize, but in computer time it's like a century. Thus without knowing the exact iteration count, it makes it a very lengthy process to brute force attack a password.
Salt. Rather than taking a direct hash of your password, a salt adds extra information to your input password, creating a unique hash. This prevents rainbow table attacks, assuming you keep your salt value protected.
Key Storage
The other side to cryptography is key storage. If you are password protecting your data, then you need to securely store the password. The easiest way is to use the OS's built in security. On Windows thats using DPAPI in the registry, and Unix, filepermissions.
AES as a Session Key
If you are looking to securely transmit data across a nonsecure channel (or even adding your own extra security ontop of SSL), you may want to looking at using AES as a session encryption.
Essentially this is two scheme encryption system that works as follows:
You generate a public/private key pair using your favorite assymetric encryption (RSA!) for your server.
Each trusted client is given the public key.
During a session, the client generates a new random AES key of 256 bit or higher.
This AES Session key is encrypted using the public RSA key.
This encrypted data containing the AES session key is sent to the server.
The server decrypts the data using it's private RSA key, and keeps the AES Session key.
During the rest of the session, all data is encrypted with the session AES key.
At the end of the session, the AES key is discarded.
While this does require more handshaking, this gives you the added protection of limiting exposure. Since the AES key is only good for a session, if it's discovered, the damage is only limited to a single session.
DES is a block cipher, so in general it makes working with bytes more tedious. AS3 is a stream cipher used primarily with GSM phone systems, because it's a stream cipher it'll work nicely with bytes.
Personally, I would use RC4 if you really need to use a stream cipher; it's very quick. There's a good implementation here http://dotnet-snippets.com/dns/rc4-encryption-SID577.aspx
There are some very important caveats you should be aware of when using stream ciphers:
1) NEVER re-use an encryption key with a stream cipher.
2) Because you're encrypting one byte at a time, it's hard to determine if the data has been tampered with, so you'll need add a digital signature or HMAC to the stream.