/// <summary> /// /// </summary> /// <param name="encryptedPayload"></param> /// <param name="cryptoKey">EncryptionResult.PublicKey (server public key) "dh=BNSSQjo..."</param> /// <param name="contentEncoding">aesgcm</param> /// <param name="encryption">EncryptionResult.Salt? "salt=WASwg7..."</param> /// <param name="p256dh">Client-generated</param> /// <param name="authKey">Client-generated</param> /// <returns></returns> public static string Decrypt(string encryptedPayload, string cryptoKey, string contentEncoding, string encryption, byte[] userPrivateKey, byte[] userPublicKey, string authKey) { // Trim the null terminator if (encryptedPayload.EndsWith("\0")) { encryptedPayload = encryptedPayload.Substring(0, encryptedPayload.Length - 1); } byte[] encryptedBytes; // WNS either gives us Base64 or UTF16, try both try { encryptedBytes = Convert.FromBase64String(encryptedPayload); } catch { encryptedBytes = Encoding.Unicode.GetBytes(encryptedPayload); } string serverPublicKey = cryptoKey.Substring("dh=".Length); // Note that using UrlBase64.Decode fails later on, but our WebEncoder seems to decode it so that it works later on byte[] serverPublicKeyBytes = WebEncoder.Base64UrlDecode(serverPublicKey); string saltStr = encryption.Substring("salt=".Length); return(Decrypt(encryptedBytes, serverPublicKeyBytes, contentEncoding, WebEncoder.Base64UrlDecode(saltStr), userPrivateKey, userPublicKey, WebEncoder.Base64UrlDecode(authKey))); }
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"); }