Пример #1
0
        public static EcdhRatchetStep InitializeServer(IKeyDerivation kdf, IDigest digest,
                                                       IKeyAgreement previousKeyPair,
                                                       byte[] rootKey, ArraySegment <byte> remotePublicKey, IKeyAgreement keyPair,
                                                       byte[] receiveHeaderKey, byte[] sendHeaderKey)
        {
            if (receiveHeaderKey.Length != 32 || sendHeaderKey.Length != 32)
            {
                throw new InvalidOperationException("Keys need to be 32 bytes.");
            }
            Log.Verbose($"--Initialize ECDH Ratchet");
            Log.Verbose($"Root Key:           {Log.ShowBytes(rootKey)}");
            Log.Verbose($"Prev ECDH Private: ({Log.ShowBytes(previousKeyPair.GetPublicKey())})");
            Log.Verbose($"ECDH Public:        {Log.ShowBytes(remotePublicKey)}");
            Log.Verbose($"Curr ECDH Private: ({Log.ShowBytes(keyPair.GetPublicKey())})");

            var e = new EcdhRatchetStep
            {
                EcdhKey          = keyPair,
                ReceiveHeaderKey = receiveHeaderKey,
                SendHeaderKey    = sendHeaderKey
            };

            // receive chain
            Log.Verbose("  --Receiving Chain");
            var rcderived = previousKeyPair.DeriveKey(remotePublicKey);

            rcderived = digest.ComputeDigest(rcderived);
            Log.Verbose($"  C Input Key:    {Log.ShowBytes(rootKey)}");
            Log.Verbose($"  C Key Info:     {Log.ShowBytes(rcderived)}");
            var rckeys = kdf.GenerateKeys(rcderived, rootKey, 3, 32);

            Log.Verbose($"  C Key Out 0:    {Log.ShowBytes(rckeys[0])}");
            Log.Verbose($"  C Key Out 1:    {Log.ShowBytes(rckeys[1])}");
            Log.Verbose($"  C Key Out 2:    {Log.ShowBytes(rckeys[2])}");
            rootKey = rckeys[0];
            e.ReceivingChain.Initialize(rckeys[1]);
            e.NextReceiveHeaderKey = rckeys[2];

            // send chain
            Log.Verbose("  --Sending Chain");
            var scderived = keyPair.DeriveKey(remotePublicKey);

            scderived = digest.ComputeDigest(scderived);
            Log.Verbose($"  C Input Key:    {Log.ShowBytes(rootKey)}");
            Log.Verbose($"  C Key Info:     {Log.ShowBytes(scderived)}");
            var sckeys = kdf.GenerateKeys(scderived, rootKey, 3, 32);

            Log.Verbose($"  C Key Out 0:    {Log.ShowBytes(sckeys[0])}");
            Log.Verbose($"  C Key Out 1:    {Log.ShowBytes(sckeys[1])}");
            Log.Verbose($"  C Key Out 2:    {Log.ShowBytes(sckeys[2])}");
            rootKey = sckeys[0];
            e.SendingChain.Initialize(sckeys[1]);
            e.NextSendHeaderKey = sckeys[2];

            // next root key
            Log.Verbose($"Next Root Key:     ({Log.ShowBytes(rootKey)})");
            e.NextRootKey = rootKey;
            return(e);
        }
Пример #2
0
        public static byte[][] GenerateKeys(this IKeyDerivation kdf, byte[] key, byte[] info, int numKeys, int keySize)
        {
            byte[]   totalKeyBytes = kdf.GenerateBytes(key, info, keySize * numKeys);
            byte[][] keys          = new byte[numKeys][];

            for (int i = 0; i < numKeys; i++)
            {
                keys[i] = new byte[keySize];
                Array.Copy(totalKeyBytes, i * keySize, keys[i], 0, keySize);
            }

            return(keys);
        }
