private static void DecryptFile(string storage, string fullInfoFilePath) { // load parameters var secret = SecretData.Deserialize(fullInfoFilePath); var basePath = Path.GetDirectoryName(fullInfoFilePath); var decryptedFullFileName = Path.Combine(basePath, secret.DecryptedFileName); byte[] iv1 = Convert.FromBase64String(secret.IV1); byte[] key1 = Convert.FromBase64String(secret.Key1); byte[] iv2 = Convert.FromBase64String(secret.IV2); byte[] key2 = Convert.FromBase64String(secret.Key2); HashAlgorithm decryptedHashAlg, encryptedHashAlg; GetHashAlgorithms(out decryptedHashAlg, out encryptedHashAlg); try { using (FileStream decryptedFileStream = new FileStream(decryptedFullFileName, FileMode.Create)) using (CryptoStream decryptedHashStream = new CryptoStream(decryptedFileStream, decryptedHashAlg, CryptoStreamMode.Write)) using (CryptoStream decryptor1 = new CryptoStream(decryptedHashStream, new RijndaelManaged { KeySize = keySize }.CreateDecryptor(key1, iv1), CryptoStreamMode.Write)) using (CryptoStream decryptor2 = new CryptoStream(decryptor1, new RijndaelManaged { KeySize = keySize }.CreateDecryptor(key2, iv2), CryptoStreamMode.Write)) using (CryptoStream encryptedHashStream = new CryptoStream(decryptor2, encryptedHashAlg, CryptoStreamMode.Write)) { var backupStorage = GetBackupStorage(storage, basePath); backupStorage.Download(secret.EncryptedFileName, encryptedHashStream); } if (secret.DecryptedMD5 != Convert.ToBase64String(decryptedHashAlg.Hash)) { throw new InvalidDataException("Decrypted hash mismatch"); } if (secret.EncryptedMD5 != Convert.ToBase64String(encryptedHashAlg.Hash)) { throw new InvalidDataException("Encrypted hash mismatch"); } } catch { try { if (File.Exists(decryptedFullFileName)) { File.Delete(decryptedFullFileName); } } catch { /* we just trying to cleanup, but probably better processing required...*/ } throw; } }
private static void Encrypt(string storage, string decryptedFullFilePath, string password1, string password2) { var secret = new SecretData(); // generate a 128-bit salt and IV using a secure PRNG byte[] iv1 = new byte[ivSize / 8]; byte[] salt1 = new byte[ivSize / 8]; byte[] key1; byte[] iv2 = new byte[ivSize / 8]; byte[] salt2 = new byte[ivSize / 8]; byte[] key2; var randomFileName = new byte[ivSize / 8]; // generate key`s using (var rng = RandomNumberGenerator.Create()) using (var kd1 = new Rfc2898DeriveBytes(password1, salt1, 10000 + salt1[0] + salt1[1] + salt1[2] + salt1[3])) using (var kd2 = new Rfc2898DeriveBytes(password2, salt2, 10000 + salt2[4] + salt2[5] + salt2[6] + salt2[7])) { rng.GetBytes(iv1); rng.GetBytes(salt1); rng.GetBytes(iv2); rng.GetBytes(salt2); rng.GetBytes(randomFileName); key1 = kd1.GetBytes(keySize / 8); key2 = kd2.GetBytes(keySize / 8); //byte[] key1 = Microsoft.AspNetCore.Cryptography.KeyDerivationKeyDerivation.Pbkdf2(password1, salt1, KeyDerivationPrf.HMACSHA512, 10000 + salt1[0] + salt1[1] + salt1[2] + salt1[3], keySize / 8); //byte[] key2 = Microsoft.AspNetCore.Cryptography.KeyDerivationKeyDerivation.Pbkdf2(password2, salt2, KeyDerivationPrf.HMACSHA512, 10000 + salt2[4] + salt2[5] + salt2[6] + salt2[7], keySize / 8); } // prepare secret.IV1 = Convert.ToBase64String(iv1); secret.Key1 = Convert.ToBase64String(key1); secret.IV2 = Convert.ToBase64String(iv2); secret.Key2 = Convert.ToBase64String(key2); secret.DecryptedFileName = Path.GetFileName(decryptedFullFilePath); //secret.EncryptedFileName = Guid.NewGuid().ToString("N"); // may disclouse information about TimeStamp and PC MAC address secret.EncryptedFileName = BitConverter.ToString(randomFileName).Replace("-", string.Empty); var baseFolder = Path.GetDirectoryName(decryptedFullFilePath); HashAlgorithm decryptedHashAlg, encryptedHashAlg; GetHashAlgorithms(out decryptedHashAlg, out encryptedHashAlg); using (FileStream decryptedFileStream = new FileStream(decryptedFullFilePath, FileMode.Open)) using (CryptoStream decryptedHashStream = new CryptoStream(decryptedFileStream, decryptedHashAlg, CryptoStreamMode.Read)) using (CryptoStream encryptor1 = new CryptoStream(decryptedHashStream, new RijndaelManaged { KeySize = keySize }.CreateEncryptor(key1, iv1), CryptoStreamMode.Read)) using (CryptoStream encryptor2 = new CryptoStream(encryptor1, new RijndaelManaged { KeySize = keySize }.CreateEncryptor(key2, iv2), CryptoStreamMode.Read)) using (CryptoStream encryptedHashStream = new CryptoStream(encryptor2, encryptedHashAlg, CryptoStreamMode.Read)) { var backupStorage = GetBackupStorage(storage, baseFolder); if (backupStorage.ProgressReporter != null) { backupStorage.ProgressReporter.Init(decryptedFileStream.Length); } backupStorage.Upload(secret.EncryptedFileName, encryptedHashStream); } secret.DecryptedMD5 = Convert.ToBase64String(decryptedHashAlg.Hash); secret.EncryptedMD5 = Convert.ToBase64String(encryptedHashAlg.Hash); secret.Serialize(decryptedFullFilePath + ".secret"); }