public static void Initialize(string inputFilePath, string outputFilePath, byte[] keyEncryptionKey) { byte[] dataEncryptionKey = new byte[Constants.EncryptionKeyLength]; try { byte[] encryptedHeader = FileHeaders.ReadEncryptedHeader(inputFilePath); byte[] nonce = FileHeaders.ReadNonce(inputFilePath); byte[] header = DecryptFileHeader(inputFilePath, encryptedHeader, nonce, keyEncryptionKey); if (header == null) { throw new ArgumentException("Incorrect password/keyfile or this file has been tampered with."); } ChunkHandling.ValidateKeyCommitmentBlock(header); int lastChunkLength = FileHeaders.GetLastChunkLength(header); int fileNameLength = FileHeaders.GetFileNameLength(header); dataEncryptionKey = FileHeaders.GetDataEncryptionKey(header); Utilities.ZeroArray(header); using (var inputFile = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, Constants.FileStreamBufferSize, FileOptions.SequentialScan)) using (var outputFile = new FileStream(outputFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, Constants.FileStreamBufferSize, FileOptions.SequentialScan)) { nonce = Sodium.Utilities.Increment(nonce); byte[] additionalData = ChunkHandling.GetPreviousPoly1305Tag(encryptedHeader); Decrypt(inputFile, outputFile, nonce, dataEncryptionKey, additionalData, lastChunkLength); } Finalize(inputFilePath, outputFilePath, fileNameLength); } catch (Exception ex) when(ExceptionFilters.Cryptography(ex)) { Utilities.ZeroArray(dataEncryptionKey); throw; } }
private static byte[] EncryptFileHeader(string inputFilePath, byte[] dataEncryptionKey, byte[] nonce, byte[] keyEncryptionKey) { byte[] keyCommitmentBlock = ChunkHandling.GetKeyCommitmentBlock(); long fileLength = FileHandling.GetFileLength(inputFilePath); byte[] lastChunkLength = BitConverter.GetBytes(Convert.ToInt32(fileLength % Constants.FileChunkSize)); byte[] fileNameLength = FileHeaders.GetFileNameLength(inputFilePath); byte[] fileHeader = Utilities.ConcatArrays(keyCommitmentBlock, lastChunkLength, fileNameLength, dataEncryptionKey); byte[] additionalData = HeaderEncryption.ComputeAdditionalData(fileLength); return(HeaderEncryption.Encrypt(fileHeader, nonce, keyEncryptionKey, additionalData)); }
private static void Encrypt(FileStream inputFile, FileStream outputFile, byte[] nonce, byte[] dataEncryptionKey, byte[] additionalData) { const int offset = 0; byte[] plaintextChunk = new byte[Constants.FileChunkSize]; while (inputFile.Read(plaintextChunk, offset, plaintextChunk.Length) > 0) { byte[] ciphertextChunk = XChaCha20BLAKE2b.Encrypt(plaintextChunk, nonce, dataEncryptionKey, additionalData, TagLength.Medium); nonce = Utilities.Increment(nonce); additionalData = ChunkHandling.GetPreviousTag(ciphertextChunk); outputFile.Write(ciphertextChunk, offset, ciphertextChunk.Length); } CryptographicOperations.ZeroMemory(dataEncryptionKey); }
public static byte[] Encrypt(byte[] passwordBytes, byte[] privateKey, byte[] keyAlgorithm) { byte[] salt = Generate.Salt(); byte[] key = Argon2.DeriveKey(passwordBytes, salt); Utilities.ZeroArray(passwordBytes); byte[] nonce = Generate.Nonce(); byte[] additionalData = Utilities.ConcatArrays(keyAlgorithm, Constants.PrivateKeyVersion); byte[] keyCommitmentBlock = ChunkHandling.GetKeyCommitmentBlock(); privateKey = Utilities.ConcatArrays(keyCommitmentBlock, privateKey); byte[] encryptedPrivateKey = SecretAeadXChaCha20Poly1305.Encrypt(privateKey, nonce, key, additionalData); Utilities.ZeroArray(privateKey); Utilities.ZeroArray(key); return(Utilities.ConcatArrays(additionalData, salt, nonce, encryptedPrivateKey)); }
private static void Encrypt(FileStream inputFile, FileStream outputFile, byte[] nonce, byte[] dataEncryptionKey, byte[] additionalData) { const int offset = 0; byte[] plaintext = new byte[Constants.FileChunkSize]; while (inputFile.Read(plaintext, offset, plaintext.Length) > 0) { byte[] plaintextChunk = ChunkHandling.PrependKeyCommitmentBlock(plaintext); byte[] ciphertextChunk = SecretAeadXChaCha20Poly1305.Encrypt(plaintextChunk, nonce, dataEncryptionKey, additionalData); nonce = Sodium.Utilities.Increment(nonce); additionalData = ChunkHandling.GetPreviousPoly1305Tag(ciphertextChunk); outputFile.Write(ciphertextChunk, offset, ciphertextChunk.Length); } Utilities.ZeroArray(dataEncryptionKey); }
private static byte[] Decrypt(byte[] passwordBytes, byte[] privateKey) { byte[] keyAlgorithm = GetKeyAlgorithm(privateKey); byte[] keyVersion = GetKeyVersion(privateKey); byte[] salt = GetSalt(privateKey); byte[] nonce = GetNonce(privateKey); byte[] additionalData = Utilities.ConcatArrays(keyAlgorithm, keyVersion); byte[] encryptedPrivateKey = GetEncryptedPrivateKey(privateKey); byte[] key = Argon2.DeriveKey(passwordBytes, salt); Utilities.ZeroArray(passwordBytes); byte[] decryptedPrivateKey = SecretAeadXChaCha20Poly1305.Decrypt(encryptedPrivateKey, nonce, key, additionalData); Utilities.ZeroArray(key); ChunkHandling.ValidateKeyCommitmentBlock(decryptedPrivateKey); return(ChunkHandling.RemoveKeyCommitmentBlock(decryptedPrivateKey)); }
private static void Decrypt(FileStream inputFile, FileStream outputFile, byte[] nonce, byte[] dataEncryptionKey, byte[] additionalData, int lastChunkLength) { inputFile.Seek(Constants.FileHeadersLength, SeekOrigin.Begin); const int offset = 0; byte[] ciphertextChunk = new byte[Constants.TotalChunkLength]; while (inputFile.Read(ciphertextChunk, offset, ciphertextChunk.Length) > 0) { byte[] plaintextChunk = XChaCha20BLAKE2b.Decrypt(ciphertextChunk, nonce, dataEncryptionKey, additionalData, TagLength.Medium); nonce = Utilities.Increment(nonce); additionalData = ChunkHandling.GetPreviousTag(ciphertextChunk); outputFile.Write(plaintextChunk, offset, plaintextChunk.Length); } outputFile.SetLength(outputFile.Length - Constants.FileChunkSize + lastChunkLength); CryptographicOperations.ZeroMemory(dataEncryptionKey); }
private static void Decrypt(FileStream inputFile, FileStream outputFile, byte[] nonce, byte[] dataEncryptionKey, byte[] additionalData, int lastChunkLength) { int headersLength = FileHeaders.GetHeadersLength(); inputFile.Seek(headersLength, SeekOrigin.Begin); const int offset = 0; byte[] ciphertextChunk = new byte[Constants.TotalChunkLength]; while (inputFile.Read(ciphertextChunk, offset, ciphertextChunk.Length) > 0) { byte[] plaintextChunk = SecretAeadXChaCha20Poly1305.Decrypt(ciphertextChunk, nonce, dataEncryptionKey, additionalData); ChunkHandling.ValidateKeyCommitmentBlock(plaintextChunk); nonce = Sodium.Utilities.Increment(nonce); additionalData = ChunkHandling.GetPreviousPoly1305Tag(ciphertextChunk); plaintextChunk = ChunkHandling.RemoveKeyCommitmentBlock(plaintextChunk); outputFile.Write(plaintextChunk, offset, plaintextChunk.Length); } outputFile.SetLength((outputFile.Length - Constants.FileChunkSize) + lastChunkLength); Utilities.ZeroArray(dataEncryptionKey); }
public static void Initialize(FileStream inputFile, string outputFilePath, byte[] ephemeralPublicKey, byte[] keyEncryptionKey) { var dataEncryptionKey = new byte[Constants.EncryptionKeyLength]; try { byte[] encryptedHeader = FileHeaders.ReadEncryptedHeader(inputFile); byte[] nonce = FileHeaders.ReadNonce(inputFile); byte[] header = DecryptFileHeader(inputFile, ephemeralPublicKey, encryptedHeader, nonce, keyEncryptionKey); if (header == null) { throw new ArgumentException("Incorrect password/key or this file has been tampered with."); } int lastChunkLength = FileHeaders.GetLastChunkLength(header); int fileNameLength = FileHeaders.GetFileNameLength(header); dataEncryptionKey = FileHeaders.GetDataEncryptionKey(header); CryptographicOperations.ZeroMemory(header); using (var outputFile = new FileStream(outputFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, Constants.FileStreamBufferSize, FileOptions.SequentialScan)) { nonce = Utilities.Increment(nonce); byte[] additionalData = ChunkHandling.GetPreviousTag(encryptedHeader); Decrypt(inputFile, outputFile, nonce, dataEncryptionKey, additionalData, lastChunkLength); } string inputFilePath = inputFile.Name; inputFile.Dispose(); Finalize(inputFilePath, outputFilePath, fileNameLength); } catch (Exception ex) when(ExceptionFilters.Cryptography(ex)) { CryptographicOperations.ZeroMemory(dataEncryptionKey); if (!(ex is ArgumentException)) { FileHandling.DeleteFile(outputFilePath); } throw; } }
public static void Initialize(string inputFilePath, string outputFilePath, byte[] ephemeralPublicKey, byte[] salt, byte[] keyEncryptionKey) { byte[] dataEncryptionKey = Generate.DataEncryptionKey(); try { using (var inputFile = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, Constants.FileStreamBufferSize, FileOptions.SequentialScan)) using (var outputFile = new FileStream(outputFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read, Constants.FileStreamBufferSize, FileOptions.SequentialScan)) { byte[] nonce = Generate.Nonce(); byte[] encryptedHeader = EncryptFileHeader(inputFilePath, dataEncryptionKey, nonce, keyEncryptionKey); FileHeaders.WriteHeaders(outputFile, ephemeralPublicKey, salt, nonce, encryptedHeader); nonce = Sodium.Utilities.Increment(nonce); byte[] additionalData = ChunkHandling.GetPreviousPoly1305Tag(encryptedHeader); Encrypt(inputFile, outputFile, nonce, dataEncryptionKey, additionalData); } Finalize(inputFilePath, outputFilePath); } catch (Exception ex) when(ExceptionFilters.Cryptography(ex)) { FileHandling.DeleteFile(outputFilePath); Utilities.ZeroArray(dataEncryptionKey); throw; } }