internal byte[] EncryptHttpMessage(byte[] httpMessage, FfRequest request) { Debug.WriteLine("Encrypting HTTP message using AES-256-GCM with PBKDF2"); var salt = new byte[16]; this.rng.GetBytes(salt); var derivedKey = KeyDerivation.Pbkdf2( password: this.config.PreSharedKey, salt: salt, prf: KeyDerivationPrf.HMACSHA256, iterationCount: this.config.Pbkdf2Iterations, numBytesRequested: 256 / 8 ); var iv = new byte[12]; this.rng.GetBytes(iv); var tag = new byte[16]; var cipherText = new byte[httpMessage.Length]; using (var aesGcm = new AesGcm(derivedKey)) { aesGcm.Encrypt(iv, httpMessage, cipherText, tag); } request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_ENCRYPTION_MODE, Value = new byte[] { (byte)FfEncryptionMode.AES_256_GCM } }); request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_ENCRYPTION_IV, Value = iv }); request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_ENCRYPTION_TAG, Value = tag }); request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_KEY_DERIVE_MODE, Value = new byte[] { (byte)FfKeyDeriveMode.PBKDF2 } }); request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_KEY_DERIVE_SALT, Value = salt }); return(cipherText); }
internal List <UdpPacket> PacketiseRequest(FfRequest request) { var packets = new List <UdpPacket>(); uint bytesLeft = (uint)request.Payload.Length; uint chunkOffset = 0; while (bytesLeft > 0) { var packet = new byte[MAX_PACKET_LENGTH]; int i = 0; this.WriteNumber <ushort>(packet, (ushort)request.Version, ref i); this.WriteNumber <ulong>(packet, request.RequestId, ref i); this.WriteNumber <uint>(packet, (uint)request.Payload.Length, ref i); this.WriteNumber <uint>(packet, chunkOffset, ref i); // Defer writing chunk length (int16) int chunkLengthOffset = i; i += 2; if (chunkOffset == 0) { this.WriteOptions(packet, request.Options, ref i); } else { // Only first packet has options so write EOL option for non initial packets packet[i++] = (byte)FfRequestOption.Type.TYPE_EOL; this.WriteNumber <ushort>(packet, 0, ref i); } ushort chunkLength = (ushort)Math.Min(bytesLeft, MAX_PACKET_LENGTH - i); Buffer.BlockCopy(request.Payload, (int)chunkOffset, packet, i, chunkLength); i += chunkLength; // Write chunk length this.WriteNumber <ushort>(packet, chunkLength, ref chunkLengthOffset); bytesLeft -= chunkLength; chunkOffset += chunkLength; packets.Add(new UdpPacket() { Packet = packet, Length = i }); } return(packets); }
internal byte[] EncryptHttpMessage(byte[] httpMessage, FfRequest request) { Debug.WriteLine("Encrypting HTTP message using AES-256-GCM"); var iv = new byte[12]; this.rng.GetBytes(iv); var tag = new byte[16]; var cipherText = new byte[httpMessage.Length]; var paddedKey = new byte[32]; var keyBytes = Encoding.UTF8.GetBytes(this.config.PreSharedKey); Buffer.BlockCopy(keyBytes, 0, paddedKey, 0, keyBytes.Length); using (var aesGcm = new AesGcm(paddedKey)) { aesGcm.Encrypt(iv, httpMessage, cipherText, tag); } request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_ENCRYPTION_MODE, Value = new byte[] { (byte)FfEncryptionMode.AES_256_GCM } }); request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_ENCRYPTION_IV, Value = iv }); request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_ENCRYPTION_TAG, Value = tag }); return(cipherText); }
internal async Task <List <UdpPacket> > CreateRequestPackets(HttpRequestMessage httpRequest) { Debug.WriteLine("Sending HTTP request using FfClient"); var requestIdBytes = new byte[8]; this.rng.GetBytes(requestIdBytes); var request = new FfRequest() { Version = FfRequestVersion.V1, RequestId = BitConverter.ToUInt64(requestIdBytes) }; if (httpRequest.RequestUri.Scheme.ToLower() == "https") { request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_HTTPS, Value = new byte[] { 1 } }); } byte[] httpMessage = await this.SerializeHttpMessage(httpRequest); if (!string.IsNullOrEmpty(this.config.PreSharedKey)) { httpMessage = this.EncryptHttpMessage(httpMessage, request); } request.Options.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_EOL }); request.Payload = httpMessage; return(this.PacketiseRequest(request)); }
private void CreateRequestSecureOptions(FfRequest request, HttpRequestMessage httpRequest) { if (httpRequest.RequestUri.Scheme.ToLower() == "https") { request.SecureOptions.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_HTTPS, Value = new byte[] { 1 } }); } request.SecureOptions.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_TIMESTAMP, Value = this.GetCurrentTimestampBytes() }); request.SecureOptions.Add(new FfRequestOption() { OptionType = FfRequestOption.Type.TYPE_EOL }); }
internal async Task <List <UdpPacket> > CreateRequestPackets(HttpRequestMessage httpRequest) { Debug.WriteLine("Sending HTTP request using FfClient"); var requestIdBytes = new byte[8]; this.rng.GetBytes(requestIdBytes); var request = new FfRequest() { Version = FfRequestVersion.V1, RequestId = BitConverter.ToUInt64(requestIdBytes) }; this.CreateRequestSecureOptions(request, httpRequest); byte[] secureOptions = this.SerializeRequestOptions(request.SecureOptions); byte[] httpMessage = await this.SerializeHttpMessage(httpRequest); byte[] payload = new byte[secureOptions.Length + httpMessage.Length]; Buffer.BlockCopy(secureOptions, 0, payload, 0, secureOptions.Length); Buffer.BlockCopy(httpMessage, 0, payload, secureOptions.Length, httpMessage.Length); if (!string.IsNullOrEmpty(this.config.PreSharedKey)) { payload = this.EncryptPayload(payload, request); } request.Options.Add(new FfRequestOption() { OptionType = request.SecureOptions.Count == 0 ? FfRequestOption.Type.TYPE_EOL : FfRequestOption.Type.TYPE_BREAK }); request.Payload = payload; return(this.PacketiseRequest(request)); }