public async Task <Node> CreateFolder(string name, Node parent, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (parent == null) { throw new ArgumentNullException("parent"); } if (parent.Type == NodeType.File) { throw new ArgumentException("Invalid parent node"); } //this.EnsureLoggedIn(); var key = Crypto.CreateAesKey(); byte[] attributes = EncryptAttributes(new Attributes(name), key); byte[] encryptedKey = Crypto.EncryptAes(key, this._masterKey); CreateNodeRequest request = CreateNodeRequest.CreateFolderNodeRequest(parent, attributes.ToBase64(), encryptedKey.ToBase64()); GetNodesResponse response = await Post <CreateNodeRequest, GetNodesResponse>(request, cancellationToken); var node = response.Nodes[0]; DecriptNode(node, response); return(node); }
private void DecriptNode(Node node, GetNodesResponse response) { node.LastModificationDate = Node.OriginalDateTime.AddSeconds(node.SerializedLastModificationDate).ToLocalTime(); if (node.Type == NodeType.File || node.Type == NodeType.Directory) { string serializedKey = node.SerializedKey; int splitPosition = serializedKey.IndexOf(":"); byte[] encryptedKey = serializedKey.Substring(splitPosition + 1).FromBase64(); var decryptedKey = Crypto.DecryptKey(encryptedKey, _masterKey); node.Key = decryptedKey; // If node is shared, we need to retrieve shared masterkey if (response.SharedKeys != null) { string owner = splitPosition > -1 ? serializedKey.Substring(0, splitPosition) : serializedKey; var sharedKey = response.SharedKeys.FirstOrDefault(x => x.Id == owner); if (sharedKey != null) { var masterKey = Crypto.DecryptKey(sharedKey.Key.FromBase64(), _masterKey); if (node.Type == NodeType.Directory) { decryptedKey = masterKey; } node.Key = Crypto.DecryptKey(encryptedKey, masterKey); } } if (node.Type == NodeType.File) { // Extract Iv and MetaMac byte[] iv = new byte[8]; byte[] metaMac = new byte[8]; Array.Copy(decryptedKey, 16, iv, 0, 8); Array.Copy(decryptedKey, 24, metaMac, 0, 8); node.Iv = iv; node.MetaMac = metaMac; // For files, key is 256 bits long. Compute the key to retrieve 128 AES key node.Key = new byte[16]; for (int idx = 0; idx < 16; idx++) { node.Key[idx] = (byte)(decryptedKey[idx] ^ decryptedKey[idx + 16]); } } Attributes attributes = DecryptAttributes(node.SerializedAttributes.FromBase64(), node.Key); node.Name = attributes.Name; } //if (this._trashNode == null) //{ // this._trashNode = nodes.First(n => n.Type == NodeType.Trash); //} }
/// <summary> /// Retrieve all filesystem nodes /// </summary> /// <returns>Flat representation of all the filesystem nodes</returns> /// <exception cref="NotSupportedException">Not logged in</exception> /// <exception cref="ApiException">Mega.co.nz service reports an error</exception> public async Task <IEnumerable <Node> > GetNodes(CancellationToken cancellationToken) { //this.EnsureLoggedIn(); GetNodesRequest request = new GetNodesRequest(); GetNodesResponse response = await Post <GetNodesRequest, GetNodesResponse>(request, cancellationToken); Node[] nodes = response.Nodes; foreach (var node in nodes) { DecriptNode(node, response); } return(nodes); }
public async Task <Node> Upload(Stream fileContent, string name, Node parent, IProgress <StreamProgress> progress, CancellationToken cancellationToken) { if (fileContent == null) { throw new ArgumentNullException("fileContent"); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (parent == null) { throw new ArgumentNullException("parent"); } if (parent.Type == NodeType.File) { throw new ArgumentException("Invalid parent node"); } //this.EnsureLoggedIn(); // Retrieve upload URL var length = fileContent.GetLength(); if (!length.HasValue) { fileContent = new MemoryStream(await fileContent.ReadAsBufferAsync(cancellationToken)); length = fileContent.GetLength(); } UploadUrlRequest uploadRequest = new UploadUrlRequest(length.Value); UploadUrlResponse uploadResponse = await Post <UploadUrlRequest, UploadUrlResponse>(uploadRequest, cancellationToken); var megaStream = new MegaEncryptStream(fileContent); string completionHandle; try { completionHandle = await PostRaw(new Uri(uploadResponse.Url), megaStream, progress, cancellationToken); } finally { megaStream.Dispose(); } // Encrypt attributes byte[] cryptedAttributes = EncryptAttributes(new Attributes(name), megaStream.FileKey); // Compute the file key byte[] fileKey = new byte[32]; for (int i = 0; i < 8; i++) { fileKey[i] = (byte)(megaStream.FileKey[i] ^ megaStream.IV[i]); fileKey[i + 16] = megaStream.IV[i]; } for (int i = 8; i < 16; i++) { fileKey[i] = (byte)(megaStream.FileKey[i] ^ megaStream.MetaMac[i - 8]); fileKey[i + 16] = megaStream.MetaMac[i - 8]; } byte[] encryptedKey = Crypto.EncryptKey(fileKey, this._masterKey); CreateNodeRequest createNodeRequest = CreateNodeRequest.CreateFileNodeRequest(parent, cryptedAttributes.ToBase64(), encryptedKey.ToBase64(), completionHandle); GetNodesResponse createNodeResponse = await Post <CreateNodeRequest, GetNodesResponse>(createNodeRequest, cancellationToken); var node = createNodeResponse.Nodes[0]; DecriptNode(node, createNodeResponse); return(node); }