public virtual byte[] Decrypt(ECPrivateKey privateKey, byte[] data) { using (var stream = new MemoryStream(data)) { // read the IV byte[] iv = new byte[16]; stream.Read(iv, 0, iv.Length); // read the publickey var pubkeysize = stream.ReadByte(); byte[] pubkeyraw = new byte[pubkeysize]; stream.Read(pubkeyraw, 0, pubkeyraw.Length); var pubkey = new ECPublicKey(pubkeyraw); // Do an EC point multiply with this.getPrivateKey() and ephemeral public key. This gives you a point M. var m = GetECPoint(pubkey).Multiply(new BigInteger(1, privateKey.Base64Array)).Normalize(); // Use the X component of point M and calculate the SHA512 hash H. byte[] h = RadixHash.Sha512Of(m.XCoord.GetEncoded()).ToByteArray(); // The first 32 bytes of H are called key_e and the last 32 bytes are called key_m. byte[] keyE = Arrays.CopyOfRange(h, 0, 32); byte[] keyM = Arrays.CopyOfRange(h, 32, 64); // Read encrypted data var size = new byte[4]; stream.Read(size, 0, size.Length); byte[] encrypted = new byte[BitConverter.ToInt32(size, 0)]; stream.Read(encrypted, 0, encrypted.Length); // Read MAC byte[] mac = new byte[32]; stream.Read(mac, 0, mac.Length); // Compare MAC with MAC'. If not equal, decryption will fail. byte[] pkMac = CalculateMAC(keyM, iv, pubkey, encrypted); if (pkMac.Equals(mac)) { throw new ApplicationException ($"Decryption failed, mac mismatch , {Convert.ToBase64String(pkMac)} <> {Convert.ToBase64String(mac)}"); } // Decrypt the cipher text with AES-256-CBC, using IV as initialization vector, key_e as decryption key, // and the cipher text as payload. The output is the padded input text. return(Crypt(false, encrypted, iv, keyE)); } }
public virtual byte[] Encrypt(ECPublicKey publicKey, byte[] data) { Random rand = new SecureRandom(); byte[] iv = new byte[16]; // 2. Generate 16 random bytes using a secure random number generator. Call them IV rand.NextBytes(iv); var randomKeyPair = GetRandomKeyPair(); // Do an EC point multiply with publicKey and random keypair. This gives you a point M. var m = GetECPoint(publicKey).Multiply(new BigInteger(1, randomKeyPair.PrivateKey.Base64Array)).Normalize(); // Use the X component of point M and calculate the SHA512 hash H. byte[] h = RadixHash.Sha512Of(m.AffineXCoord.GetEncoded()).ToByteArray(); // The first 32 bytes of H are called key_e and the last 32 bytes are called key_m. byte[] keyE = Arrays.CopyOfRange(h, 0, 32); byte[] keyM = Arrays.CopyOfRange(h, 32, 64); byte[] encrypted = Crypt(true, data, iv, keyE); // Calculate a 32 byte MAC with HMACSHA256, using key_m as salt and // IV + ephemeral.pub + cipher text as data. Call the output MAC. byte[] mac = CalculateMAC(keyM, iv, randomKeyPair.PublicKey, encrypted); // Write out the encryption result IV +ephemeral.pub + encrypted + MAC using (var memstr = new MemoryStream()) { memstr.Write(iv, 0, iv.Length); memstr.WriteByte((byte)randomKeyPair.PublicKey.Length()); memstr.Write(randomKeyPair.PublicKey.Base64Array, 0, randomKeyPair.PublicKey.Length()); memstr.Write(BitConverter.GetBytes(encrypted.Length), 0, 4); memstr.Write(encrypted, 0, encrypted.Length); memstr.Write(mac, 0, mac.Length); return(memstr.ToArray()); } }