Example #1
0
		private async void CreateNewEndpoint_OnClick(object sender, RoutedEventArgs e) {
			this.CreateNewEndpoint.IsEnabled = false;
			this.CreateNewEndpoint.Cursor = Cursors.AppStarting;
			try {
				var cts = new CancellationTokenSource();
				var endpointTask = this.OwnEndpointServices.CreateAsync(cts.Token);
				var dialog = new SaveFileDialog();
				bool? result = dialog.ShowDialog(this);
				if (result.HasValue && result.Value) {
					Uri addressBookEntry = await this.OwnEndpointServices.PublishAddressBookEntryAsync(await endpointTask, cts.Token);
					await this.SetEndpointAsync(await endpointTask, addressBookEntry, cts.Token);
					using (var stream = dialog.OpenFile()) {
						var writer = new BinaryWriter(stream, Encoding.UTF8);
						writer.SerializeDataContract(addressBookEntry);
						writer.Flush();
						await this.Channel.Endpoint.SaveAsync(stream, cts.Token);
					}
				} else {
					cts.Cancel();
				}
			} finally {
				this.CreateNewEndpoint.Cursor = Cursors.Arrow;
				this.CreateNewEndpoint.IsEnabled = true;
			}
		}
Example #2
0
		/// <summary>
		/// Sends the specified dart to the recipients specified in the message.
		/// </summary>
		/// <param name="message">The dart to send.</param>
		/// <param name="cancellationToken">The cancellation token.</param>
		/// <returns>The asynchronous result.</returns>
		public virtual Task PostAsync(Message message, CancellationToken cancellationToken = default(CancellationToken)) {
			Requires.NotNull(message, "message");

			var ms = new MemoryStream();
			var writer = new BinaryWriter(ms);
			writer.SerializeDataContract(message);
			writer.Flush();
			ms.Position = 0;

			var payload = new Payload(ms.ToArray(), Message.ContentType);
			var allRecipients = new List<Endpoint>(message.Recipients);
			if (message.CarbonCopyRecipients != null) {
				allRecipients.AddRange(message.CarbonCopyRecipients);
			}

			var readOnlyRecipients = new ReadOnlyCollection<Endpoint>(allRecipients);
			return this.Channel.PostAsync(payload, readOnlyRecipients, message.ExpirationUtc, cancellationToken);
		}
Example #3
0
        /// <summary>
        /// Saves the receiving endpoint including private data to the specified stream.
        /// </summary>
        /// <param name="target">The stream to write to.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task whose completion signals the save is complete.</returns>
        public Task SaveAsync(Stream target, CancellationToken cancellationToken = default(CancellationToken))
        {
            Requires.NotNull(target, "target");

            var ms = new MemoryStream();
            using (var writer = new BinaryWriter(ms))
            {
                writer.SerializeDataContract(this);
                ms.Position = 0;
                return ms.CopyToAsync(target, 4096, cancellationToken);
            }
        }
Example #4
0
        /// <summary>
        /// Creates a signed address book entry that describes the public information in this endpoint.
        /// </summary>
        /// <param name="cryptoServices">The crypto services to use for signing the address book entry.</param>
        /// <returns>The address book entry.</returns>
        public AddressBookEntry CreateAddressBookEntry(CryptoSettings cryptoServices)
        {
            Requires.NotNull(cryptoServices, "cryptoServices");

            var ms = new MemoryStream();
            var writer = new BinaryWriter(ms);
            var entry = new AddressBookEntry();
            writer.SerializeDataContract(this.PublicEndpoint);
            writer.Flush();
            entry.SerializedEndpoint = ms.ToArray();
            entry.Signature = WinRTCrypto.CryptographicEngine.Sign(this.SigningKey, entry.SerializedEndpoint);
            return entry;
        }
