I manage to send push notifications from my server to my client app using this encryption. But once all data has been received I cannot find a way how to decrypt it.
As far as I'm aware this document describes the basics of the algorithm for decryption but it is not as detailed as I wish.
Here is the code that I'm using for encryption:
public static EncryptionResult EncryptMessage(byte[] userKey, byte[] userSecret, byte[] data,
ushort padding = 0, bool randomisePadding = false) {
SecureRandom Random = new SecureRandom();
byte[] Salt = new byte[16];
Random.NextBytes(Salt);
X9ECParameters Curve = ECNamedCurveTable.GetByName("prime256v1");
ECDomainParameters Spec = new ECDomainParameters(Curve.Curve, Curve.G, Curve.N, Curve.H, Curve.GetSeed());
ECKeyPairGenerator Generator = new ECKeyPairGenerator();
Generator.Init(new ECKeyGenerationParameters(Spec, new SecureRandom()));
AsymmetricCipherKeyPair KeyPair = Generator.GenerateKeyPair();
ECDHBasicAgreement AgreementGenerator = new ECDHBasicAgreement();
AgreementGenerator.Init(KeyPair.Private);
BigInteger IKM = AgreementGenerator.CalculateAgreement(new ECPublicKeyParameters(Spec.Curve.DecodePoint(userKey), Spec));
byte[] PRK = GenerateHKDF(userSecret, IKM.ToByteArrayUnsigned(), Encoding.UTF8.GetBytes("Content-Encoding: auth"), 32);
byte[] PublicKey = ((ECPublicKeyParameters)KeyPair.Public).Q.GetEncoded(false);
byte[] CEK = GenerateHKDF(Salt, PRK, CreateInfoChunk("aesgcm", userKey, PublicKey), 16);
byte[] Nonce = GenerateHKDF(Salt, PRK, CreateInfoChunk("nonce", userKey, PublicKey), 12);
if (randomisePadding && padding > 0) padding = Convert.ToUInt16(Math.Abs(Random.NextInt()) % (padding + 1));
byte[] Input = new byte[padding + 2 + data.Length];
Buffer.BlockCopy(ConvertInt(padding), 0, Input, 0, 2);
Buffer.BlockCopy(data, 0, Input, padding + 2, data.Length);
IBufferedCipher Cipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
Cipher.Init(true, new AeadParameters(new KeyParameter(CEK), 128, Nonce));
byte[] Message = new byte[Cipher.GetOutputSize(Input.Length)];
Cipher.DoFinal(Input, 0, Input.Length, Message, 0);
return new EncryptionResult() { Salt = Salt, Payload = Message, PublicKey = PublicKey };
}
public class EncryptionResult {
public byte[] PublicKey { get; set; }
public byte[] Payload { get; set; }
public byte[] Salt { get; set; }
}
public class JsonSubscription {
public string endpoint { get; set; }
public Dictionary<string, string> keys { get; set; }
}
public static byte[] ConvertInt(int number) {
byte[] Output = BitConverter.GetBytes(Convert.ToUInt16(number));
if (BitConverter.IsLittleEndian) Array.Reverse(Output);
return Output;
}
public static byte[] CreateInfoChunk(string type, byte[] recipientPublicKey, byte[] senderPublicKey) {
List<byte> Output = new List<byte>();
Output.AddRange(Encoding.UTF8.GetBytes($"Content-Encoding: {type}P-256"));
Output.AddRange(ConvertInt(recipientPublicKey.Length));
Output.AddRange(recipientPublicKey);
Output.AddRange(ConvertInt(senderPublicKey.Length));
Output.AddRange(senderPublicKey);
return Output.ToArray();
}
public static byte[] GenerateHKDF(byte[] salt, byte[] ikm, byte[] info, int len) {
IMac PRKGen = MacUtilities.GetMac("HmacSHA256");
PRKGen.Init(new KeyParameter(MacUtilities.CalculateMac("HmacSHA256", new KeyParameter(salt), ikm)));
PRKGen.BlockUpdate(info, 0, info.Length);
PRKGen.Update((byte)1);
byte[] Result = MacUtilities.DoFinal(PRKGen);
if (Result.Length > len) Array.Resize(ref Result, len);
return Result;
}
So the decryption code should be something like that:
public static byte[] DecryptData(byte[] serverKey, byte[] salt, byte[] clientPrivateKey, byte[] clientAuthSecret, byte[] clientPublicKey, byte[] encryptedData)
{
// decrypt
}
question from:
https://stackoverflow.com/questions/65932787/is-there-a-way-for-webpush-decryption-in-net