Example #1
0
        /// <summary>
        /// Downloads a <see cref="PayloadReference"/> that is referenced from an incoming inbox item.
        /// </summary>
        /// <param name="inboxItem">The inbox item that referenced the <see cref="PayloadReference"/>.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task representing the asynchronous operation.</returns>
        protected virtual async Task<PayloadReference> DownloadPayloadReferenceAsync(IncomingList.IncomingItem inboxItem, CancellationToken cancellationToken)
        {
            Requires.NotNull(inboxItem, "inboxItem");

            var responseMessage = await this.HttpClient.GetAsync(inboxItem.Location, cancellationToken).ConfigureAwait(false);
            if (responseMessage.StatusCode == HttpStatusCode.NotFound)
            {
                // delete inbox item and move on.
                await this.DeletePayloadReferenceAsync(inboxItem.Location, cancellationToken).ConfigureAwait(false);
                this.Log("Missing payload reference.", null);
                return null;
            }

            responseMessage.EnsureSuccessStatusCode();
            var responseStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false);
            var responseStreamCopy = new MemoryStream();
            await responseStream.CopyToAsync(responseStreamCopy, 4096, cancellationToken).ConfigureAwait(false);
            responseStreamCopy.Position = 0;

            var encryptedKey = await responseStreamCopy.ReadSizeAndBufferAsync(cancellationToken).ConfigureAwait(false);
            var key = WinRTCrypto.CryptographicEngine.Decrypt(this.Endpoint.EncryptionKey, encryptedKey);
            var iv = await responseStreamCopy.ReadSizeAndBufferAsync(cancellationToken).ConfigureAwait(false);
            var ciphertextStream = await responseStreamCopy.ReadSizeAndStreamAsync(cancellationToken).ConfigureAwait(false);
            var encryptedVariables = new SymmetricEncryptionVariables(key, iv);

            var plainTextPayloadStream = new MemoryStream();
            await this.CryptoServices.DecryptAsync(ciphertextStream, plainTextPayloadStream, encryptedVariables, cancellationToken).ConfigureAwait(false);

            plainTextPayloadStream.Position = 0;
            AsymmetricAlgorithm? signingHashAlgorithm = null;   //// Encoding.UTF8.GetString(await plainTextPayloadStream.ReadSizeAndBufferAsync(cancellationToken));
            byte[] signature = await plainTextPayloadStream.ReadSizeAndBufferAsync(cancellationToken).ConfigureAwait(false);
            long payloadStartPosition = plainTextPayloadStream.Position;
            var signedBytes = new byte[plainTextPayloadStream.Length - plainTextPayloadStream.Position];
            await plainTextPayloadStream.ReadAsync(signedBytes, 0, signedBytes.Length).ConfigureAwait(false);
            plainTextPayloadStream.Position = payloadStartPosition;
            var plainTextPayloadReader = new BinaryReader(plainTextPayloadStream);

            var recipientPublicSigningKeyBuffer = plainTextPayloadReader.ReadSizeAndBuffer();

            var creationDateUtc = DateTime.FromBinary(plainTextPayloadReader.ReadInt64());
            var notificationAuthor = Utilities.DeserializeDataContract<Endpoint>(plainTextPayloadReader);
            var messageReference = Utilities.DeserializeDataContract<PayloadReference>(plainTextPayloadReader);
            messageReference.ReferenceLocation = inboxItem.Location;
            if (messageReference.HashAlgorithmName == null)
            {
                messageReference.HashAlgorithmName = Utilities.GuessHashAlgorithmFromLength(messageReference.Hash.Length).GetHashAlgorithmName();
            }

            if (!CryptoProviderExtensions.VerifySignatureWithTolerantHashAlgorithm(notificationAuthor.SigningKeyPublicMaterial, signedBytes, signature, signingHashAlgorithm))
            {
                throw new InvalidMessageException();
            }

            if (!Utilities.AreEquivalent(recipientPublicSigningKeyBuffer, this.Endpoint.PublicEndpoint.SigningKeyPublicMaterial))
            {
                throw new InvalidMessageException(Strings.MisdirectedMessage);
            }

            return messageReference;
        }
        public async Task ECAsymmetricSigningAndEncryption()
        {
            var bob = new ECDsaCng(521);
            var bobPublic = CngKey.Import(bob.Key.Export(CngKeyBlobFormat.EccPublicBlob), CngKeyBlobFormat.EccPublicBlob);
            var alice = new ECDsaCng(521);
            var alicePublic = CngKey.Import(alice.Key.Export(CngKeyBlobFormat.EccPublicBlob), CngKeyBlobFormat.EccPublicBlob);

            // Bob formulates request.
            var bobRequest = new MemoryStream();
            var bobDH = ECDiffieHellman.Create();
            {
                byte[] bobPublicDH = bobDH.PublicKey.ToByteArray();
                byte[] bobSignedDH = bob.SignData(bobPublicDH);
                await bobRequest.WriteSizeAndBufferAsync(bobPublicDH, CancellationToken.None);
                await bobRequest.WriteSizeAndBufferAsync(bobSignedDH, CancellationToken.None);
                bobRequest.Position = 0;
            }

            // Alice reads request.
            var aliceResponse = new MemoryStream();
            byte[] aliceKeyMaterial;
            var aliceDH = new ECDiffieHellmanCng();
            {
                byte[] bobPublicDH = await bobRequest.ReadSizeAndBufferAsync(CancellationToken.None);
                byte[] bobSignedDH = await bobRequest.ReadSizeAndBufferAsync(CancellationToken.None);
                var bobDsa = new ECDsaCng(bobPublic);
                Assert.IsTrue(bobDsa.VerifyData(bobPublicDH, bobSignedDH));
                var bobDHPK = ECDiffieHellmanCngPublicKey.FromByteArray(bobPublicDH, CngKeyBlobFormat.EccPublicBlob);
                aliceKeyMaterial = aliceDH.DeriveKeyMaterial(bobDHPK);

                await aliceResponse.WriteSizeAndBufferAsync(aliceDH.PublicKey.ToByteArray(), CancellationToken.None);
                await aliceResponse.WriteSizeAndBufferAsync(alice.SignData(aliceDH.PublicKey.ToByteArray()), CancellationToken.None);

                // Alice also adds a secret message.
                using (var aes = SymmetricAlgorithm.Create())
                {
                    using (var encryptor = aes.CreateEncryptor(aliceKeyMaterial, new byte[aes.BlockSize / 8]))
                    {
                        var cipherText = new MemoryStream();
                        using (var cryptoStream = new CryptoStream(cipherText, encryptor, CryptoStreamMode.Write))
                        {
                            cryptoStream.Write(new byte[] { 0x1, 0x3, 0x2 }, 0, 3);
                            cryptoStream.FlushFinalBlock();
                            cipherText.Position = 0;
                            await aliceResponse.WriteSizeAndStreamAsync(cipherText, CancellationToken.None);
                        }
                    }
                }

                aliceResponse.Position = 0;
            }

            // Bob reads response
            byte[] bobKeyMaterial;
            {
                byte[] alicePublicDH = await aliceResponse.ReadSizeAndBufferAsync(CancellationToken.None);
                byte[] aliceSignedDH = await aliceResponse.ReadSizeAndBufferAsync(CancellationToken.None);
                var aliceDsa = new ECDsaCng(alicePublic);
                Assert.IsTrue(aliceDsa.VerifyData(alicePublicDH, aliceSignedDH));
                var aliceDHPK = ECDiffieHellmanCngPublicKey.FromByteArray(alicePublicDH, CngKeyBlobFormat.EccPublicBlob);
                bobKeyMaterial = bobDH.DeriveKeyMaterial(aliceDHPK);

                // And Bob reads Alice's secret message.
                using (var aes = SymmetricAlgorithm.Create())
                {
                    using (var decryptor = aes.CreateDecryptor(aliceKeyMaterial, new byte[aes.BlockSize / 8]))
                    {
                        var plaintext = new MemoryStream();
                        var substream = await aliceResponse.ReadSizeAndStreamAsync(CancellationToken.None);
                        using (var cryptoStream = new CryptoStream(substream, decryptor, CryptoStreamMode.Read))
                        {
                            await cryptoStream.CopyToAsync(plaintext);
                            plaintext.Position = 0;
                            byte[] secretMessage = new byte[1024];
                            int readBytes = plaintext.Read(secretMessage, 0, secretMessage.Length);
                        }
                    }
                }
            }

            CollectionAssert.AreEqual(aliceKeyMaterial, bobKeyMaterial);
        }