Example #5
0
        /// <summary>
        /// Shares the reference to a message payload with the specified recipient.
        /// </summary>
        /// <param name="messageReference">The payload reference to share.</param>
        /// <param name="recipient">The recipient that should be notified of the message.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task representing the asynchronous operation.</returns>
        protected virtual async Task<NotificationPostedReceipt> PostPayloadReferenceAsync(PayloadReference messageReference, Endpoint recipient, CancellationToken cancellationToken)
        {
            Requires.NotNull(recipient, "recipient");
            Requires.NotNull(messageReference, "messageReference");

            cancellationToken.ThrowIfCancellationRequested();

            // Prepare the payload.
            var plainTextPayloadStream = new MemoryStream();
            var plainTextPayloadWriter = new BinaryWriter(plainTextPayloadStream);

            // Include the intended recipient's signing certificate so the recipient knows that
            // the message author intended the recipient to receive it (defeats fowarding and re-encrypting
            // a message notification with the intent to deceive a victim that a message was intended for them when it was not.)
            plainTextPayloadWriter.WriteSizeAndBuffer(recipient.SigningKeyPublicMaterial);

            plainTextPayloadWriter.Write(DateTime.UtcNow.ToBinary());

            // Write out the author of this notification (which may be different from the author of the
            // message itself in the case of a "forward").
            plainTextPayloadWriter.SerializeDataContract(this.Endpoint.PublicEndpoint);

            plainTextPayloadWriter.SerializeDataContract(messageReference);
            plainTextPayloadWriter.Flush();
            this.Log("Message invite plaintext", plainTextPayloadStream.ToArray());

            byte[] notificationSignature = WinRTCrypto.CryptographicEngine.Sign(this.Endpoint.SigningKey, plainTextPayloadStream.ToArray());
            var signedPlainTextPayloadStream = new MemoryStream((int)plainTextPayloadStream.Length + notificationSignature.Length + 4);
            ////await signedPlainTextPayloadStream.WriteSizeAndBufferAsync(Encoding.UTF8.GetBytes(this.CryptoServices.HashAlgorithmName), cancellationToken);
            await signedPlainTextPayloadStream.WriteSizeAndBufferAsync(notificationSignature, cancellationToken).ConfigureAwait(false);
            plainTextPayloadStream.Position = 0;
            await plainTextPayloadStream.CopyToAsync(signedPlainTextPayloadStream, 4096, cancellationToken).ConfigureAwait(false);
            signedPlainTextPayloadStream.Position = 0;
            var cipherTextStream = new MemoryStream();
            var encryptedVariables = await this.CryptoServices.EncryptAsync(signedPlainTextPayloadStream, cipherTextStream, cancellationToken: cancellationToken).ConfigureAwait(false);
            this.Log("Message invite ciphertext", cipherTextStream.ToArray());
            this.Log("Message invite key", encryptedVariables.Key);
            this.Log("Message invite IV", encryptedVariables.IV);

            var builder = new UriBuilder(recipient.MessageReceivingEndpoint);
            var lifetimeInMinutes = (int)(messageReference.ExpiresUtc - DateTime.UtcNow).TotalMinutes;
            builder.Query += "&lifetime=" + lifetimeInMinutes.ToString(CultureInfo.InvariantCulture);

            var postContent = new MemoryStream();
            var encryptionKey = CryptoSettings.EncryptionAlgorithm.ImportPublicKey(
                recipient.EncryptionKeyPublicMaterial,
                CryptoSettings.PublicKeyFormat);
            var encryptedKey = WinRTCrypto.CryptographicEngine.Encrypt(encryptionKey, encryptedVariables.Key);
            this.Log("Message invite encrypted key", encryptedKey);
            await postContent.WriteSizeAndBufferAsync(encryptedKey, cancellationToken).ConfigureAwait(false);
            await postContent.WriteSizeAndBufferAsync(encryptedVariables.IV, cancellationToken).ConfigureAwait(false);
            cipherTextStream.Position = 0;
            await postContent.WriteSizeAndStreamAsync(cipherTextStream, cancellationToken).ConfigureAwait(false);
            await postContent.FlushAsync().ConfigureAwait(false);
            postContent.Position = 0;

            using (var response = await this.HttpClient.PostAsync(builder.Uri, new StreamContent(postContent), cancellationToken).ConfigureAwait(false))
            {
                if (response.Content != null)
                {
                    // Just to help in debugging.
                    string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
                }

                response.EnsureSuccessStatusCode();
                var receipt = new NotificationPostedReceipt(recipient, response.Headers.Date);
                return receipt;
            }
        }
