/// <summary> /// Decrypts data using the given RSA key /// </summary> /// <param name="Data">Data to decrypt</param> /// <param name="Params">RSA key</param> /// <returns>Decrypted data</returns> private static byte[] DecryptWithRSAKey(AesCryptoData Data, RSAParameters Params) { if (RSAEncryption.HasPrivateKey(Params)) { return(RSAEncryption.Decrypt(Params, Data.Data)); } throw new CryptographicException("The supplied RSA key lacks the private key parts"); }
/// <summary> /// Decrypts data using a given password /// </summary> /// <param name="Data">Data to decrypt</param> /// <param name="Password">Password that was used to encrypt</param> /// <returns>Decrypted and authenticated data</returns> private static byte[] DecryptWithPassword(AesCryptoData Data, string Password) { using (var pbkdf = new Rfc2898DeriveBytes(Password, Data.Salt, PBKDF_ITERATIONS)) { var MacKey = pbkdf.GetBytes(AES_KEYSIZE / 8); var AesKey = pbkdf.GetBytes(AES_KEYSIZE / 8); return(DecryptWithKey(Data, AesKey, MacKey)); } }
/// <summary> /// Encrypts data using the given password /// </summary> /// <param name="Data">Data to encrypt</param> /// <param name="Password">Password to encrypt the data with</param> /// <returns>Encrypted data</returns> private static AesCryptoData EncryptWithPassword(byte[] Data, string Password) { var Salt = new AesCryptoData().Salt; using (var pbkdf = new Rfc2898DeriveBytes(Password, Salt, PBKDF_ITERATIONS)) { var MacKey = pbkdf.GetBytes(AES_KEYSIZE / 8); var AesKey = pbkdf.GetBytes(AES_KEYSIZE / 8); var CD = EncryptWithKey(Data, AesKey, MacKey); CD.Salt = Salt; return(CD); } }
/// <summary> /// Encrypts data with a provided AES key and MAC key /// </summary> /// <param name="Data">Data to encrypt</param> /// <param name="AesKey">AES key (must match <see cref="Aes.KeySize"/>)</param> /// <param name="MacKey">MAC key (should not be the same as the AES key)</param> /// <returns>Encrypted and hashed data</returns> private static AesCryptoData EncryptWithKey(byte[] Data, byte[] AesKey, byte[] MacKey) { var CD = new AesCryptoData(); using (var AesEncryptor = new AesManaged()) { AesEncryptor.BlockSize = CD.IV.Length * 8; AesEncryptor.KeySize = AesKey.Length * 8; AesEncryptor.IV = CD.IV; AesEncryptor.Key = AesKey; AesEncryptor.Mode = CD.Mode; AesEncryptor.Padding = CD.Padding; using (var Enc = AesEncryptor.CreateEncryptor()) { CD.Data = Enc.TransformFinalBlock(Data, 0, Data.Length); CD.Mac = MAC(CD.Data, MacKey); } } return(CD); }
/// <summary> /// Decrypts data with a provided AES key and MAC key /// </summary> /// <param name="Data">Data to decrypt</param> /// <param name="AesKey">AES key</param> /// <param name="MacKey">MAC key</param> /// <returns>Decrypted and authenticated data</returns> /// <remarks>Will throw a <see cref="CryptographicException"/> if the MAC does not validates first</remarks> private static byte[] DecryptWithKey(AesCryptoData Data, byte[] AesKey, byte[] MacKey) { using (var AesEncryptor = new AesManaged()) { AesEncryptor.BlockSize = Data.IV.Length * 8; AesEncryptor.KeySize = AesKey.Length * 8; AesEncryptor.IV = Data.IV; AesEncryptor.Key = AesKey; AesEncryptor.Mode = Data.Mode; AesEncryptor.Padding = Data.Padding; if (!MAC(Data.Data, MacKey).SequenceEqual(Data.Mac)) { throw new CryptographicException("Invalid password or the encrypted data has been tampered with"); } using (var Dec = AesEncryptor.CreateDecryptor()) { return(Dec.TransformFinalBlock(Data.Data, 0, Data.Data.Length)); } } }
/// <summary> /// Decrypts data using a given key file /// </summary> /// <param name="Data">Data to decrypt</param> /// <param name="Keyfile">Key file to use as password</param> /// <returns>Decrypted and authenticated data</returns> private static byte[] DecryptWithKeyfile(AesCryptoData Data, string Keyfile) { return(DecryptWithPassword(Data, Convert.ToBase64String(File.ReadAllBytes(Keyfile)))); }
/// <summary> /// Encrypts the given data using the given methods /// </summary> /// <param name="Modes">Encryption modes</param> /// <param name="Content">Data to encrypt</param> /// <param name="ModeParams">Parameter for the supplied modes (for those that require parameters)</param> /// <returns>Encrypted and serializable data</returns> /// <remarks>See the <see cref="CryptoMode"/> enumeration for required arguments</remarks> public static EncryptedData Encrypt(CryptoMode Modes, byte[] Content, IDictionary <CryptoMode, object> ModeParams = null) { var ED = new EncryptedData(); var AesKey = ED.AesKey = GetRandomKey(); var MacKey = ED.MacKey = GetRandomKey(); var KeyBlob = Encoding.ASCII.GetBytes(Convert.ToBase64String(AesKey) + ":" + Convert.ToBase64String(MacKey)); var EncModes = Tools.FlagsToArray(Modes); ED.Data = EncryptWithKey(Content, AesKey, MacKey); ED.Providers = EncModes.Select(m => new KeyProvider() { Mode = m }).ToArray(); for (var i = 0; i < ED.Providers.Length; i++) { var P = ED.Providers[i]; var Data = new AesCryptoData(); var Param = ModeParams == null ? null : (ModeParams.ContainsKey(P.Mode) ? ModeParams[P.Mode] : null); switch (P.Mode) { case CryptoMode.CryptUser: Data.Salt = Data.IV = null; Data.Data = ProtectData(false, KeyBlob); break; case CryptoMode.CryptMachine: Data.Salt = Data.IV = null; Data.Data = ProtectData(true, KeyBlob); break; case CryptoMode.RSA: if (Param == null || Param.GetType() != typeof(RSAParameters)) { throw new ArgumentException("RSA mode requires an RSAParameters structure as argument"); } Data = EncryptWithRSAKey(KeyBlob, (RSAParameters)Param); break; case CryptoMode.Keyfile: if (Param == null || Param.GetType() != typeof(string)) { throw new ArgumentException("Keyfile mode requires a file name argument"); } Data = EncryptWithKeyfile(KeyBlob, Param.ToString()); break; case CryptoMode.Password: if (Param == null || Param.GetType() != typeof(string)) { throw new ArgumentException("Password mode requires a password argument"); } Data = EncryptWithPassword(KeyBlob, Param.ToString()); break; default: throw new NotImplementedException($"Algorithm {P.Mode} is not implemented"); } P.KeyData = Data; } return(ED); }