Example #3
0
		/// <summary>
		/// Downloads a <see cref="PayloadReference"/> that is referenced from an incoming inbox item.
		/// </summary>
		/// <param name="inboxItem">The inbox item that referenced the <see cref="PayloadReference"/>.</param>
		/// <param name="cancellationToken">The cancellation token.</param>
		/// <returns>The task representing the asynchronous operation.</returns>
		protected virtual async Task<PayloadReference> DownloadPayloadReferenceAsync(IncomingList.IncomingItem inboxItem, CancellationToken cancellationToken) {
			Requires.NotNull(inboxItem, "inboxItem");

			var responseMessage = await this.HttpClient.GetAsync(inboxItem.Location, cancellationToken);
			if (responseMessage.StatusCode == HttpStatusCode.NotFound) {
				// delete inbox item and move on.
				await this.DeletePayloadReferenceAsync(inboxItem.Location, cancellationToken);
				this.Log("Missing payload reference.", null);
				return null;
			}

			responseMessage.EnsureSuccessStatusCode();
			var responseStream = await responseMessage.Content.ReadAsStreamAsync();
			var responseStreamCopy = new MemoryStream();
			await responseStream.CopyToAsync(responseStreamCopy, 4096, cancellationToken);
			responseStreamCopy.Position = 0;

			var encryptedKey = await responseStreamCopy.ReadSizeAndBufferAsync(cancellationToken);
			var key = this.CryptoServices.Decrypt(this.Endpoint.EncryptionKeyPrivateMaterial, encryptedKey);
			var iv = await responseStreamCopy.ReadSizeAndBufferAsync(cancellationToken);
			var ciphertext = await responseStreamCopy.ReadSizeAndBufferAsync(cancellationToken);
			var encryptedPayload = new SymmetricEncryptionResult(key, iv, ciphertext);

			var plainTextPayloadBuffer = this.CryptoServices.Decrypt(encryptedPayload);

			var plainTextPayloadStream = new MemoryStream(plainTextPayloadBuffer);
			var signature = await plainTextPayloadStream.ReadSizeAndBufferAsync(cancellationToken);
			long payloadStartPosition = plainTextPayloadStream.Position;
			var signedBytes = new byte[plainTextPayloadStream.Length - plainTextPayloadStream.Position];
			await plainTextPayloadStream.ReadAsync(signedBytes, 0, signedBytes.Length);
			plainTextPayloadStream.Position = payloadStartPosition;
			var plainTextPayloadReader = new BinaryReader(plainTextPayloadStream);

			var recipientPublicSigningKeyBuffer = plainTextPayloadReader.ReadSizeAndBuffer();

			var creationDateUtc = DateTime.FromBinary(plainTextPayloadReader.ReadInt64());
			var notificationAuthor = Utilities.DeserializeDataContract<Endpoint>(plainTextPayloadReader);
			var messageReference = Utilities.DeserializeDataContract<PayloadReference>(plainTextPayloadReader);
			messageReference.ReferenceLocation = inboxItem.Location;

			if (!this.CryptoServices.VerifySignature(notificationAuthor.SigningKeyPublicMaterial, signedBytes, signature)) {
				throw new InvalidMessageException();
			}

			if (!Utilities.AreEquivalent(recipientPublicSigningKeyBuffer, this.Endpoint.PublicEndpoint.SigningKeyPublicMaterial)) {
				throw new InvalidMessageException(Strings.MisdirectedMessage);
			}

			return messageReference;
		}