Example #6
0
        /// <summary>
        /// Encrypts a message and uploads it to the cloud.
        /// </summary>
        /// <param name="message">The message being transmitted.</param>
        /// <param name="expiresUtc">The date after which the message may be destroyed.</param>
        /// <param name="bytesCopiedProgress">Receives progress in terms of number of bytes uploaded.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The task whose result is a reference to the uploaded payload including decryption key.</returns>
        public virtual async Task<PayloadReference> PostPayloadAsync(Payload message, DateTime expiresUtc, IProgress<int> bytesCopiedProgress = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            Requires.NotNull(message, "message");
            Requires.That(expiresUtc.Kind == DateTimeKind.Utc, "expiresUtc", Strings.UTCTimeRequired);
            Requires.ValidState(this.CloudBlobStorage != null, "BlobStorageProvider must not be null");

            cancellationToken.ThrowIfCancellationRequested();

            var plainTextStream = new MemoryStream();
            var writer = new BinaryWriter(plainTextStream);
            writer.SerializeDataContract(message);
            writer.Flush();
            var plainTextBuffer = plainTextStream.ToArray();
            this.Log("Message plaintext", plainTextBuffer);

            plainTextStream.Position = 0;
            var cipherTextStream = new MemoryStream();
            var encryptionVariables = await this.CryptoServices.EncryptAsync(plainTextStream, cipherTextStream, cancellationToken: cancellationToken).ConfigureAwait(false);
            this.Log("Message symmetrically encrypted", cipherTextStream.ToArray());
            this.Log("Message symmetric key", encryptionVariables.Key);
            this.Log("Message symmetric IV", encryptionVariables.IV);

            cipherTextStream.Position = 0;
            var hasher = WinRTCrypto.HashAlgorithmProvider.OpenAlgorithm(this.CryptoServices.SymmetricHashAlgorithm);
            var messageHash = hasher.HashData(cipherTextStream.ToArray());
            this.Log("Encrypted message hash", messageHash);

            cipherTextStream.Position = 0;
            Uri blobUri = await this.CloudBlobStorage.UploadMessageAsync(cipherTextStream, expiresUtc, contentType: message.ContentType, bytesCopiedProgress: bytesCopiedProgress, cancellationToken: cancellationToken).ConfigureAwait(false);
            return new PayloadReference(blobUri, messageHash, this.CryptoServices.SymmetricHashAlgorithm.GetHashAlgorithmName(), encryptionVariables.Key, encryptionVariables.IV, expiresUtc);
        }
Example #7
0
		/// <summary>
		/// Shares the reference to a message payload with the specified recipient.
		/// </summary>
		/// <param name="messageReference">The payload reference to share.</param>
		/// <param name="recipient">The recipient that should be notified of the message.</param>
		/// <param name="cancellationToken">The cancellation token.</param>
		/// <returns>The task representing the asynchronous operation.</returns>
		protected virtual async Task PostPayloadReferenceAsync(PayloadReference messageReference, Endpoint recipient, CancellationToken cancellationToken) {
			Requires.NotNull(recipient, "recipient");
			Requires.NotNull(messageReference, "messageReference");

			cancellationToken.ThrowIfCancellationRequested();

			// Prepare the payload.
			var plainTextPayloadStream = new MemoryStream();
			var plainTextPayloadWriter = new BinaryWriter(plainTextPayloadStream);

			// Include the intended recipient's signing certificate so the recipient knows that 
			// the message author intended the recipient to receive it (defeats fowarding and re-encrypting
			// a message notification with the intent to deceive a victim that a message was intended for them when it was not.)
			plainTextPayloadWriter.WriteSizeAndBuffer(recipient.SigningKeyPublicMaterial);

			plainTextPayloadWriter.Write(DateTime.UtcNow.ToBinary());

			// Write out the author of this notification (which may be different from the author of the 
			// message itself in the case of a "forward").
			plainTextPayloadWriter.SerializeDataContract(this.Endpoint.PublicEndpoint);

			plainTextPayloadWriter.SerializeDataContract(messageReference);
			plainTextPayloadWriter.Flush();
			this.Log("Message invite plaintext", plainTextPayloadStream.ToArray());

			byte[] notificationSignature = this.CryptoServices.Sign(plainTextPayloadStream.ToArray(), this.Endpoint.SigningKeyPrivateMaterial);
			var signedPlainTextPayloadStream = new MemoryStream((int)plainTextPayloadStream.Length + notificationSignature.Length + 4);
			await signedPlainTextPayloadStream.WriteSizeAndBufferAsync(notificationSignature, cancellationToken);
			plainTextPayloadStream.Position = 0;
			await plainTextPayloadStream.CopyToAsync(signedPlainTextPayloadStream, 4096, cancellationToken);
			var encryptedPayload = this.CryptoServices.Encrypt(signedPlainTextPayloadStream.ToArray());
			this.Log("Message invite ciphertext", encryptedPayload.Ciphertext);
			this.Log("Message invite key", encryptedPayload.Key);
			this.Log("Message invite IV", encryptedPayload.IV);

			var builder = new UriBuilder(recipient.MessageReceivingEndpoint);
			var lifetimeInMinutes = (int)(messageReference.ExpiresUtc - DateTime.UtcNow).TotalMinutes;
			builder.Query += "&lifetime=" + lifetimeInMinutes.ToString(CultureInfo.InvariantCulture);

			var postContent = new MemoryStream();
			var encryptedKey = this.CryptoServices.Encrypt(recipient.EncryptionKeyPublicMaterial, encryptedPayload.Key);
			this.Log("Message invite encrypted key", encryptedKey);
			await postContent.WriteSizeAndBufferAsync(encryptedKey, cancellationToken);
			await postContent.WriteSizeAndBufferAsync(encryptedPayload.IV, cancellationToken);
			await postContent.WriteSizeAndBufferAsync(encryptedPayload.Ciphertext, cancellationToken);
			await postContent.FlushAsync();
			postContent.Position = 0;

			using (var response = await this.HttpClient.PostAsync(builder.Uri, new StreamContent(postContent), cancellationToken)) {
				response.EnsureSuccessStatusCode();
			}
		}
