private void DecryptAttachment(SignalServiceAttachmentPointer pointer, Stream ciphertextFileStream, Stream plaintextFileStream)
        {
            byte[] buf = new byte[32];
            Stream s   = AttachmentCipherInputStream.CreateFor(ciphertextFileStream, pointer.Size != null ? pointer.Size.Value : 0, pointer.Key, pointer.Digest);

            s.CopyTo(plaintextFileStream);
        }
        /// <summary>
        /// Retrieves a SignalServiceAttachment
        /// </summary>
        /// <param name="token"></param>
        /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
        /// received in a <see cref="SignalServiceDataMessage"/></param>
        /// <param name="tmpCipherDestination">The temporary destination for this attachment before decryption</param>
        /// <param name="maxSizeBytes">The maximum size for this attachment (not yet implemented)</param>
        /// <param name="listener">An optional listener (may be null) to receive callbacks on download progress.</param>
        public async Task <Stream> RetrieveAttachment(CancellationToken token, SignalServiceAttachmentPointer pointer, Stream tmpCipherDestination, int maxSizeBytes, IProgressListener listener)
        {
            await Socket.RetrieveAttachment(token, pointer.Id, tmpCipherDestination, maxSizeBytes);

            tmpCipherDestination.Position = 0;
            return(AttachmentCipherInputStream.CreateFor(tmpCipherDestination, pointer.Size != null ? pointer.Size.Value : 0, pointer.Key, pointer.Digest));
        }
        /// <summary>
        /// Retrieves a <see cref="SignalServiceStickerManifest"/>.
        /// </summary>
        /// <param name="packId">The 16-byte packId that identifies the sticker pack.</param>
        /// <param name="packKey">The 32-byte packKey that decrypts the sticker pack.</param>
        /// <param name="token">Cancellation token, may be null.</param>
        /// <returns>The <see cref="SignalServiceStickerManifest"/> representing the sticker pack.</returns>
        /// <exception cref="IOException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        public async Task <SignalServiceStickerManifest> RetrieveStickerManifestAsync(byte[] packId, byte[] packKey, CancellationToken?token = null)
        {
            if (token == null)
            {
                token = CancellationToken.None;
            }

            byte[] manifestBytes = await socket.RetrieveStickerManifestAsync(packId, token);

            Stream       cipherStream = AttachmentCipherInputStream.CreateForStickerData(manifestBytes, packKey);
            MemoryStream outputStream = new MemoryStream();

            Util.Copy(cipherStream, outputStream);

            sticker.Pack pack = sticker.Pack.Parser.ParseFrom(outputStream.ToArray());
            List <SignalServiceStickerManifest.StickerInfo> stickers = new List <SignalServiceStickerManifest.StickerInfo>(pack.Stickers.Count);

            SignalServiceStickerManifest.StickerInfo?cover = pack.Cover != null ? new SignalServiceStickerManifest.StickerInfo((int)pack.Cover.Id, pack.Cover.Emoji) : null;

            foreach (sticker.Pack.Types.Sticker sticker in pack.Stickers)
            {
                stickers.Add(new SignalServiceStickerManifest.StickerInfo((int)sticker.Id, sticker.Emoji));
            }

            return(new SignalServiceStickerManifest(pack.Title, pack.Author, cover, stickers));
        }
        public void Test_Attachment_DecryptFailOnBadKey()
        {
            string?cipherFile          = null;
            bool   hitCorrectException = false;

            try
            {
                byte[]        key            = Util.GetSecretBytes(64);
                byte[]        plaintextInput = Encoding.UTF8.GetBytes("Gwen Stacy");
                EncryptResult encryptResult  = EncryptData(plaintextInput, key);
                byte[]        badKey         = new byte[64];

                cipherFile = WriteToFile(encryptResult.ciphertext);

                using FileStream fileStream = File.Open(cipherFile, FileMode.Open);
                AttachmentCipherInputStream.CreateForAttachment(fileStream, plaintextInput.Length, badKey, encryptResult.digest);
            }
            catch (InvalidMessageException)
            {
                hitCorrectException = true;
            }
            finally
            {
                if (cipherFile != null)
                {
                    DeleteFile(cipherFile);
                }
            }

            Assert.IsTrue(hitCorrectException);
        }
        public void Test_Sticker_EncryptDecryptEmpty()
        {
            byte[]        packKey        = Util.GetSecretBytes(32);
            byte[]        plaintextInput = Encoding.UTF8.GetBytes(string.Empty);
            EncryptResult encryptResult  = EncryptData(plaintextInput, ExpandPackKey(packKey));

            using Stream inputStream = AttachmentCipherInputStream.CreateForStickerData(encryptResult.ciphertext, packKey);
            byte[] plaintextOutput = ReadInputStreamFully(inputStream);

            CollectionAssert.AreEqual(plaintextInput, plaintextOutput);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="packId"></param>
        /// <param name="packKey"></param>
        /// <param name="stickerId"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        /// <exception cref="IOException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        public async Task <Stream> RetrieveStickerAsync(byte[] packId, byte[] packKey, int stickerId, CancellationToken?token = null)
        {
            if (token == null)
            {
                token = CancellationToken.None;
            }

            byte[] data = await socket.RetrieveStickerAsync(packId, stickerId, token);

            return(AttachmentCipherInputStream.CreateForStickerData(data, packKey));
        }
        public void Test_Attachment_EncryptDecryptEmpty()
        {
            byte[]        key            = Util.GetSecretBytes(64);
            byte[]        plaintextInput = Encoding.UTF8.GetBytes(string.Empty);
            EncryptResult encryptResult  = EncryptData(plaintextInput, key);
            string        cipherFile     = WriteToFile(encryptResult.ciphertext);

            using Stream inputStream = AttachmentCipherInputStream.CreateForAttachment(File.Open(cipherFile, FileMode.Open), plaintextInput.Length, key, encryptResult.digest);
            byte[] plaintextOutput = ReadInputStreamFully(inputStream);

            CollectionAssert.AreEqual(plaintextInput, plaintextOutput);

            DeleteFile(cipherFile);
        }
示例#8
0
        private async Task <AttachmentPointer> CreateAttachmentPointer(CancellationToken token, SignalServiceAttachmentStream attachment)
        {
            byte[]             attachmentKey    = Util.GetSecretBytes(64);
            long               paddedLength     = PaddingInputStream.GetPaddedSize(attachment.Length);
            long               ciphertextLength = AttachmentCipherInputStream.GetCiphertextLength(paddedLength);
            PushAttachmentData attachmentData   = new PushAttachmentData(attachment.ContentType,
                                                                         new PaddingInputStream(attachment.InputStream, attachment.Length),
                                                                         ciphertextLength,
                                                                         new AttachmentCipherOutputStreamFactory(attachmentKey),
                                                                         attachment.Listener);

            (ulong id, byte[] digest) = await socket.SendAttachment(token, attachmentData);

            var attachmentPointer = new AttachmentPointer
            {
                ContentType = attachment.ContentType,
                Id          = id,
                Key         = ByteString.CopyFrom(attachmentKey),
                Digest      = ByteString.CopyFrom(digest),
                Size        = (uint)attachment.Length
            };

            if (attachment.FileName != null)
            {
                attachmentPointer.FileName = attachment.FileName;
            }

            if (attachment.Preview != null)
            {
                attachmentPointer.Thumbnail = ByteString.CopyFrom(attachment.Preview);
            }

            if (attachment.Width > 0)
            {
                attachmentPointer.Width = (uint)attachment.Width;
            }

            if (attachment.Height > 0)
            {
                attachmentPointer.Height = (uint)attachment.Height;
            }

            if (attachment.VoiceNote)
            {
                attachmentPointer.Flags = (uint)AttachmentPointer.Types.Flags.VoiceMessage;
            }

            return(attachmentPointer);
        }
        /// <summary>
        /// Retrieves a SignalServiceAttachment
        /// </summary>
        /// <param name="pointer">The <see cref="SignalServiceAttachmentPointer"/>
        /// received in a <see cref="SignalServiceDataMessage"/></param>
        /// <param name="destination">The download destination for this attachment.</param>
        /// <param name="maxSizeBytes"></param>
        /// <param name="listener">An optional listener (may be null) to receive callbacks on download progress.</param>
        /// <param name="token"></param>
        /// <exception cref="IOException"></exception>
        /// <exception cref="InvalidMessageException"></exception>
        public async Task <Stream> RetrieveAttachmentAsync(SignalServiceAttachmentPointer pointer, Stream destination, int maxSizeBytes, IProgressListener?listener, CancellationToken?token = null)
        {
            if (token == null)
            {
                token = CancellationToken.None;
            }

            if (pointer.Digest == null)
            {
                throw new InvalidMessageException("No attachment digest!");
            }

            await socket.RetrieveAttachmentAsync(pointer.CdnNumber, pointer.RemoteId, destination, maxSizeBytes, listener, token);

            destination.Position = 0;
            return(AttachmentCipherInputStream.CreateForAttachment(destination, pointer.Size != null ? pointer.Size.Value : 0, pointer.Key, pointer.Digest));
        }
        public void Test_Attachment_EncryptDecryptMultipleTimes()
        {
            // Test that the file passed to AttachmentCipherInputStream can be reused.
            byte[]        key            = Util.GetSecretBytes(64);
            byte[]        plaintextInput = Encoding.UTF8.GetBytes("Peter Parker");
            EncryptResult encryptResult  = EncryptData(plaintextInput, key);
            string        cipherFile     = WriteToFile(encryptResult.ciphertext);

            for (int i = 0; i < 10; i++)
            {
                using Stream inputStream = AttachmentCipherInputStream.CreateForAttachment(File.Open(cipherFile, FileMode.Open), plaintextInput.Length, key, encryptResult.digest);
                byte[] plaintextOutput = ReadInputStreamFully(inputStream);

                CollectionAssert.AreEqual(plaintextInput, plaintextOutput);
            }

            DeleteFile(cipherFile);
        }
        public void Test_Sticker_DecryptFailOnBadKey()
        {
            bool hitCorrectException = false;

            try
            {
                byte[]        packKey        = Util.GetSecretBytes(32);
                byte[]        plaintextInput = Encoding.UTF8.GetBytes("Gwen Stacy");
                EncryptResult encryptResult  = EncryptData(plaintextInput, ExpandPackKey(packKey));
                byte[]        badPackKey     = new byte[32];

                AttachmentCipherInputStream.CreateForStickerData(encryptResult.ciphertext, badPackKey);
            }
            catch (InvalidMessageException)
            {
                hitCorrectException = true;
            }

            Assert.IsTrue(hitCorrectException);
        }
        public void Test_Sticker_DecryptFailOnBadMac()
        {
            bool hitCorrectException = false;

            try
            {
                byte[]        packKey          = Util.GetSecretBytes(32);
                byte[]        plaintextInput   = Encoding.UTF8.GetBytes("Uncle Ben");
                EncryptResult encryptResult    = EncryptData(plaintextInput, ExpandPackKey(packKey));
                byte[]        badMacCiphertext = new byte[encryptResult.ciphertext.Length];
                Array.Copy(encryptResult.ciphertext, badMacCiphertext, badMacCiphertext.Length);

                badMacCiphertext[badMacCiphertext.Length - 1] = 0;

                AttachmentCipherInputStream.CreateForStickerData(badMacCiphertext, packKey);
            }
            catch (InvalidMessageException)
            {
                hitCorrectException = true;
            }

            Assert.IsTrue(hitCorrectException);
        }