So, I am the approach David Hayden posted on his blog (http://davidhayden.com/blog/dave/archive/2004/02/16/157.aspx) to create a salt and hash the user's password by taking the user's raw password and the generated salt and using SHA1 to hash the value.
I then store the salt and the hashed password in the database.
The website is currently load balanced, so I was wondering if resulting hash value would be the same for both servers.
Here is the snippet of code posted on David Hayden's blog:
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);
}
private static string CreatePasswordHash(string pwd, string salt)
{
string saltAndPwd = String.Concat(pwd, salt);
string hashedPwd =
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "sha1");
return hashedPwd;
}
The reason I ask is that this code uses the code snippet:
FormsAuthentication.HashPasswordForStoringInConfigFile(
saltAndPwd, "sha1");
I think the key question your asking here is if the SHA1 algorithm is the same whatever server it is running on. In which case the answer is yes.
Presumably you store your generated salt somewhere that all the servers can access it, along with the password hash? So the method used to generate the salt doesn't need to be consistent across servers.
This method will only use the parameters passed into it.
Don't worry about it; it will work.
"To address this issue, the validationKey and decryptionKey values must be identical on all computers in the Web farm."
http://msdn.microsoft.com/en-us/library/ff647070.aspx#pagexplained0002_webfarmscenarios
Related
I am getting an error decrypting a message in go that was encrypted in C# (using corresponding public/private keys)
My client is written in C# and my server is written in Go. I generated a private and public key via go's crypto/rsa package (using rsa.GenerateKey(random Reader, bits int)). I then store the public key file generated where the client can access it and the private key where the server can access it. I encrypt on the client with the following code (using bouncy castle):
public static string Encrypt(string plainText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
PemReader pr = new PemReader(
new StringReader(m_publicKey)
);
RsaKeyParameters keys = (RsaKeyParameters)pr.ReadObject();
// PKCS1 OAEP paddings
OaepEncoding eng = new OaepEncoding(new RsaEngine());
eng.Init(true, keys);
int length = plainTextBytes.Length;
int blockSize = eng.GetInputBlockSize();
List<byte> cipherTextBytes = new List<byte>();
for (int chunkPosition = 0; chunkPosition < length; chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
cipherTextBytes.AddRange(eng.ProcessBlock(
plainTextBytes, chunkPosition, chunkSize
));
}
return Convert.ToBase64String(cipherTextBytes.ToArray());
}
The go server parses this string from the header and uses the private key to decrypt:
func DecryptWithPrivateKey(ciphertext []byte, priv *rsa.PrivateKey) []byte {
hash := sha512.New()
plaintext, err := rsa.DecryptOAEP(hash, rand.Reader, priv, ciphertext, nil)
if err != nil {
fmt.Fprintf(os.Stderr, err.Error())
}
return plaintext
}
The decryption function throws crypto/rsa: decryption error. If I try pasting the cipher text directly into go (rather then sending from the client), the same error occurs.
NOTE: in order to get the public key to load, I needed to change the header from:
-----BEGIN RSA PUBLIC KEY-----
...
to
-----BEGIN PUBLIC KEY-----
...
and the same for the footer. I am assuming this is a formatting issue but not sure how to go about solving.
EDIT: it seems that golang OAEP uses sha256 and bouncy castle uses SHA-1. Go's documentation specifies that the hash for encryption and decryption must be the same. This seems likely to be the issue? If it is, how can I change the hashing algorithm used by either go or C#?
Yes, you need to match the hash. In GoLang you've already set it to SHA-512 if I take a look at your code. Using SHA-256 at minimum should probably be preferred, but using SHA-1 is relatively safe as the MGF1 function doesn't rely on the collision resistance of the underlying hash. It's also the default for most runtimes, I don't know why GoLang decided against that.
Probably the best is to set SHA-512 for both runtimes, so here is the necessary constant for .NET.
Note that the underlying story is even more complex as OAEP uses a hash over a label as well as a hash within MGF1 (mask generation function 1, the only one specified). Both need to be specified in advance and generally the same hash function is used, but sometimes it is not.
The label is generally empty and most runtimes don't even allow setting it, so the hash value over the label is basically a hash-function specific constant that doesn't matter for security. The constant just manages to make things incompatible; "More flexible" isn't always a good thing.
I want to verify a private key signed SHA256 hash using the CryptographicEngine in a UWP application. The hash is created externally and is signed with a private RSA key with passphrase. For this example however, I also generate the unsigned hash. Both hashes are then compared at the end to verify that they are the same.
I have created my private and public keys using OSX command line, specified in this blog.
This gave me two .pem files. My public key has the following structure:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fasaNKpXDf4B4ObQ76X
qOaSRaedFCAHvsW4G0PzxL/...ETC ETC
-----END PUBLIC KEY-----
Here is my C# code to decrypt the hash:
//HASH THE INPUT STRING
var inputText = "stringtohash";
// put the string in a buffer, UTF-8 encoded...
IBuffer input = CryptographicBuffer.ConvertStringToBinary(inputText,
BinaryStringEncoding.Utf8);
// hash it...
var hasher = HashAlgorithmProvider.OpenAlgorithm("SHA256");
IBuffer hashed = hasher.HashData(input);
// format it...
string ourhash = CryptographicBuffer.EncodeToBase64String(hashed);
Debug.WriteLine(ourhash);
//CONVERT EXTERNAL HASH TO BUFFER
IBuffer data = CryptographicBuffer.DecodeFromBase64String("b18fbf9bc0fc7595af646155e18b71e1aeccf01719f9f293c72217d7b95cc2106edb419078c4c5c1c7f7d106b90198a4f26beb49ff4a714db4bface1f94fff193b8126ce05fe13825144a3dde97f55399846b6fd768f1fb152f1ba71bbf5cde8c1a7e58621a493070256e2444db36c346a88e870906529cf13c072ead50b6a01b2e74c7ef8c5d423e8ea25220f524b563ae2c3345b7837f9cd1a357540b1380c86287b9a240cf67f7518f11418352b665b657c5ffb6cbcb6126ec59e360de6304392b78cf4de79b52d73b8292df6a1e643d0c0f0945aae5949b391e2915772c996f03e6d1879192b7edf0f40c01b875e768358aa47a992070f628418ddf06472");
//CONVERT PUBLIC KEY TO BUFFER
IBuffer publickey = CryptographicBuffer.DecodeFromBase64String("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3fasaNKpXDf4B4ObQ76XqOaSRaedFCAHvsW4G0PzxL / RuAQFz80esZPyyDCps1PAbTKzQ + QblChPo7PJkbsU4HzNN4PIRGh5xum6SRmdvOowrlTUtyxdOkRJoFxmiR / VCea + PUspt26F7PLcK9ao5 + hVzMvPuqdYenqzd01f1t5hQEhFQ9qjB6Es8fpizHd / RSRfZ7n6rVKm9wYfCRLB7GJ7IHhWGuZrx9fjzsbW8eagu06qRhnUuR5oDVjXC8ZeazsRiw50xMuOzkhX9Oo081IYikwCgseJmQhT7vF4lZoyeB4qJpwTCA + glSy1w9N8ZfxyXK8QaT2RsrBrzl0ZCwIDAQAB");
// Open an asymmetric algorithm provider for the specified algorithm.
AsymmetricKeyAlgorithmProvider rsa = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// Import Key
CryptographicKey key = rsa.ImportPublicKey(publickey, CryptographicPublicKeyBlobType.X509SubjectPublicKeyInfo);
// Decrypt the Hash using our Key
IBuffer result = CryptographicEngine.Decrypt(key, data, null);
Debug.WriteLine(result.ToString());
//Compare the two hashes
if (data == result) {
//Hash is verified!
}
Unfortunately when reaching the Decrypt method I get a NotImplementedException with error
The method or operation is not implemented
I researched online and I understand what needs to happen in theory but I don't know how to debug this further. What can I try?
Although both called PKCS#1 v1.5 padding, the padding for signature generation and encryption is not identical, see RFC 3447 for more details.
If you look at the RsaPkcs1 property you can see it is aimed at encryption:
Use the string retrieved by this property to set the asymmetric algorithm name when you call the OpenAlgorithm method. The string represents an RSA public key algorithm that uses PKCS1 to pad the plaintext. No hash algorithm is used.
As I don't see any option for "raw RSA", i.e. RSA without padding, it seems you are only able to verify your signature. However, RSA decryption expects an RSA private key. It's very likely that you get the error because of this: if you try and decrypt with a public key it will fail.
If you want to precompute the hash you can use VerifySignatureWithHashInput.
For other functionality you may have to use e.g. the C# lightweight API of Bouncy Castle. In the end you don't need platform provided cryptography to verify a signature.
I trying to Decrypt password in visual studio 2010 using C-Sharp language but i m stuck on this error i try all the solution which was provided on this side but my error not resolved how i encrypt password can anybody tell me using MD5 my code is,Now it gives another error "String reference not set to an instance of a String.*Parameter name: s" What can i do i cant understand .I m newbie on C#*.I dont know what can i do if i waste your time then sorry to all.
public string PasswordDecrypt(string sQueryString)
{
byte[] buffer;
TripleDESCryptoServiceProvider loCryptoClass = new
TripleDESCryptoServiceProvider();
MD5CryptoServiceProvider loCryptoProvider = new MD5CryptoServiceProvider();
try
{
buffer = Convert.FromBase64String(sQueryString);
loCryptoClass.Key = loCryptoProvider.ComputeHash(ASCIIEncoding.ASCII.GetBytes(sQueryString));
loCryptoClass.IV = lbtVector;
return ASCIIEncoding.ASCII.GetString(loCryptoClass.CreateDecryptor().TransformFinalBlock(buffer, 0, buffer.Length));
}
catch (Exception ex)
{
throw ex;
}
finally
{
loCryptoClass.Clear();
loCryptoProvider.Clear();
loCryptoClass = null;
loCryptoProvider = null;
}
}
The code relevant to your question is this:
string sQueryString = txtPassword.Text;
byte[] buffer = Convert.FromBase64String(sQueryString);
Create a test case for this, containing the data as is entered when you get the error. Perhaps your users don't input their password as base64.
I think you are confused about what to do for password security. Passwords don't get encrypted, they get hashed. That's kind of a one-way-encryption. The same password will always result in the same hash, but different passwords are allowed to generate the same hash, so it's impossible to decrypt it from hash to password.
While that doesn't sound useful at first, the point is that you never actually store the password, encrypted or not. You store the hash value of the password. That way you know when someone enters a password, it gets hashed and matches the stored hash, it's the correct password... without ever knowing what the password was.
So you cannot decrypt a hash. You simply hash your input and compare with an earlier hash from the correct password.
Please note that you should also google Salting hashes, a technique for lowering the attack surface of hashes once the data store was breached and the hash is known to potential attackers.
I'm trying to port the following Java code to a C# equivalent:
public static String encrypt(String value, String key) throws InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] bytes = value.getBytes(Charset.forName("UTF-8"));
X509EncodedKeySpec x509 = new X509EncodedKeySpec(DatatypeConverter.parseBase64Binary(key));
KeyFactory factory = KeyFactory.getInstance("RSA");
PublicKey publicKey = factory.generatePublic(x509);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
bytes = cipher.doFinal(bytes);
return DatatypeConverter.printBase64Binary(bytes);
}
So far I managed to write the following in C#, using the BouncyCastle library for .NET:
public static string Encrypt(string value, string key)
{
var bytes = Encoding.UTF8.GetBytes(value);
var publicKeyBytes = Convert.FromBase64String(key);
var asymmetricKeyParameter = PublicKeyFactory.CreateKey(publicKeyBytes);
var rsaKeyParameters = (RsaKeyParameters) asymmetricKeyParameter;
var cipher = CipherUtilities.GetCipher("RSA");
cipher.Init(true, rsaKeyParameters);
var processBlock = cipher.DoFinal(bytes);
return Convert.ToBase64String(processBlock);
}
The two methods, though, produce different results even if called with the same parameters.
For testing purposes, I'm using the following public RSA key:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLCZahTj/oz8mL6xsIfnX399Gt6bh8rDHx2ItTMjUhQrE/9kGznP5PVP19vFkQjHhcBBJ0Xi1C1wPWMKMfBsnCPwKTF/g4yga6yw26awEy4rvfjTCuFUsrShSPOz9OxwJ4t0ZIjuKxTRCDVUO7d/GZh2r7lx4zJCxACuHci0DvTQIDAQAB
Could you please help me to port the Java code successfully or suggest an alternative to get the same result in C#?
EDIT1: output in Java is different each time I run the program. I don't think that any padding was specified, so I don't understand what makes the output random.
EDIT2: Java uses PKCS1 by default, so it was enough to specify it in the C# cipher initialization to get the same encryption type (although not the same result, which was irrelevant at this point).
As an educated guess, I would say that Java adds random padding to create a stronger encryption.
Most practical implementations of RSA do this, and as the wiki puts it...
Because RSA encryption is a deterministic encryption algorithm – i.e., has no random component – an attacker can successfully launch a chosen plaintext attack against the cryptosystem, by encrypting likely plaintexts under the public key and test if they are equal to the ciphertext. A cryptosystem is called semantically secure if an attacker cannot distinguish two encryptions from each other even if the attacker knows (or has chosen) the corresponding plaintexts. As described above, RSA without padding is not semantically secure.
This is likely why your two methods don't output the same.
After looking at how to generate self-signed digital signatures from Creating a self-signed certificate in C#, I can call CreateSelfSignCertificatePfx and get PXF data in a byte array back, which can then be used within an X509Certificate2 object to sign and verify. Example...
byte[] pfx = Certificate.CreateSelfSignCertificatePfx("O=Company,CN=Firstname,SN=Lastname", DateTime.Now, DateTime.Now.AddYears(1), "password");
X509Certificate2 cert = new X509Certificate2(pfx, "password");
byte[] publicBytes = cert.RawData;
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
byte[] signedData = rsa.SignData(new System.Text.UTF8Encoding().GetBytes("Test"), new SHA1CryptoServiceProvider());
RSACryptoServiceProvider rsa2 = (RSACryptoServiceProvider)new X509Certificate2(publicBytes).PublicKey.Key;
bool verified = rsa2.VerifyData(new System.Text.UTF8Encoding().GetBytes("Test"), new SHA1CryptoServiceProvider(), signedData);
This works. My concern though is the original bytes, byte[] pfx from above, need to be stored in a DB (to sign stuff). The question becomes, how secure are the bytes in this format? I know you need the password to construct the new X509Certificate2 with a private key, but in a general sense, how secure are the bytes without the password? I have no problems encrypting these bytes as an added layer, but is that necessary?
According to X509Certificate2.X509Certificate2(Byte[], String) Constructor
Calling this constructor with the correct password decrypts the private key and saves it to a key container.
I just want to ensure the private key is safe without the password.
In my eyes the question is not whether you should put the "bytes" in the database, but more, would you put the file with the private key in your file system.
In the way you're doing it, it's essentially the same thing. You're just storing the bytes that make up the cert file.
I may be failing to understand the difference here, but they bytes and the file are essentially the same thing, the only difference being the fact that one has to gain access to the db to get them.
Use a smartcard or token to store your private key.
UPDATE:
The Pvt key can be accessed by anyone who can access the machine.
The private keys in a PFX (PKCS#12) are stored encrypted, which is of course what the password is for. Not all of a PFX is encrypted, the structural pieces stay plaintext to contain metadata about the contents (like what encryption algorithm was used).
Based on inspecting the file, as of Windows 7 the private keys are encrypted using 3-key (168-bit) 3DES. The key is derived via a complex formula involving your password; there's nothing saved in the file which gives any indication as to what your password was, how long it was, et cetera.
The password is usually proven correct by the addition of a MAC on the contents, which uses the same password for its key derivation function. In the possible case of the MAC password and the encryption password being different (which I've personally never seen) the password is verified by the structural information in the encrypted payload.
DES' weakness mainly lay in the small keysize, it's easily brute forcable today. A 3-key 3DES key has 112 more semantic bits than a (1)DES key, making it take 2^112 (~5 x 10^33) times longer to break.
So, at the end of the day, the private key is cryptographically sound. But like anything with a password-based input, if you use a bad password that is easily guessed then it can be cracked by brute force.