Example #8
0
		/// <summary>
		/// Encrypts a message and uploads it to the cloud.
		/// </summary>
		/// <param name="message">The message being transmitted.</param>
		/// <param name="expiresUtc">The date after which the message may be destroyed.</param>
		/// <param name="cancellationToken">The cancellation token.</param>
		/// <returns>The task whose result is a reference to the uploaded payload including decryption key.</returns>
		protected virtual async Task<PayloadReference> PostPayloadAsync(Payload message, DateTime expiresUtc, CancellationToken cancellationToken) {
			Requires.NotNull(message, "message");
			Requires.That(expiresUtc.Kind == DateTimeKind.Utc, "expiresUtc", Strings.UTCTimeRequired);
			Requires.ValidState(this.CloudBlobStorage != null, "BlobStorageProvider must not be null");

			cancellationToken.ThrowIfCancellationRequested();

			var plainTextStream = new MemoryStream();
			var writer = new BinaryWriter(plainTextStream);
			writer.SerializeDataContract(message);
			writer.Flush();
			var plainTextBuffer = plainTextStream.ToArray();
			this.Log("Message plaintext", plainTextBuffer);

			var encryptionResult = this.CryptoServices.Encrypt(plainTextBuffer);
			this.Log("Message symmetrically encrypted", encryptionResult.Ciphertext);
			this.Log("Message symmetric key", encryptionResult.Key);
			this.Log("Message symmetric IV", encryptionResult.IV);

			var messageHash = this.CryptoServices.Hash(encryptionResult.Ciphertext);
			this.Log("Encrypted message hash", messageHash);

			using (MemoryStream cipherTextStream = new MemoryStream(encryptionResult.Ciphertext)) {
				Uri blobUri = await this.CloudBlobStorage.UploadMessageAsync(cipherTextStream, expiresUtc, cancellationToken: cancellationToken);
				return new PayloadReference(blobUri, messageHash, encryptionResult.Key, encryptionResult.IV, expiresUtc);
			}
		}
Example #9
0
		/// <summary>
		/// Creates a signed address book entry that describes the public information in this endpoint.
		/// </summary>
		/// <param name="cryptoServices">The crypto services to use for signing the address book entry.</param>
		/// <returns>The address book entry.</returns>
		public AddressBookEntry CreateAddressBookEntry(ICryptoProvider cryptoServices) {
			Requires.NotNull(cryptoServices, "cryptoServices");

			var ms = new MemoryStream();
			var writer = new BinaryWriter(ms);
			var entry = new AddressBookEntry();
			writer.SerializeDataContract(this.PublicEndpoint);
			writer.Flush();
			entry.SerializedEndpoint = ms.ToArray();
			entry.Signature = cryptoServices.Sign(entry.SerializedEndpoint, this.SigningKeyPrivateMaterial);
			return entry;
		}