Example #1
0
        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");
        }
Example #2
0
        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));
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }
Example #5
0
        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));
                    }
                }
Example #6
0
        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;
 }