0
votes

I don't have deep information about cryptography ,but as I gathered some information,as an asymmetric solution I want to use RSA and here is the code which I found,I want to store an encrypted password into database and decrypt it whenever I want to get the user information,I mean these two actions don't happen respectively and whenever I like I can select from database and decrypt the previously save data.I know that there is something wrong with the generated keys,but because of low knowledge on this subject I cannot handle it. I get the following Exception on decryption.

The parameter is incorrect. at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) at System.Security.Cryptography.RSACryptoServiceProvider.DecryptKey(SafeKeyHandle pKeyContext, Byte[] pbEncryptedKey, Int32 cbEncryptedKey, Boolean fOAEP, ObjectHandleOnStack ohRetDecryptedKey) at System.Security.Cryptography.RSACryptoServiceProvider.Decrypt(Byte[] rgb, Boolean fOAEP)

Encryption Class:

public static class AsymmetricEncryption
{
    private static bool _optimalAsymmetricEncryptionPadding = false;

    public static void GenerateKeys(int keySize, out string publicKey, out string publicAndPrivateKey)
    {
        using (var provider = new RSACryptoServiceProvider(keySize))
        {
            publicKey = provider.ToXmlString(false);
            publicAndPrivateKey = provider.ToXmlString(true);
        }
    }

    public static string EncryptText(string text, int keySize, string publicKeyXml)
    {
        var encrypted = Encrypt(Encoding.UTF8.GetBytes(text), keySize, publicKeyXml);
        return Convert.ToBase64String(encrypted);
    }

    public static byte[] Encrypt(byte[] data, int keySize, string publicKeyXml)
    {
        if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
        int maxLength = GetMaxDataLength(keySize);
        if (data.Length > maxLength) throw new ArgumentException(String.Format("Maximum data length is {0}", maxLength), "data");
        if (!IsKeySizeValid(keySize)) throw new ArgumentException("Key size is not valid", "keySize");
        if (String.IsNullOrEmpty(publicKeyXml)) throw new ArgumentException("Key is null or empty", "publicKeyXml");

        using (var provider = new RSACryptoServiceProvider(keySize))
        {
            provider.FromXmlString(publicKeyXml);
            return provider.Encrypt(data, _optimalAsymmetricEncryptionPadding);
        }
    }

    public static string DecryptText(string text, int keySize, string publicAndPrivateKeyXml)
    {
        var decrypted = Decrypt(Convert.FromBase64String(text), keySize, publicAndPrivateKeyXml);
        return Encoding.UTF8.GetString(decrypted);
    }

    public static byte[] Decrypt(byte[] data, int keySize, string publicAndPrivateKeyXml)
    {
        if (data == null || data.Length == 0) throw new ArgumentException("Data are empty", "data");
        if (!IsKeySizeValid(keySize)) throw new ArgumentException("Key size is not valid", "keySize");
        if (String.IsNullOrEmpty(publicAndPrivateKeyXml)) throw new ArgumentException("Key is null or empty", "publicAndPrivateKeyXml");

        using (var provider = new RSACryptoServiceProvider(keySize))
        {
            provider.FromXmlString(publicAndPrivateKeyXml);
            return provider.Decrypt(data, _optimalAsymmetricEncryptionPadding);
        }
    }

    public static int GetMaxDataLength(int keySize)
    {
        if (_optimalAsymmetricEncryptionPadding)
        {
            return ((keySize - 384) / 8) + 7;
        }
        return ((keySize - 384) / 8) + 37;
    }

    public static bool IsKeySizeValid(int keySize)
    {
        return keySize >= 384 &&
                keySize <= 16384 &&
                keySize % 8 == 0;
    }
}

Encrypt usage:

const int keySize = 1024;
string publicAndPrivateKey;
string publicKey;

AsymmetricEncryption.GenerateKeys(keySize, out publicKey, out publicAndPrivateKey);

string text = "text for encryption";
string encrypted = AsymmetricEncryption.EncryptText(text, keySize, publicKey);

Decrypt usage:

const int keySize = 1024;
string publicAndPrivateKey;
string publicKey;

AsymmetricEncryption.GenerateKeys(keySize, out publicKey, out publicAndPrivateKey);

string text = "text for encryption";
string encrypted = AsymmetricEncryption.DecryptText(text, keySize, publicKey);

I read the encrypted text from a table.And I like to decrypt it. Please help me solve this issue. Thanks in advance

Snippet link

1

1 Answers

1
votes

Let me stop you right here, before you actually figure out the exception.

IT IS A HORRIBLE IDEA TO STORE PASSWORDS REVERSIBLY, regardless what encryption you use. There are memory scrubbers and a million other problems with that scheme.

Passwords are to be HASHED, NOT ENCRYPTED. The difference is that hashes are hard to reverse if implemented properly. Use BCrypt or SHA2 or SHA3 or some other good hashing algorithms, use proper salt.

Here's an example, but consult someone knowledgeable before using in production, I may have bugs, the methods are coded for simplicity and may be too simple:

public string GetHash(string secret, string salt = null)
{
  var hasher = SHA256Managed.Create();
  salt = salt ?? Guid.NewGuid().ToString("N"); // 128 bit salt 
  var hashResult = hasher.ComputeHash(Encoding.UTF8.GetBytes(salt+"|"+what));
  return "SHA256|" + salt + "|" + Convert.ToBase64String(hashResult);
}

Now you can store the string you get from this function in your DB and the next time a password comes in (over HTTPS, I hope) you can check it by getting the salt from the string stored in DB:

public bool CheckSecretHash(string secret, string hashFromDB){
  var hashParts = hashFromDB.Split('|'); // string[3]
  var rehash = GetHash(secret, hashParts[1]);
  return hashFromDB == rehash;
}

Bonus points: challenge-response. ALWAYS USE HTTPS.