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); }
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); }