Пример #3
0
        public static EcdhRatchetStep[] InitializeClient(IKeyDerivation kdf, IDigest digest,
                                                         byte[] rootKey, ArraySegment <byte> remotePublicKey0, ArraySegment <byte> remotePublicKey1, IKeyAgreement keyPair,
                                                         byte[] receiveHeaderKey, byte[] sendHeaderKey,
                                                         IKeyAgreement nextKeyPair)
        {
            if (receiveHeaderKey.Length != 32 || sendHeaderKey.Length != 32)
            {
                throw new InvalidOperationException("Keys need to be 32 bytes.");
            }
            Log.Verbose($"--Initialize ECDH Ratchet CLIENT");
            Log.Verbose($"Root Key:           {Log.ShowBytes(rootKey)}");
            Log.Verbose($"ECDH Public 0:      {Log.ShowBytes(remotePublicKey0)}");
            Log.Verbose($"ECDH Public 1:      {Log.ShowBytes(remotePublicKey1)}");
            Log.Verbose($"ECDH Private:      ({Log.ShowBytes(keyPair.GetPublicKey())})");

            var e0 = new EcdhRatchetStep
            {
                EcdhKey       = keyPair,
                SendHeaderKey = sendHeaderKey
            };

            // receive chain doesn't exist
            Log.Verbose("  --Receiving Chain");

            // send chain
            Log.Verbose("  --Sending Chain");
            var scderived = keyPair.DeriveKey(remotePublicKey0);

            scderived = digest.ComputeDigest(scderived);
            Log.Verbose($"  C Input Key:    {Log.ShowBytes(rootKey)}");
            Log.Verbose($"  C Key Info:     {Log.ShowBytes(scderived)}");
            var sckeys = kdf.GenerateKeys(scderived, rootKey, 3, 32);

            Log.Verbose($"  C Key Out 0:    {Log.ShowBytes(sckeys[0])}");
            Log.Verbose($"  C Key Out 1:    {Log.ShowBytes(sckeys[1])}");
            Log.Verbose($"  C Key Out 2:    {Log.ShowBytes(sckeys[2])}");
            rootKey = sckeys[0];
            e0.SendingChain.Initialize(sckeys[1]);
            var nextSendHeaderKey = sckeys[2];

            var e1 = InitializeServer(kdf, digest,
                                      keyPair,
                                      rootKey,
                                      remotePublicKey1,
                                      nextKeyPair,
                                      receiveHeaderKey,
                                      nextSendHeaderKey);

            return(new[] { e0, e1 });
        }
Пример #4
0
        public EcdhRatchetStep Ratchet(IKeyDerivation kdf, IDigest digest, ArraySegment <byte> remotePublicKey, IKeyAgreement keyPair)
        {
            var nextStep = InitializeServer(kdf, digest,
                                            EcdhKey,
                                            NextRootKey,
                                            remotePublicKey,
                                            keyPair,
                                            NextReceiveHeaderKey,
                                            NextSendHeaderKey);

            NextRootKey          = null;
            EcdhKey              = null;
            NextSendHeaderKey    = null;
            NextReceiveHeaderKey = null;

            return(nextStep);
        }
Пример #5
0
        public (byte[] key, int generation) RatchetForSending(IKeyDerivation kdf)
        {
            // message keys are 128 bit
            var nextKeyBytes = kdf.GenerateBytes(ChainKey, ChainContext, 32 + 16);

            byte[] nextChainKey = new byte[32];
            Array.Copy(nextKeyBytes, nextChainKey, 32);
            byte[] messageKey = new byte[16];
            Array.Copy(nextKeyBytes, 32, messageKey, 0, 16);

            Log.Verbose($"      RTC  #:      {Generation + 1}");
            Log.Verbose($"      RTC IN:      {Log.ShowBytes(ChainKey)}");
            Log.Verbose($"      RTC CK:      {Log.ShowBytes(nextChainKey)}");
            Log.Verbose($"      RTC OK:      {Log.ShowBytes(messageKey)}");

            Generation++;
            ChainKey = nextChainKey;
            return(messageKey, Generation);
        }
Пример #6
0
        public (byte[] key, int generation) RatchetForReceiving(IKeyDerivation kdf, int toGeneration)
        {
            int gen;

            byte[] chain;
            if (toGeneration > Generation)
            {
                gen   = Generation;
                chain = ChainKey;
            }
            else if (toGeneration > OldGeneration && OldChainKey != null)
            {
                gen   = OldGeneration;
                chain = OldChainKey;
            }
            else
            {
                throw new InvalidOperationException("Could not ratchet to the generation because the old keys have been lost");
            }

            bool mustSkip     = toGeneration > Generation && toGeneration - Generation > 1;
            bool incrementOld = toGeneration > OldGeneration && OldChainKey != null && toGeneration == OldGeneration + 1;

            byte[] key = null;
            while (gen < toGeneration)
            {
                Log.Verbose($"      RTC  #:      {gen + 1}");
                Log.Verbose($"      RTC IN:      {Log.ShowBytes(chain)}");

                // message keys are 128 bit
                var    nextKeyBytes = kdf.GenerateBytes(chain, ChainContext, 32 + 16);
                byte[] nextChainKey = new byte[32];
                Array.Copy(nextKeyBytes, nextChainKey, 32);
                byte[] messageKey = new byte[16];
                Array.Copy(nextKeyBytes, 32, messageKey, 0, 16);

                gen++;
                chain = nextChainKey;
                key   = messageKey;

                Log.Verbose($"      RTC CK:      {Log.ShowBytes(nextChainKey)}");
                Log.Verbose($"      RTC OK:      {Log.ShowBytes(messageKey)}");
            }

            if (mustSkip && OldChainKey == null)
            {
                OldChainKey   = ChainKey;
                OldGeneration = Generation;
            }

            if (toGeneration > Generation)
            {
                Generation = gen;
                ChainKey   = chain;
            }

            if (incrementOld)
            {
                OldGeneration++;
                OldChainKey = chain;
            }

            return(key, gen);
        }