From 91e29e8313d46a52fccfe03ab7bd64c516490d52 Mon Sep 17 00:00:00 2001 From: Daniel Cohen Gindi Date: Sat, 28 Sep 2024 20:17:48 +0300 Subject: [PATCH] Cache the private keys for less overhead when signing messages --- CorePush/Apple/ApnSender.cs | 21 +++++++++--- CorePush/Apple/ApnSettings.cs | 47 ++++++++++++++++++++++++--- CorePush/Firebase/FirebaseSender.cs | 15 ++++++++- CorePush/Firebase/FirebaseSettings.cs | 7 +++- 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/CorePush/Apple/ApnSender.cs b/CorePush/Apple/ApnSender.cs index 9d4dd80..ed74c07 100644 --- a/CorePush/Apple/ApnSender.cs +++ b/CorePush/Apple/ApnSender.cs @@ -120,15 +120,28 @@ private string GetJwtToken() private string CreateJwtToken() { - var header = serializer.Serialize(new { alg = "ES256", kid = CryptoHelper.CleanP8Key(settings.P8PrivateKeyId) }); + var header = serializer.Serialize(new { alg = "ES256", kid = settings.P8PrivateKeyIdClean }); var payload = serializer.Serialize(new { iss = settings.TeamId, iat = CryptoHelper.GetEpochTimestamp() }); var headerBase64 = Base64UrlEncode(header); var payloadBase64 = Base64UrlEncode(payload); var unsignedJwtData = $"{headerBase64}.{payloadBase64}"; var unsignedJwtBytes = Encoding.UTF8.GetBytes(unsignedJwtData); - - var privateKeyBytes = Convert.FromBase64String(CryptoHelper.CleanP8Key(settings.P8PrivateKey)); - var keyParams = (ECPrivateKeyParameters) PrivateKeyFactory.CreateKey(privateKeyBytes); + + ECPrivateKeyParameters keyParams = settings.CachedP8PrivateKeyParams as ECPrivateKeyParameters; + if (keyParams == null) + { + lock(settings) + { + keyParams = settings.CachedP8PrivateKeyParams as ECPrivateKeyParameters; + if (keyParams == null) + { + var privateKeyBytes = Convert.FromBase64String(CryptoHelper.CleanP8Key(settings.P8PrivateKey)); + keyParams = (ECPrivateKeyParameters)PrivateKeyFactory.CreateKey(privateKeyBytes); + settings.CachedP8PrivateKeyParams = keyParams; + } + } + } + var q = keyParams.Parameters.G.Multiply(keyParams.D).Normalize(); using var dsa = ECDsa.Create(new ECParameters diff --git a/CorePush/Apple/ApnSettings.cs b/CorePush/Apple/ApnSettings.cs index 5c0cf76..655c6ce 100644 --- a/CorePush/Apple/ApnSettings.cs +++ b/CorePush/Apple/ApnSettings.cs @@ -1,29 +1,68 @@ +using CorePush.Utils; + namespace CorePush.Apple; +#nullable enable + public class ApnSettings { + private string? _P8PrivateKey = null; + private string? _P8PrivateKeyId = null; + private string? _P8PrivateKeyIdClean = null; + /// /// p8 certificate string /// - public string P8PrivateKey { get; set; } + public string? P8PrivateKey + { + get + { + return _P8PrivateKey; + } + set + { + lock (this) + { + _P8PrivateKey = value; + CachedP8PrivateKeyParams = null; + } + } + } /// /// 10 digit p8 certificate id. Usually a part of a downloadable certificate filename /// - public string P8PrivateKeyId { get; set; } + public string? P8PrivateKeyId + { + get + { + return _P8PrivateKeyId; + } + set + { + lock (this) + { + _P8PrivateKeyId = value; + _P8PrivateKeyIdClean = CryptoHelper.CleanP8Key(value); + } + } + } /// /// Apple 10 digit team id /// - public string TeamId { get; set; } + public string? TeamId { get; set; } /// /// App slug / bundle name /// - public string AppBundleIdentifier { get; set; } + public string? AppBundleIdentifier { get; set; } /// /// Development or Production server /// public ApnServerType ServerType { get; set; } + + internal string? P8PrivateKeyIdClean { get { return _P8PrivateKeyIdClean; } } + internal object? CachedP8PrivateKeyParams; } \ No newline at end of file diff --git a/CorePush/Firebase/FirebaseSender.cs b/CorePush/Firebase/FirebaseSender.cs index 02ce3c0..bd1207a 100644 --- a/CorePush/Firebase/FirebaseSender.cs +++ b/CorePush/Firebase/FirebaseSender.cs @@ -165,7 +165,20 @@ private string GetMasterToken() var unsignedJwtData = $"{headerBase64}.{payloadBase64}"; var unsignedJwtBytes = Encoding.UTF8.GetBytes(unsignedJwtData); - var privateKey = ParsePkcs8PrivateKeyPem(settings.PrivateKey); + var privateKey = settings._CachedPivateKey as AsymmetricKeyParameter; + if (privateKey == null) + { + lock(settings) + { + privateKey = settings._CachedPivateKey as AsymmetricKeyParameter; + if (privateKey == null) + { + privateKey = ParsePkcs8PrivateKeyPem(settings.PrivateKey); + settings._CachedPivateKey = privateKey; + } + } + } + var signer = new RsaDigestSigner(new Org.BouncyCastle.Crypto.Digests.Sha256Digest()); signer.Init(true, privateKey); signer.BlockUpdate(unsignedJwtBytes, 0, unsignedJwtBytes.Length); diff --git a/CorePush/Firebase/FirebaseSettings.cs b/CorePush/Firebase/FirebaseSettings.cs index 4e195d4..621c663 100644 --- a/CorePush/Firebase/FirebaseSettings.cs +++ b/CorePush/Firebase/FirebaseSettings.cs @@ -1,5 +1,7 @@ using System.Text.Json.Serialization; +#nullable enable + namespace CorePush.Firebase; public record FirebaseSettings( @@ -7,4 +9,7 @@ public record FirebaseSettings( [property: JsonPropertyName("private_key")] string PrivateKey, [property: JsonPropertyName("client_email")] string ClientEmail, [property: JsonPropertyName("token_uri")] string TokenUri -); \ No newline at end of file +) +{ + internal object? _CachedPivateKey; +} \ No newline at end of file