public static bool AuthenticateFile(string filePath, byte[] macKey, out byte[] storedHash) { try { bool tampered = true; storedHash = ReadStoredHash(filePath); if (storedHash != null) { byte[] computedHash = new byte[Constants.HashLength]; using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, Constants.FileBufferSize, FileOptions.SequentialScan)) { // Remove the stored MAC from the file before computing the MAC fileStream.SetLength(fileStream.Length - computedHash.Length); MemoryEncryption.DecryptByteArray(ref macKey); computedHash = HashingAlgorithms.Blake2(fileStream, macKey); MemoryEncryption.EncryptByteArray(ref macKey); } // Invert result tampered = !Sodium.Utilities.Compare(storedHash, computedHash); if (tampered == true) { // Restore the stored MAC AppendHash(filePath, storedHash); } } return(tampered); } catch (Exception ex) when(ExceptionFilters.FileAccessExceptions(ex)) { Logging.LogException(ex.ToString(), Logging.Severity.High); DisplayMessage.ErrorResultsText(filePath, ex.GetType().Name, "Unable to authenticate the file."); storedHash = null; return(true); } }
private static byte[] GetKeyfileBytes(byte[] passwordBytes) { if (!string.IsNullOrEmpty(Globals.KeyfilePath)) { byte[] keyfileBytes = Keyfiles.ReadKeyfile(Globals.KeyfilePath); if (keyfileBytes != null) { MemoryEncryption.DecryptByteArray(ref passwordBytes); // Combine password and keyfile bytes passwordBytes = HashingAlgorithms.Blake2(passwordBytes, keyfileBytes); MemoryEncryption.EncryptByteArray(ref passwordBytes); Utilities.ZeroArray(keyfileBytes); } } return(passwordBytes); }
public static (byte[] encryptionKey, byte[] macKey) DeriveKeys(byte[] passwordBytes, byte[] salt, int iterations, int memorySize) { var argon2id = PasswordHash.ArgonAlgorithm.Argon_2ID13; MemoryEncryption.DecryptByteArray(ref passwordBytes); // Derive a 96 byte key byte[] derivedKey = PasswordHash.ArgonHashBinary(passwordBytes, salt, iterations, memorySize, Constants.Argon2KeySize, argon2id); // 256-bit encryption key byte[] encryptionKey = new byte[Constants.EncryptionKeySize]; Array.Copy(derivedKey, encryptionKey, encryptionKey.Length); // 512-bit MAC key byte[] macKey = new byte[Constants.MACKeySize]; Array.Copy(derivedKey, encryptionKey.Length, macKey, 0, macKey.Length); Utilities.ZeroArray(derivedKey); MemoryEncryption.EncryptByteArray(ref passwordBytes); MemoryEncryption.EncryptByteArray(ref encryptionKey); MemoryEncryption.EncryptByteArray(ref macKey); return(encryptionKey, macKey); }
private static byte[] ComputeFileHash(string encryptedFilePath, byte[] macKey) { try { byte[] computedHash = new byte[Constants.HashLength]; using (var fileStream = new FileStream(encryptedFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, Constants.FileBufferSize, FileOptions.SequentialScan)) { MemoryEncryption.DecryptByteArray(ref macKey); computedHash = HashingAlgorithms.Blake2(fileStream, macKey); MemoryEncryption.EncryptByteArray(ref macKey); } return(computedHash); } catch (Exception ex) when(ExceptionFilters.FileAccessExceptions(ex)) { Logging.LogException(ex.ToString(), Logging.Severity.High); DisplayMessage.ErrorResultsText(encryptedFilePath, ex.GetType().Name, "Unable to compute MAC."); return(null); } }
private static void DecryptFile(string filePath, int parametersLength, byte[] macBackup, byte[] encryptionKey, BackgroundWorker bgwDecryption) { try { string decryptedFilePath = Regex.Replace(filePath, Constants.EncryptedExtension, string.Empty); int headersLength = Constants.SaltLength + parametersLength; using (var plaintext = new FileStream(decryptedFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, Constants.FileBufferSize, FileOptions.SequentialScan)) using (var ciphertext = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, Constants.FileBufferSize, FileOptions.SequentialScan)) { // Skip the header bytes ciphertext.Seek(headersLength, SeekOrigin.Begin); byte[] fileBytes = FileHandling.GetBufferSize(ciphertext.Length); // Generate a counter starting at 0 byte[] counter = Generate.Counter(); int bytesRead; MemoryEncryption.DecryptByteArray(ref encryptionKey); while ((bytesRead = ciphertext.Read(fileBytes, 0, fileBytes.Length)) > 0) { byte[] decryptedBytes = StreamEncryption.DecryptXChaCha20(fileBytes, counter, encryptionKey); plaintext.Write(decryptedBytes, 0, bytesRead); counter = Sodium.Utilities.Increment(counter); // Report progress if decrypting a single file ReportProgress.ReportEncryptionProgress(plaintext.Position, ciphertext.Length, bgwDecryption); } Utilities.ZeroArray(encryptionKey); } CompleteDecryption(filePath, decryptedFilePath); } catch (Exception ex) when(ExceptionFilters.FileEncryptionExceptions(ex)) { Logging.LogException(ex.ToString(), Logging.Severity.High); DisplayMessage.ErrorResultsText(filePath, ex.GetType().Name, "Failed to backup the MAC. This data is required for decryption."); Utilities.ZeroArray(encryptionKey); RestoreMAC(filePath, macBackup); } }
private static void EncryptFile(string filePath, string encryptedFilePath, byte[] salt, byte[] encryptionKey, byte[] macKey, BackgroundWorker bgwEncryption) { try { using (var ciphertext = new FileStream(encryptedFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, Constants.FileBufferSize, FileOptions.SequentialScan)) using (var plaintext = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read, Constants.FileBufferSize, FileOptions.SequentialScan)) { WriteFileHeaders.WriteHeaders(ciphertext, salt); // Store headers length to correct percentage calculation long headersLength = ciphertext.Position; byte[] fileBytes = FileHandling.GetBufferSize(plaintext.Length); // Generate a counter starting at 0 byte[] counter = Generate.Counter(); int bytesRead; MemoryEncryption.DecryptByteArray(ref encryptionKey); while ((bytesRead = plaintext.Read(fileBytes, 0, fileBytes.Length)) > 0) { byte[] encryptedBytes = StreamEncryption.EncryptXChaCha20(fileBytes, counter, encryptionKey); ciphertext.Write(encryptedBytes, 0, bytesRead); counter = Sodium.Utilities.Increment(counter); // Report progress if encrypting a single file ReportProgress.ReportEncryptionProgress(ciphertext.Position, plaintext.Length + headersLength, bgwEncryption); } } Utilities.ZeroArray(encryptionKey); CompleteEncryption(filePath, encryptedFilePath, macKey); } catch (Exception ex) when(ExceptionFilters.FileEncryptionExceptions(ex)) { Logging.LogException(ex.ToString(), Logging.Severity.High); DisplayMessage.ErrorResultsText(filePath, ex.GetType().Name, "Unable to encrypt the file."); FileHandling.DeleteFile(encryptedFilePath); Utilities.ZeroArray(encryptionKey); Utilities.ZeroArray(macKey); } }
private static byte[] HashPasswordBytes(byte[] passwordBytes) { passwordBytes = HashingAlgorithms.Blake2(passwordBytes); MemoryEncryption.EncryptByteArray(ref passwordBytes); return(passwordBytes); }