Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
96 views
in Technique[技术] by (71.8m points)

c# - Is there a way for WebPush decryption in .net?

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...