private static async Task <string> GetDecryptedContentHelperAsync(RawNotification notification) { if (notification.Headers == null) { // It's not encrypted return(notification.Content); } string encryptedPayload = notification.Content; // r/JwZaorThJfqkpZjV6umbDXQy9G string cryptoKey = notification.Headers["Crypto-Key"]; // dh=BNSSQjo... string contentEncoding = notification.Headers["Content-Encoding"]; // aesgcm string encryption = notification.Headers["Encryption"]; // salt=WASwg7... var storage = await PushSubscriptionStorage.GetAsync(); StoredPushSubscription[] storedSubscriptions = storage.GetSubscriptions(notification.ChannelId); foreach (var sub in storedSubscriptions) { try { byte[] userPrivateKey = WebEncoder.Base64UrlDecode(sub.P265Private); byte[] userPublicKey = WebEncoder.Base64UrlDecode(sub.Keys.P256DH); string decrypted = Decryptor.Decrypt(encryptedPayload, cryptoKey, contentEncoding, encryption, userPrivateKey, userPublicKey, sub.Keys.Auth); // Make sure we've deleted any old channels now that we successfully received with this one await storage.DeleteSubscriptionsOlderThanAsync(notification.ChannelId, sub); return(decrypted); } catch { } } throw new Exception("Failed to decrypt"); }
private static async Task <PushSubscription> SubscribeHelper(string applicationServerKey, string channelId) { IBuffer appServerKeyBuffer = UrlB64ToUint8Array(applicationServerKey).AsBuffer(); // No matter what, we always get the channel (we don't do any caching and expiration logic, WNS caches the channel for 24 hours) var channel = await PushNotificationChannelManager.GetDefault().CreateRawPushNotificationChannelWithAlternateKeyForApplicationAsync(appServerKeyBuffer, channelId); var storage = await PushSubscriptionStorage.GetAsync(); var existingSubscriptionInfo = storage.GetSubscriptions(channelId).FirstOrDefault(i => i.ChannelUri == channel.Uri); if (existingSubscriptionInfo != null) { // If the app server key has changed if (existingSubscriptionInfo.AppServerKey != applicationServerKey) { // We need to destroy the WNS channel and create a new one // Close the channel channel.Close(); // Create a new one channel = await PushNotificationChannelManager.GetDefault().CreateRawPushNotificationChannelWithAlternateKeyForApplicationAsync(appServerKeyBuffer, channelId); // And set existing subscription info to null since there's no longer existing info existingSubscriptionInfo = null; } else { // Otherwise, return the existing info return(new PushSubscription() { Endpoint = channel.Uri, Keys = new PushSubscriptionKeys() { Auth = existingSubscriptionInfo.Keys.Auth, P256DH = existingSubscriptionInfo.Keys.P256DH }, Channel = channel, ExpirationTime = channel.ExpirationTime }); } } // Note that we have to store a series of these key pairs... // A developer with an existing channel might call Subscribe again, generating a new channel and key pair, // but they fail to upload the channel/key to their server. Therefore, their server still has the old channel/key, // and pushing to that channel still needs to work, so we need to hold onto the old keys. // We can't delete the old keys until either (1) the expiration time of 30 days for the channel occurs, // or (2) we've received and decrypted a push with the newer key pair, and can therefore throw away the old keys, since // we know at that point that the server successfully received the new channel/key. // Although in case (2), the app developer could still hold onto a previous channel and use it, so the only real truth is the // expiration time. Other than that, any channel that we return MUST keep working. // However, W3C spec states that once a message has been received for a newer subscription, the old ones MUST be deactivated, // so (2) is the correct pattern // Otherwise, we have to create new pairs for this new channel string p256dh; var keyPair = GenerateKeyPair(); p256dh = Uint8ArrayToB64String(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keyPair.Public).PublicKeyData.GetBytes()); var authBytes = CryptographicBuffer.GenerateRandom(16).ToArray(); string auth = Uint8ArrayToB64String(authBytes); await storage.SavePushSubscriptionAsync(channelId, new StoredPushSubscription() { ChannelUri = channel.Uri, Keys = new PushSubscriptionKeys() { Auth = auth, P256DH = p256dh }, AppServerKey = applicationServerKey, P265Private = Uint8ArrayToB64String(PrivateKeyInfoFactory.CreatePrivateKeyInfo(keyPair.Private).ToAsn1Object().GetDerEncoded()) }); return(new PushSubscription() { Endpoint = channel.Uri, Keys = new PushSubscriptionKeys() { Auth = auth, P256DH = p256dh }, Channel = channel, ExpirationTime = channel.ExpirationTime }); }