diff --git a/MegaApiClient/Cryptography/Crypto.cs b/MegaApiClient/Cryptography/Crypto.cs index 978f822..4862da0 100644 --- a/MegaApiClient/Cryptography/Crypto.cs +++ b/MegaApiClient/Cryptography/Crypto.cs @@ -38,12 +38,14 @@ public static byte[] DecryptKey(byte[] data, byte[] key) public static byte[] EncryptKey(byte[] data, byte[] key) { byte[] result = new byte[data.Length]; - - for (int idx = 0; idx < data.Length; idx += 16) + using (var encryptor = CreateAesEncryptor(key)) { - byte[] block = data.CopySubArray(16, idx); - byte[] encryptedBlock = EncryptAes(block, key); - Array.Copy(encryptedBlock, 0, result, idx, 16); + for (int idx = 0; idx < data.Length; idx += 16) + { + byte[] block = data.CopySubArray(16, idx); + byte[] encryptedBlock = EncryptAes(block, encryptor); + Array.Copy(encryptedBlock, 0, result, idx, 16); + } } return result; @@ -77,9 +79,19 @@ public static byte[] DecryptAes(byte[] data, byte[] key) } } + public static ICryptoTransform CreateAesEncryptor(byte[] key) + { + return AesCbc.CreateEncryptor(key, DefaultIv); + } + + public static byte[] EncryptAes(byte[] data, ICryptoTransform encryptor) + { + return encryptor.TransformFinalBlock(data, 0, data.Length); + } + public static byte[] EncryptAes(byte[] data, byte[] key) { - using (ICryptoTransform encryptor = AesCbc.CreateEncryptor(key, DefaultIv)) + using (ICryptoTransform encryptor = CreateAesEncryptor(key)) { return encryptor.TransformFinalBlock(data, 0, data.Length); } diff --git a/MegaApiClient/MegaApiClient.cs b/MegaApiClient/MegaApiClient.cs index 6c0d759..5a100ac 100644 --- a/MegaApiClient/MegaApiClient.cs +++ b/MegaApiClient/MegaApiClient.cs @@ -909,9 +909,12 @@ private static string GenerateHash(string email, byte[] passwordAesKey) } // Encrypt hash using password key - for (int it = 0; it < 16384; it++) + using (var encryptor = Crypto.CreateAesEncryptor(passwordAesKey)) { - hash = Crypto.EncryptAes(hash, passwordAesKey); + for (int it = 0; it < 16384; it++) + { + hash = Crypto.EncryptAes(hash, encryptor); + } } // Retrieve bytes 0-4 and 8-12 from the hash diff --git a/MegaApiClient/MegaApiClient.csproj b/MegaApiClient/MegaApiClient.csproj index 2cd86b0..aa80385 100644 --- a/MegaApiClient/MegaApiClient.csproj +++ b/MegaApiClient/MegaApiClient.csproj @@ -25,6 +25,9 @@ true true true + false + false + false @@ -88,6 +91,7 @@ + diff --git a/MegaApiClient/Stream/MegaAesCtrStream.cs b/MegaApiClient/Stream/MegaAesCtrStream.cs index 9628f34..1fa4b3a 100644 --- a/MegaApiClient/Stream/MegaAesCtrStream.cs +++ b/MegaApiClient/Stream/MegaAesCtrStream.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; + using System.Security.Cryptography; internal class MegaAesCtrStreamCrypter : MegaAesCtrStream { @@ -70,8 +71,9 @@ internal abstract class MegaAesCtrStream : Stream private readonly Stream stream; private readonly Mode mode; - private readonly long[] chunksPositions; + private readonly HashSet chunksPositionsCache; private readonly byte[] counter = new byte[8]; + private readonly ICryptoTransform encryptor; private long currentCounter = 0; private byte[] currentChunkMac = new byte[16]; private byte[] fileMac = new byte[16]; @@ -99,7 +101,16 @@ protected MegaAesCtrStream(Stream stream, long streamLength, Mode mode, byte[] f this.fileKey = fileKey; this.iv = iv; - this.chunksPositions = this.GetChunksPositions(this.streamLength); + this.ChunksPositions = this.GetChunksPositions(this.streamLength).ToArray(); + this.chunksPositionsCache = new HashSet(this.ChunksPositions); + + this.encryptor = Crypto.CreateAesEncryptor(this.fileKey); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + this.encryptor.Dispose(); } protected enum Mode @@ -108,10 +119,7 @@ protected enum Mode Decrypt } - public long[] ChunksPositions - { - get { return this.chunksPositions; } - } + public long[] ChunksPositions { get; } public override bool CanRead { @@ -159,12 +167,12 @@ public override int Read(byte[] buffer, int offset, int count) for (long pos = this.position; pos < Math.Min(this.position + count, this.streamLength); pos += 16) { // We are on a chunk bondary - if (this.chunksPositions.Any(chunk => chunk == pos)) + if (this.chunksPositionsCache.Contains(pos)) { if (pos != 0) { // Compute the current chunk mac data on each chunk bondary - this.ComputeChunk(); + this.ComputeChunk(encryptor); } // Init chunk mac with Iv values @@ -192,7 +200,7 @@ public override int Read(byte[] buffer, int offset, int count) Array.Copy(this.iv, ivCounter, 8); Array.Copy(this.counter, 0, ivCounter, 8, 8); - byte[] encryptedIvCounter = Crypto.EncryptAes(ivCounter, this.fileKey); + byte[] encryptedIvCounter = Crypto.EncryptAes(ivCounter, encryptor); for (int inputPos = 0; inputPos < inputLength; inputPos++) { @@ -204,7 +212,7 @@ public override int Read(byte[] buffer, int offset, int count) Array.Copy(output, 0, buffer, (int)(offset + pos - this.position), (int)Math.Min(output.Length, this.streamLength - pos)); // Crypt to current chunk mac - this.currentChunkMac = Crypto.EncryptAes(this.currentChunkMac, this.fileKey); + this.currentChunkMac = Crypto.EncryptAes(this.currentChunkMac, encryptor); } long len = Math.Min(count, this.streamLength - this.position); @@ -213,7 +221,7 @@ public override int Read(byte[] buffer, int offset, int count) // When stream is fully processed, we compute the last chunk if (this.position == this.streamLength) { - this.ComputeChunk(); + this.ComputeChunk(encryptor); // Compute Meta MAC for (int i = 0; i < 4; i++) @@ -263,35 +271,32 @@ private void IncrementCounter() Array.Copy(counter, this.counter, 8); } - private void ComputeChunk() + private void ComputeChunk(ICryptoTransform encryptor) { for (int i = 0; i < 16; i++) { this.fileMac[i] ^= this.currentChunkMac[i]; } - this.fileMac = Crypto.EncryptAes(this.fileMac, this.fileKey); + this.fileMac = Crypto.EncryptAes(this.fileMac, encryptor); } - private long[] GetChunksPositions(long size) + private IEnumerable GetChunksPositions(long size) { - List chunks = new List(); - chunks.Add(0); + yield return 0; long chunkStartPosition = 0; for (int idx = 1; (idx <= 8) && (chunkStartPosition < (size - (idx * 131072))); idx++) { chunkStartPosition += idx * 131072; - chunks.Add(chunkStartPosition); + yield return chunkStartPosition; } while ((chunkStartPosition + 1048576) < size) { chunkStartPosition += 1048576; - chunks.Add(chunkStartPosition); + yield return chunkStartPosition; } - - return chunks.ToArray(); } } } diff --git a/tools/packages.config b/tools/packages.config new file mode 100644 index 0000000..85fc75c --- /dev/null +++ b/tools/packages.config @@ -0,0 +1,4 @@ + + + +