Пример #1
0
 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;
     }
 }
Пример #2
0
        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));
        }
Пример #3
0
        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);
        }
Пример #4
0
 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));
 }
Пример #5
0
        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);
        }
Пример #6
0
 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));
 }
Пример #7
0
        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);
        }
Пример #8
0
        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);
        }
Пример #9
0
        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;
            }
        }
Пример #10
0
 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;
     }
 }