I have to store the key into memory. So as security concern we can not store the cryptographic key into the memory directly, We need to store the key in Encrypted way. So the idea is we store the key in encrypted manner and at the time of crypto operation, just decrypt the key and use it and dispose the key.
So we are using Password based encryption(PBE) define in BouncyCastle c# version Example code.
The problem in code is that the password is fix here. I have to generate the password at run time.
Steps to Store the Key:
Generate password
Create temporary key to encrypt the key(secure data)
Save into memory
Steps to perform Crypto operation:
Generate password
Create temporary key to decrypt the key(secure data)
perform crypto operation
Dispose the key(secure data)
Here is an idea so the password can be never stored unencrypted outside local vars:
using System;
using System.Security;
using System.Security.Cryptography;
using System.Text;
private string _SecureKey;
public bool MemorizePassword { get; set; }
public string Password
{
get
{
if ( _Password.IsNullOrEmpty() ) return _Password;
var buf = Encoding.Default.GetBytes(_Password);
ProtectedMemory.Unprotect(buf, MemoryProtectionScope.SameProcess);
return Encoding.Default.GetString(Decrypt(buf, _SecureKey.ToString()));
}
set
{
if ( !MemorizePassword )
{
_Password = "";
return;
}
CreateSecureKey();
if ( value.IsNullOrEmpty() )
_Password = value;
else
{
var buf = Encrypt(Encoding.Default.GetBytes(value), _SecureKey.ToString());
ProtectedMemory.Protect(buf, MemoryProtectionScope.SameProcess);
_Password = Encoding.Default.GetString(buf);
}
}
}
private void CreateSecureKey()
{
_SecureKey = new SecureString();
foreach ( char c in Convert.ToBase64String(CreateCryptoKey(64)) )
_SecureKey.AppendChar(c);
_SecureKey.MakeReadOnly();
}
static public byte[] CreateCryptoKey(int length)
{
if ( length < 1 ) length = 1;
byte[] key = new byte[length];
new RNGCryptoServiceProvider().GetBytes(key);
return key;
}
static public byte[] Encrypt(byte[] data, string password)
{
return Encrypt(data, password, DefaultCryptoSalt);
}
static public byte[] Decrypt(byte[] data, string password)
{
return Decrypt(data, password, DefaultCryptoSalt);
}
static public string Encrypt(string str, string password, byte[] salt)
{
if ( str.IsNullOrEmpty() ) return str;
PasswordDeriveBytes p = new PasswordDeriveBytes(password, salt);
var s = Encrypt(Encoding.Default.GetBytes(str), p.GetBytes(32), p.GetBytes(16));
return Convert.ToBase64String(s);
}
static public string Decrypt(string str, string password, byte[] salt)
{
if ( str.IsNullOrEmpty() ) return str;
PasswordDeriveBytes p = new PasswordDeriveBytes(password, salt);
var s = Decrypt(Convert.FromBase64String(str), p.GetBytes(32), p.GetBytes(16));
return Encoding.Default.GetString(s);
}
static public byte[] Encrypt(byte[] data, byte[] key, byte[] iv)
{
if ( data == null ) return data;
using ( MemoryStream m = new MemoryStream() )
{
var r = Rijndael.Create().CreateEncryptor(key, iv);
using ( CryptoStream c = new CryptoStream(m, r, CryptoStreamMode.Write) )
c.Write(data, 0, data.Length);
return m.ToArray();
}
}
static public byte[] Decrypt(byte[] data, byte[] key, byte[] iv)
{
if ( data == null ) return data;
using ( MemoryStream m = new MemoryStream() )
{
var r = Rijndael.Create().CreateDecryptor(key, iv);
using ( CryptoStream c = new CryptoStream(m, r, CryptoStreamMode.Write) )
c.Write(data, 0, data.Length);
return m.ToArray();
}
}
Example of salt specific to your app (use any random value between 0 and 255):
byte[] DefaultCryptoSalt = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Related
I am trying to save encrypted data to a Text file and then open and decrypt it. When I try to Decrypt it I receive the error "Padding is Invalid and Cannot Be Removed." I am using example code directly from Microsoft for encryption and decryption.
Here is MY code to encrypt and save file:
string json = JsonConvert.SerializeObject(credentials);
using (AesManaged myAes = new AesManaged())
{
byte[] encrypted = ControlHelperscs.EncryptStringToBytes_Aes(json, myAes.Key, myAes.IV);
File.WriteAllBytes(subPath, encrypted);
}
Here is my code to Retrieve and Decrypt file:
using (AesManaged myAes = new AesManaged())
{
byte[] file = File.ReadAllBytes(subPath);
string decrypt = ControlHelperscs.DecryptStringFromBytes_Aes(file, myAes.Key, myAes.IV);
credentials = JsonConvert.DeserializeObject<LoginModel>(decrypt);
}
Here are Encrypt and Decrypt methods:
public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
byte[] encrypted;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create an encryptor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesManaged object
// with the specified key and IV.
using (AesManaged aesAlg = new AesManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decryptor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
I'm sorry I deleted my comment (it was wrong in that context), but I reworked your example to have a little less boilerplate and be able to encrypt and decrypt properly. The problem is that you're generating a new and different Key/IV pair to decrypt from the one you used to encrypt. Of course it won't be able to decrypt. So, here is the part to make it work:
byte[] key;
byte[] iv;
string json = JsonConvert.SerializeObject(credentials);
using (AesManaged myAes = new AesManaged())
{
key = myAes.Key;
iv = myAes.IV;
byte[] encrypted = ControlHelperscs.EncryptStringToBytes_Aes(json, key, iv);
File.WriteAllBytes(subPath, encrypted);
}
byte[] file = File.ReadAllBytes(subPath);
string decrypt = ControlHelperscs.DecryptStringFromBytes_Aes(file, key, iv);
credentials = JsonConvert.DeserializeObject<LoginModel>(decrypt);
and here are the slightly reworked heavy-lifting methods to be a bit more compact:
public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText is null)
{
throw new ArgumentNullException(nameof(plainText));
}
if (plainText.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(plainText), plainText, "length cannot be zero");
}
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
if (key.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(key), key, "length cannot be zero");
}
if (iv is null)
{
throw new ArgumentNullException(nameof(iv));
}
if (iv.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(iv), iv, "length cannot be zero");
}
// Create an AesManaged object
// with the specified key and IV.
// Create an encryptor to perform the stream transform.
// Create the streams used for encryption.
using (SymmetricAlgorithm aesAlg = new AesManaged { Key = key, IV = iv })
using (ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV))
using (MemoryStream msEncrypt = new MemoryStream())
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
using (TextWriter swEncrypt = new StreamWriter(csEncrypt))
{
// Write all data to the stream.
swEncrypt.Write(plainText);
swEncrypt.Flush();
csEncrypt.FlushFinalBlock();
// Return the encrypted bytes from the memory stream.
return msEncrypt.ToArray();
}
}
public static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText is null)
{
throw new ArgumentNullException(nameof(cipherText));
}
if (cipherText.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(cipherText), cipherText, "length cannot be zero");
}
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
if (key.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(key), key, "length cannot be zero");
}
if (iv is null)
{
throw new ArgumentNullException(nameof(iv));
}
if (iv.Length == 0)
{
throw new ArgumentOutOfRangeException(nameof(iv), iv, "length cannot be zero");
}
// Create an AesManaged object
// with the specified key and IV.
// Create a decryptor to perform the stream transform.
// Create the streams used for decryption.
using (SymmetricAlgorithm aesAlg = new AesManaged { Key = key, IV = iv })
using (ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV))
using (Stream msDecrypt = new MemoryStream(cipherText))
using (Stream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
using (TextReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
return srDecrypt.ReadToEnd();
}
}
I am trying to port an existing .net encryption code to ruby. But stuck with the key not set error.
Bellow is the .net code to encrypt a string.
private static string Encrypt(string strToEncrypt, string saltValue, string password)
{
using (var csp = new AesCryptoServiceProvider())
{
ICryptoTransform e = GetCryptoTransform(csp, true, saltValue, password);
byte[] inputBuffer = Encoding.UTF8.GetBytes(strToEncrypt);
byte[] output = e.TransformFinalBlock(inputBuffer, 0, inputBuffer.Length);
string encrypted = Convert.ToBase64String(output);
return encrypted;
}
}
private static ICryptoTransform GetCryptoTransform(AesCryptoServiceProvider csp, bool encrypting, string saltValue, string password)
{
csp.Mode = CipherMode.CBC;
csp.Padding = PaddingMode.PKCS7;
var passWord = password;
var salt = saltValue;
//a random Init. Vector. just for testing
String iv = "e675f725e675f123";
var spec = new Rfc2898DeriveBytes(Encoding.UTF8.GetBytes(passWord), Encoding.UTF8.GetBytes(salt), 1000);
byte[] key = spec.GetBytes(16);
csp.IV = Encoding.UTF8.GetBytes(iv);
csp.Key = key;
if (encrypting)
{
return csp.CreateEncryptor();
}
return csp.CreateDecryptor();
}
I have used Ruby's OpenSSL::PKCS5 library to generate key and OpenSSL::Cipher to encrypt using AES algorithm like bellow.
def aes_encrypt(input_string)
cipher = OpenSSL::Cipher.new('AES-128-CBC')
cipher.encrypt
key = encryption_key
iv = cipher.random_iv
cipher.update(input_string) + cipher.final
end
def encryption_key
OpenSSL::PKCS5.pbkdf2_hmac_sha1(PASSWORD, SALT, 1000, 16)
end
Can anyone let know where I am missing? (Padding ?)
I want to decrypt AES 128 in Universal app (win 10), but we do not have AesManaged because this lib doesn't exist in System.Security.Cryptography.
So, how can I decrypt my string in UWA c#?
I use this code in windows phone 8 :
public static string DecryptString(string cipherText)
{
const string password = "myPass";
string plaintext = null;
try
{
if (!string.IsNullOrEmpty(cipherText))
{
if (cipherText != "")
{
var key = new byte[KeySize];
var passwordbytes = Encoding.UTF8.GetBytes(password);
for (var i = 0; i < KeySize; i++)
{
if (i >= passwordbytes.Length)
{
key[i] = 0;
break;
}
key[i] = passwordbytes[i];
}
var cipherTextBytes = Convert.FromBase64String(cipherText.Replace("-", "+").Replace("_", "/"));
// Declare the string used to hold
// the decrypted text.
BCEngine
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (var aesAlg = new AesManaged())
{
//aesAlg.Mode = CipherMode.CBC;
aesAlg.KeySize = KeySize * 8;
// Create a decrytor to perform the stream transform.
var decryptor = aesAlg.CreateDecryptor(key, Iv);
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream(cipherTextBytes))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
}
}
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
}
return plaintext;
}
I have the following encrypt/decrypt methods on JAVA
private static final String ALGORITHM = "AES";
protected static String encrypt(String valueToEnc, byte[] keyValue) throws Exception {
Key key = generateKey(keyValue);
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
String encryptedValue = new BASE64Encoder().encode(encValue);
return encryptedValue;
}
protected static String decrypt(String encryptedValue, byte[] keyValue) throws Exception {
try
{
Key key = generateKey(keyValue);
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedValue);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
catch(Exception ex)
{
return "";
}
}
private static Key generateKey(byte[] keyValue) throws Exception {
Key key = new SecretKeySpec(keyValue, ALGORITHM);
return key;
}
What would be the equivalent decryption for (C#).NET?. I have tested some Cipher examples that I have found, but none of them return the same as the Java Version.
Thanks.
Try this:
using System;
using System.IO;
using System.Security.Cryptography;
namespace Aes_Example
{
class AesExample
{
public static void Main()
{
try
{
string original = "Here is some data to encrypt!";
// Create a new instance of the AesCryptoServiceProvider
// class. This generates a new key and initialization
// vector (IV).
using (AesCryptoServiceProvider myAes = new AesCryptoServiceProvider())
{
// Encrypt the string to an array of bytes.
byte[] encrypted = EncryptStringToBytes_Aes(original, myAes.Key, myAes.IV);
// Decrypt the bytes to a string.
string roundtrip = DecryptStringFromBytes_Aes(encrypted, myAes.Key, myAes.IV);
//Display the original data and the decrypted data.
Console.WriteLine("Original: {0}", original);
Console.WriteLine("Round Trip: {0}", roundtrip);
}
}
catch (Exception e)
{
Console.WriteLine("Error: {0}", e.Message);
}
}
static byte[] EncryptStringToBytes_Aes(string plainText, byte[] Key, byte[] IV)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
throw new ArgumentNullException("plainText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("Key");
byte[] encrypted;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
// Return the encrypted bytes from the memory stream.
return encrypted;
}
static string DecryptStringFromBytes_Aes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
if (IV == null || IV.Length <= 0)
throw new ArgumentNullException("IV");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
}
}
source: http://msdn.microsoft.com/en-us/library/system.security.cryptography.aescryptoserviceprovider(v=vs.110).aspx
I'm implementing the ValidateUser method on a custom MembershipProvider class. I've seen quite a few examples of this, I'm looking for some guidance on how to properly encode/hash/encrypt my passwords. I'm no crypto expert, and I'm a little anxious about straying from the default implementation. Should I just copy the relevant source code from the SqlMembershipProvider or will any of these work?
http://mattwrock.com/post/2009/10/14/Implementing-custom-Membership-Provider-and-Role-Provider-for-Authinticating-ASPNET-MVC-Applications.aspx
public override bool ValidateUser(string username, string password)
{
if(string.IsNullOrEmpty(password.Trim())) return false;
string hash = EncryptPassword(password);
User user = _repository.GetByUserName(username);
if (user == null) return false;
if (user.Password == hash)
{
User = user;
return true;
}
return false;
}
protected string EncryptPassword(string password)
{
// Produses an MD5 hash string of the password
//we use codepage 1252 because that is what sql server uses
byte[] pwdBytes = Encoding.GetEncoding(1252).GetBytes(password);
byte[] hashBytes = System.Security.Cryptography.MD5.Create().ComputeHash(pwdBytes);
return Encoding.GetEncoding(1252).GetString(hashBytes);
}
ASP.NET membership salt?
public string EncodePassword(string pass, string salt)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] src = Encoding.Unicode.GetBytes(salt);
byte[] dst = new byte[src.Length + bytes.Length];
Buffer.BlockCopy(src, 0, dst, 0, src.Length);
Buffer.BlockCopy(bytes, 0, dst, src.Length, bytes.Length);
HashAlgorithm algorithm = HashAlgorithm.Create("SHA1");
byte[] inArray = algorithm.ComputeHash(dst);
return Convert.ToBase64String(inArray);
}
ASP.NET membership salt?
private const int ITERATIONS = 10000;
private const int SALT_SIZE = 32;
private const int HASH_SIZE = 32;
public void SaltAndHashPassword(string password, out byte[] salt, out byte[] hash)
{
Rfc2898DeriveBytes rdb = new Rfc2898DeriveBytes(password, SALT_SIZE, ITERATIONS);
salt = rdb.Salt;
hash = rdb.GetBytes(HASH_SIZE);
}
ASP.NET membership salt?
internal string GenerateSalt()
{
byte[] buf = new byte[16];
(new RNGCryptoServiceProvider()).GetBytes(buf);
return Convert.ToBase64String(buf);
}
internal string EncodePassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bAll = new byte[bSalt.Length + bIn.Length];
byte[] bRet = null;
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm s = HashAlgorithm.Create("SHA1");
// Hardcoded "SHA1" instead of Membership.HashAlgorithmType
bRet = s.ComputeHash(bAll);
}
else
{
bRet = EncryptPassword(bAll);
}
return Convert.ToBase64String(bRet);
}
Download BCrypt.Net. As opposed to typica SHA hashing, which is too fast making anything encrypted with it easy to brute force. BCrypt is slower due to a configurable work factor, so whilst imperceptable to the user, when trying to brute force 700m keys a second, you simply can't.
Once you have bcrypt all you need to do to hash is:
...
private static readonly int BCRYPT_WORK_FACTOR = 10;
string hashedPassword = BCrypt.Net.BCrypt.HashPassword(account.HashedPassword, BCRYPT_WORK_FACTOR);
...
and to check a password:
bool matched = BCrypt.Net.BCrypt.Verify(password, match.HashedPassword))
More info here: http://www.danharman.net/2011/06/25/encrypting-hashing-passwords-for-your-website/
I use next:
var salt = Encoding.UTF8.GetBytes(this.Name);
var bytes = Encoding.UTF8.GetBytes(password);
return Convert.ToBase64String(new HMACSHA1(salt).ComputeHash(bytes));