public async Task <TLSRequest> DecryptRequest(TLSEnvelope tlsEnvelope)
        {
            Guard.NotNull(tlsEnvelope);
            await this._publicMemberLock.WaitAsync();

            try
            {
                var ar = new TLSRequest();

                byte[] clientDynamicPrivateKey;
                this._server.DynamicPrivateDecryptionKeys.TryGetValue(tlsEnvelope.PrivateKeyHint, out clientDynamicPrivateKey);
                if (clientDynamicPrivateKey == null)
                {
                    throw new Exception(
                              "This should rarely happen. It means, the server has hinted me to private Key I no longer have.");
                }

                RemovePreviousKeys(tlsEnvelope.PrivateKeyHint);

                var dynamicSharedSecret = this._visualCrypt2Service.CalculateAndHashSharedSecret(clientDynamicPrivateKey,
                                                                                                 tlsEnvelope.DynamicPublicKey);
                Debug.WriteLine($"{this.MyId}: TLSDecrypt:  PrivateKeyHint: {tlsEnvelope.PrivateKeyHint}");

                // TLSAuthMode Combined
                byte[] authSecretBytes      = this._server.AuthSecret;
                var    symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, authSecretBytes);
                // End TLSAuthMode Combined

                // TODO: make LRO optional!
                var lro             = new LongRunningOperation(progress => { }, () => { });
                var cipherV2        = VisualCrypt2Formatter.DissectVisualCryptBytes(tlsEnvelope.EncipheredPayload, lro.Context);
                var decryptResponse = this._visualCrypt2Service.BinaryDecrypt(cipherV2,
                                                                              new KeyMaterial64(symmetricKeyMaterial), lro.Context);
                var isIncomingKeyUnusable = false;
                if (!decryptResponse.IsSuccess)
                {
                    // has the server just lost the dynamic keys?
                    this._server.DynamicPrivateDecryptionKeys.TryGetValue(tlsEnvelope.PrivateKeyHint,
                                                                          out clientDynamicPrivateKey);
                    if (clientDynamicPrivateKey == null)
                    {
                        throw new Exception(
                                  "This should rarely happen. It means, the server has hinted me to private Key I no longer have.");
                    }
                    dynamicSharedSecret = this._visualCrypt2Service.CalculateAndHashSharedSecret(clientDynamicPrivateKey,
                                                                                                 this._server.StaticPublicKey);
                    authSecretBytes      = new byte[32];
                    symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, authSecretBytes);
                    var decryptResponse2 = this._visualCrypt2Service.BinaryDecrypt(cipherV2,
                                                                                   new KeyMaterial64(symmetricKeyMaterial), lro.Context);
                    if (!decryptResponse2.IsSuccess)
                    {
                        throw new Exception("Decryption failed in all ways!");
                    }
                    decryptResponse = decryptResponse2;
                    Debug.WriteLine("Decryption succeded in Anonymous mode.");
                    DoReset();
                    isIncomingKeyUnusable = true;
                }

                byte[] tlsDecryptedRequest = decryptResponse.Result.GetBytes();

                ar.IsAuthenticated = true;
                ar.UserId          = this._server.UserId;
                ar.CommandData     = tlsDecryptedRequest;

                if (!isIncomingKeyUnusable)
                {
                    Guard.NotNull(tlsEnvelope.DynamicPublicKey);
                    if (tlsEnvelope.DynamicPublicKeyId == 0)
                    {
                        throw new ArgumentException("A dynamic public key must never have an ID of 0.");
                    }
                    this._server.LatestDynamicPublicKey   = tlsEnvelope.DynamicPublicKey;
                    this._server.LatestDynamicPublicKeyId = tlsEnvelope.DynamicPublicKeyId;
                }
                return(ar);
            }
            finally
            {
                this._publicMemberLock.Release();
            }
        }
Exemple #2
0
        public TLSRequest TLSServerDecryptRequest(TLSEnvelope tlsEnvelope)
        {
            Guard.NotNull(tlsEnvelope);
            var ar = new TLSRequest();

            byte[] serverPrivateKey;             // static or dynamic
            if (tlsEnvelope.PrivateKeyHint == 0) // The client has used server's static public key to encrypt...
            {
                serverPrivateKey = this._serverPrivateKey;
            }
            // ... so we simple use the servers static private key
            else // tlsEnvelope.PrivateKeyHint is the number the server generated earlier
            {
                serverPrivateKey = GetServerDynamicPrivateKeyForUserByPrivateKeyHint(tlsEnvelope.PrivateKeyHint);
            }
            if (serverPrivateKey == null)
            {
                // we lost our dynamic private key b/c of a disk failure and we don't know who sent us what :-(
                return(null);
            }

            byte[] dynamicSharedSecret = this._visualCrypt2Service.CalculateAndHashSharedSecret(serverPrivateKey, tlsEnvelope.DynamicPublicKey);

            Debug.WriteLine($"{this.ServerId}: TLSDecrypt:  PrivateKeyHint: {tlsEnvelope.PrivateKeyHint}");

            // 'TLSAuthMode.Separate'
            byte[] symmetricKeyMaterial = ByteArrays.Concatenate(dynamicSharedSecret, new byte[32]); // no auth, we dont know who the user is
            // End 'TLSAuthMode.Separate'

            var lro             = new LongRunningOperation(progress => { }, () => { });
            var cipherV2        = VisualCrypt2Formatter.DissectVisualCryptBytes(tlsEnvelope.EncipheredPayload, lro.Context);
            var decryptResponse = this._visualCrypt2Service.BinaryDecrypt(cipherV2, new KeyMaterial64(symmetricKeyMaterial), lro.Context);

            if (!decryptResponse.IsSuccess)
            {
                throw new Exception(decryptResponse.Error);
            }

            byte[] tlsDecryptedRequest = decryptResponse.Result.GetBytes();

            // 'TLSAuthMode.Separate'
            var authSecretFromMessage = new byte[32];

            Buffer.BlockCopy(tlsDecryptedRequest, 0, authSecretFromMessage, 0, authSecretFromMessage.Length);

            // must be set even if the user is not authenticated for the case where a new identity is published right now.
            ar.UserId = Encoding.UTF8.GetString(tlsDecryptedRequest, 32, 10);
            // try authenticate
            var authSecret = GetAuthSecret(ar.UserId);

            if (authSecret != null)
            {
                if (ByteArrays.AreAllBytesEqual(authSecretFromMessage, authSecret))
                {
                    ar.IsAuthenticated = true;
                }
            }
            else
            {
                ar.IsAuthenticated = false;
            }

            var requestData = new byte[tlsDecryptedRequest.Length - 32 - 10];

            Buffer.BlockCopy(tlsDecryptedRequest, 32 + 10, requestData, 0, requestData.Length);
            ar.CommandData = requestData;
            // End 'TLSAuthMode.Separate'

            if (ar.IsAuthenticated)
            {
                SaveIncomingDynamicPublicKey(ar.UserId, tlsEnvelope.DynamicPublicKey, tlsEnvelope.DynamicPublicKeyId);
            }

            return(ar);
        }