public static EncryptionResult EncryptMessage(byte[] userKey, byte[] userSecret, byte[] data, ushort padding = 0, bool randomisePadding = false)
{
var Random = new SecureRandom();
var Salt = new byte[16];
Random.NextBytes(Salt);
var Curve = ECNamedCurveTable.GetByName("prime256v1");
var Spec = new ECDomainParameters(Curve.Curve, Curve.G, Curve.N, Curve.H, Curve.GetSeed());
var Generator = new ECKeyPairGenerator();
Generator.Init(new ECKeyGenerationParameters(Spec, new SecureRandom()));
var KeyPair = Generator.GenerateKeyPair();
var AgreementGenerator = new ECDHBasicAgreement();
AgreementGenerator.Init(KeyPair.Private);
var IKM =
AgreementGenerator.CalculateAgreement(new ECPublicKeyParameters(Spec.Curve.DecodePoint(userKey), Spec));
var PRK = GenerateHKDF(userSecret, IKM.ToByteArrayUnsigned(),
Encoding.UTF8.GetBytes("Content-Encoding: auth\0"), 32);
var PublicKey = ((ECPublicKeyParameters)KeyPair.Public).Q.GetEncoded(false);
var CEK = GenerateHKDF(Salt, PRK, CreateInfoChunk("aesgcm", userKey, PublicKey), 16);
var Nonce = GenerateHKDF(Salt, PRK, CreateInfoChunk("nonce", userKey, PublicKey), 12);
if (randomisePadding && (padding > 0)) padding = Convert.ToUInt16(Math.Abs(Random.NextInt()) % (padding + 1));
var Input = new byte[padding + 2 + data.Length];
Buffer.BlockCopy(ConvertInt(padding), 0, Input, 0, 2);
Buffer.BlockCopy(data, 0, Input, padding + 2, data.Length);
var Cipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
Cipher.Init(true, new AeadParameters(new KeyParameter(CEK), 128, Nonce));
var Message = new byte[Cipher.GetOutputSize(Input.Length)];
Cipher.DoFinal(Input, 0, Input.Length, Message, 0);
return new EncryptionResult { Salt = Salt, Payload = Message, PublicKey = PublicKey };
}