private void LoadInternal(Stream memory, IKeyAgreementFactory kexFac) { var versionInt = memory.ReadByte(); if (versionInt < 0) { throw new EndOfStreamException(); } var versionByte = (byte)versionInt; bool isClient = (versionByte & 0b0000_1000) != 0; bool hasInit = (versionByte & 0b0001_0000) != 0; bool hasRatchet = (versionByte & 0b0010_0000) != 0; bool hasEcdh = (versionByte & 0b0100_0000) != 0; bool hasServerPublicKey = (versionByte & 0b1000_0000) != 0; if (!isClient) { throw new InvalidOperationException("The provided state is not client state"); } if (hasInit) { if (InitializationNonce == null || InitializationNonce.Length != MicroRatchetContext.InitializationNonceSize) { InitializationNonce = new byte[MicroRatchetContext.InitializationNonceSize]; } memory.Read(InitializationNonce, 0, MicroRatchetContext.InitializationNonceSize); } if (hasEcdh) { LocalEcdhForInit = kexFac.Deserialize(memory); } if (hasServerPublicKey) { if (ServerPublicKey == null || ServerPublicKey.Length != MicroRatchetContext.ExpectedPublicKeySize) { ServerPublicKey = new byte[MicroRatchetContext.ExpectedPublicKeySize]; } memory.Read(ServerPublicKey, 0, MicroRatchetContext.ExpectedPublicKeySize); } if (hasRatchet) { ReadRatchet(memory, kexFac); } Log.Verbose($"Read {memory.Position} bytes of client state"); }
public static new ServerState Load(byte[] source, IKeyAgreementFactory kexFac, int keySize = 32) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (kexFac == null) { throw new ArgumentNullException(nameof(kexFac)); } using var ms = new MemoryStream(source); return(Load(ms, kexFac, keySize)); }
public static new ServerState Load(Stream source, IKeyAgreementFactory kexFac, int keySize = 32) { if (source == null) { throw new ArgumentNullException(nameof(source)); } if (kexFac == null) { throw new ArgumentNullException(nameof(kexFac)); } if (keySize != 32) { throw new InvalidOperationException("Invalid key size"); } var state = new ServerState(keySize); state.LoadInternal(source, kexFac); return(state); }
public static bool MatchMessageToSession(ArraySegment <byte> message, IAesFactory aesfac, IKeyAgreementFactory kexfac, byte[] state) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (aesfac == null) { throw new ArgumentNullException(nameof(aesfac)); } if (kexfac == null) { throw new ArgumentNullException(nameof(kexfac)); } if (state == null) { throw new ArgumentNullException(nameof(state)); } if (message.Count < MinimumMessageSize) { throw new ArgumentException("The message is too small to be a valid message", nameof(message)); } using var mem = new MemoryStream(state); using var s = State.Load(mem, kexfac, 32); if (s == null) { return(false); } if (s != null && s.Ratchets != null && !s.Ratchets.IsEmpty) { byte[][] keys = new byte[s.Ratchets.Count + 1][]; for (int i = 0; i < s.Ratchets.Count; i++) { keys[i] = s.Ratchets[i].ReceiveHeaderKey; if (i == s.Ratchets.Count - 1) { keys[i + 1] = s.Ratchets[i].NextReceiveHeaderKey; } } return(MatchMessageWithMac(message, aesfac, keys) >= 0); } if (s is ServerState ss && ss.FirstReceiveHeaderKey != null) { return(MatchMessageWithMac(message, aesfac, ss.FirstReceiveHeaderKey) >= 0); } return(false); }
protected void ReadRatchet(Stream stream, IKeyAgreementFactory kexFac) { List <EcdhRatchetStep> steps = new List <EcdhRatchetStep>(); bool last = true; bool secondToLast = false; for (; ;) { // check if this is still a ratchet record var b = stream.ReadByte(); stream.Seek(-1, SeekOrigin.Current); if (b < 0 || (b & 0b1110_0000) == 0) { break; } if (last) { var genbytes = new byte[8]; stream.Read(genbytes, 0, 8); genbytes[0] &= 0b0001_1111; var rgeneration = BigEndianBitConverter.ToInt32(genbytes, 0); // hot var sgeneration = BigEndianBitConverter.ToInt32(genbytes, 4); // hot and important var ecdh = kexFac.Deserialize(stream); var nextRootKey = new byte[KeySizeInBytes]; var sHeaderKey = new byte[KeySizeInBytes]; var sNextHeaderKey = new byte[KeySizeInBytes]; var sChainKey = new byte[KeySizeInBytes]; var rHeaderKey = new byte[KeySizeInBytes]; var rNextHeaderKey = new byte[KeySizeInBytes]; var rChainKey = new byte[KeySizeInBytes]; stream.Read(nextRootKey, 0, KeySizeInBytes); // cold stream.Read(sHeaderKey, 0, KeySizeInBytes); // cold stream.Read(sNextHeaderKey, 0, KeySizeInBytes); // cold stream.Read(sChainKey, 0, KeySizeInBytes); // hot and important stream.Read(rHeaderKey, 0, KeySizeInBytes); // cold stream.Read(rNextHeaderKey, 0, KeySizeInBytes); // cold stream.Read(rChainKey, 0, KeySizeInBytes); // hot steps.Add(EcdhRatchetStep.Create(ecdh, nextRootKey, rgeneration, rHeaderKey, rNextHeaderKey, rChainKey, sgeneration, sHeaderKey, sNextHeaderKey, sChainKey)); } else if (secondToLast) { if ((b & 0b1000_0000) != 0) { // send and receive chain var genbytes = new byte[8]; stream.Read(genbytes, 0, 8); genbytes[0] &= 0b0001_1111; var rgeneration = BigEndianBitConverter.ToInt32(genbytes, 0); // hot var sgeneration = BigEndianBitConverter.ToInt32(genbytes, 4); // hot and important var sHeaderKey = new byte[KeySizeInBytes]; var sChainKey = new byte[KeySizeInBytes]; var rHeaderKey = new byte[KeySizeInBytes]; var rChainKey = new byte[KeySizeInBytes]; stream.Read(sHeaderKey, 0, KeySizeInBytes); // cold stream.Read(sChainKey, 0, KeySizeInBytes); // hot and important stream.Read(rHeaderKey, 0, KeySizeInBytes); // cold stream.Read(rChainKey, 0, KeySizeInBytes); // hot steps.Add(EcdhRatchetStep.Create(null, null, rgeneration, rHeaderKey, null, rChainKey, sgeneration, sHeaderKey, null, sChainKey)); } else { // only sending chain - the client starts with only a sending chain as the first generation var genbytes = new byte[4]; stream.Read(genbytes, 0, 4); genbytes[0] &= 0b0001_1111; var sgeneration = BigEndianBitConverter.ToInt32(genbytes, 0); // hot and important var sHeaderKey = new byte[KeySizeInBytes]; var sChainKey = new byte[KeySizeInBytes]; stream.Read(sHeaderKey, 0, KeySizeInBytes); // cold stream.Read(sChainKey, 0, KeySizeInBytes); // hot and important steps.Add(EcdhRatchetStep.Create(null, null, 0, null, null, null, sgeneration, sHeaderKey, null, sChainKey)); } }
private void LoadInternal(Stream memory, IKeyAgreementFactory kexFac) { var versionInt = memory.ReadByte(); if (versionInt < 0) { throw new EndOfStreamException(); } var versionByte = (byte)versionInt; bool isClient = (versionByte & 0b0000_1000) != 0; bool hasInit = (versionByte & 0b0001_0000) != 0; bool hasRatchet = (versionByte & 0b0010_0000) != 0; bool hasEcdh = (versionByte & 0b0100_0000) != 0; bool hasClientPublicKey = (versionByte & 0b1000_0000) != 0; if (isClient) { throw new InvalidOperationException("The provided state is not server state"); } if (hasInit) { if (ClientInitializationNonce == null || ClientInitializationNonce.Length != MicroRatchetContext.InitializationNonceSize) { ClientInitializationNonce = new byte[MicroRatchetContext.InitializationNonceSize]; } if (RootKey == null || RootKey.Length != KeySizeInBytes) { RootKey = new byte[KeySizeInBytes]; } if (FirstSendHeaderKey == null || FirstSendHeaderKey.Length != KeySizeInBytes) { FirstSendHeaderKey = new byte[KeySizeInBytes]; } if (FirstReceiveHeaderKey == null || FirstReceiveHeaderKey.Length != KeySizeInBytes) { FirstReceiveHeaderKey = new byte[KeySizeInBytes]; } if (NextInitializationNonce == null || NextInitializationNonce.Length != MicroRatchetContext.InitializationNonceSize) { NextInitializationNonce = new byte[MicroRatchetContext.InitializationNonceSize]; } memory.Read(ClientInitializationNonce, 0, MicroRatchetContext.InitializationNonceSize); memory.Read(RootKey, 0, KeySizeInBytes); memory.Read(FirstSendHeaderKey, 0, KeySizeInBytes); memory.Read(FirstReceiveHeaderKey, 0, KeySizeInBytes); memory.Read(NextInitializationNonce, 0, MicroRatchetContext.InitializationNonceSize); } if (hasEcdh) { LocalEcdhRatchetStep0 = kexFac.Deserialize(memory); LocalEcdhRatchetStep1 = kexFac.Deserialize(memory); } if (hasClientPublicKey) { if (ClientPublicKey == null || ClientPublicKey.Length != KeySizeInBytes) { ClientPublicKey = new byte[32]; } memory.Read(ClientPublicKey, 0, 32); } if (hasRatchet) { ReadRatchet(memory, kexFac); } Log.Verbose($"Read {memory.Position} bytes of server state"); }
public DeterministicKexFac(IKeyAgreementFactory other, FakeRandomNumberGenerator rng) { _other = other; _rng = rng; }