/// <summary>
        /// This method asks the server for a list of identifiers paired with method
        /// names and -parameter types. This is used when invoking methods server side.
        /// </summary>
        protected override void SyncInterface(Type serviceType,
                                              string username = null, string password = null)
        {
            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                var sw = Stopwatch.StartNew();
                _logger.Debug("Zk authentiation started for: {0}, {1}", username, password);
                //do zk protocol authentication
                var sr = new ZkProtocol();

                // Step 1. Client sends username and ephemeral hash of random number.
                var aRand            = sr.CryptRand();
                var aClientEphemeral = sr.GetClientEphemeralA(aRand);

                // send username and aClientEphemeral to server
                _binWriter.Write((int)MessageType.ZkInitiate);
                _binWriter.Write(username);
                _logger.Debug("username sent to server: {0}", username);

                _binWriter.Write(aClientEphemeral); //always 32 bytes
                _logger.Debug("ClientEphemeral (A) sent to server: {0}", Convert.ToBase64String(aClientEphemeral));

                // get response from server
                var userFound = _binReader.ReadBoolean();
                if (!userFound)
                {
                    _logger.Debug("User not found. InvalidCredentialException thrown.");
                    throw new InvalidCredentialException("authentication failed");
                }
                var salt = _binReader.ReadBytes(32);
                _logger.Debug("Salt received from server: {0}", Convert.ToBase64String(salt));
                var bServerEphemeral = _binReader.ReadBytes(32);
                _logger.Debug("ServerEphemeral (B) received from server: {0}", Convert.ToBase64String(bServerEphemeral));

                // Step 3. Client and server calculate random scramble of ephemeral hash values exchanged.
                var clientScramble = sr.CalculateRandomScramble(aClientEphemeral, bServerEphemeral);

                // Step 4. Client computes session key
                var clientSessionKey = sr.ClientComputeSessionKey(salt, username, password,
                                                                  aClientEphemeral, bServerEphemeral, clientScramble);

                // Step 6. Client creates hash of session key and sends to server. Server creates same key and verifies.
                var clientSessionHash = sr.ClientCreateSessionHash(username, salt, aClientEphemeral,
                                                                   bServerEphemeral, clientSessionKey);
                // send to server and server verifies
                _binWriter.Write((int)MessageType.ZkProof);
                _binWriter.Write(clientSessionHash); //always 32 bytes

                _logger.Debug("ClientSessionKey Hash sent to server: {0}", Convert.ToBase64String(clientSessionHash));

                // get response
                var serverVerified = _binReader.ReadBoolean();
                if (!serverVerified)
                {
                    _logger.Debug("Server verification failed. InvalidCredentialException thrown.");
                    throw new InvalidCredentialException("authentication failed");
                }
                var serverSessionHash       = _binReader.ReadBytes(32);
                var clientServerSessionHash = sr.ServerCreateSessionHash(aClientEphemeral,
                                                                         clientSessionHash, clientSessionKey);
                if (!serverSessionHash.IsEqualTo(clientServerSessionHash))
                {
                    _logger.Debug("Server hash mismatch. InvalidCredentialException thrown. Has received: {0}", Convert.ToBase64String(serverSessionHash));
                    throw new InvalidCredentialException("authentication failed");
                }
                _logger.Debug("Server Hash match. Received from server: {0}", Convert.ToBase64String(serverSessionHash));
                _zkCrypto = new ZkCrypto(clientSessionKey, clientScramble);
                _logger.Debug("Zk authentiation completed successfully.");
                sw.Stop();
                _stats.Log("ZkAuthentication", sw.ElapsedMilliseconds);
            }

            if (!SyncInfoCache.TryGetValue(serviceType, out _syncInfo))
            {
                //write the message type
                _binWriter.Write((int)MessageType.SyncInterface);
                if (null != _zkCrypto)
                {
                    //sync interface with encryption
                    var assemName             = serviceType.ToConfigName();
                    var assemblyNameEncrypted = _zkCrypto.Encrypt(assemName.ConvertToBytes());
                    _binWriter.Write(assemblyNameEncrypted.Length);
                    _binWriter.Write(assemblyNameEncrypted);
                }
                else
                {
                    _binWriter.Write(serviceType.ToConfigName());
                }
                //read sync data
                var len = _binReader.ReadInt32();
                //len is zero when AssemblyQualifiedName not same version or not found
                if (len == 0)
                {
                    throw new TypeAccessException("SyncInterface failed. Type or version of type unknown.");
                }
                var bytes = _binReader.ReadBytes(len);
                if (null != _zkCrypto)
                {
                    _logger.Debug("Encrypted data received from server: {0}", Convert.ToBase64String(bytes));
                    bytes = _zkCrypto.Decrypt(bytes);
                    _logger.Debug("Decrypted data received from server: {0}", Convert.ToBase64String(bytes));
                }
                _syncInfo = _serializer.Deserialize <ServiceSyncInfo>(bytes);
                SyncInfoCache.AddOrUpdate(serviceType, _syncInfo, (t, info) => _syncInfo);
            }
        }
Beispiel #2
0
        public void SimpleProtocolTest()
        {
            var sr       = new ZkProtocol();
            var username = "******";
            var pwd      = "cc3a6a12-0e5b-47fb-ae45-3485e34582d4";

            // prerequisit: generate password hash that would be stored on server
            var pwdHash = sr.HashCredentials(username, pwd);

            // Step 1. Client sends username and ephemeral hash of random number.
            var aRand            = sr.CryptRand();
            var aClientEphemeral = sr.GetClientEphemeralA(aRand);
            // send username and aClientEphemeral to server

            // Step 2. Server looks up username, gets pwd hash, and sends client ephemeral has of params.
            var bRand            = sr.CryptRand();
            var bServerEphemeral = sr.GetServerEphemeralB(pwdHash.Salt, pwdHash.Verifier, bRand);
            // send salt and bServerEphemeral to client
            var clientSalt = pwdHash.Salt;

            // Step 3. Client and server calculate random scramble of ephemeral hash values exchanged.
            var clientScramble = sr.CalculateRandomScramble(aClientEphemeral, bServerEphemeral);
            var serverScramble = sr.CalculateRandomScramble(aClientEphemeral, bServerEphemeral);

            var scrambleSame = clientScramble.IsEqualTo(serverScramble);

            // Step 4. Client computes session key
            var clientSessionKey = sr.ClientComputeSessionKey(clientSalt, username, pwd, aClientEphemeral, bServerEphemeral, clientScramble);

            // Step 5. Server computes session key
            var serverSessionKey = sr.ServerComputeSessionKey(pwdHash.Salt, pwdHash.Key, aClientEphemeral, bServerEphemeral, serverScramble);

            var sessionKeysSame = clientSessionKey.IsEqualTo(serverSessionKey);


            // Step 6. Client creates hash of session key and sends to server. Server creates same key and verifies.
            var clientSessionHash = sr.ClientCreateSessionHash(username, pwdHash.Salt, aClientEphemeral,
                                                               bServerEphemeral, clientSessionKey);
            // send to server and server verifies
            // server validates clientSessionHash is same as serverClientSessionHash
            var serverClientSessionHash = sr.ClientCreateSessionHash(username, pwdHash.Salt, aClientEphemeral,
                                                                     bServerEphemeral, serverSessionKey);

            var clientEqualToServer = clientSessionHash.IsEqualTo(serverClientSessionHash);

            // Step 7. Server creates hash of session key and sends to client. Client creates same key and verifies.
            var serverSessionHash = sr.ServerCreateSessionHash(aClientEphemeral, clientSessionHash, serverSessionKey);
            // server sends serverSessionHash to client
            // validate that serverSessionHash is same as clientServerSessionHash
            var clientServerSessionHash = sr.ServerCreateSessionHash(aClientEphemeral, clientSessionHash, clientSessionKey);

            var serverEqualToClient = serverSessionHash.IsEqualTo(clientServerSessionHash);

            //proof
            Assert.True(sessionKeysSame);
            Assert.True(scrambleSame);
            Assert.True(clientEqualToServer);
            Assert.True(serverEqualToClient);

            var data      = sr.Combine(sr.CryptRand(), sr.CryptRand(), sr.CryptRand());
            var crypto    = new ZkCrypto(clientSessionKey, clientScramble);
            var encrypted = crypto.Encrypt(data);
            var decrypted = crypto.Decrypt(encrypted);
            var cryptSame = data.IsEqualTo(decrypted);

            Assert.True(cryptSame);
        }
Beispiel #3
0
        /// <summary>
        /// This method asks the server for a list of identifiers paired with method
        /// names and -parameter types. This is used when invoking methods server side.
        /// </summary>
        protected override void SyncInterface(Type serviceType,
                                              string username = null, string password = null)
        {
            if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password))
            {
                //do zk protocol authentication
                var sr = new ZkProtocol();

                // Step 1. Client sends username and ephemeral hash of random number.
                var aRand            = sr.CryptRand();
                var aClientEphemeral = sr.GetClientEphemeralA(aRand);

                // send username and aClientEphemeral to server
                _binWriter.Write((int)MessageType.ZkInitiate);
                _binWriter.Write(username);
                _binWriter.Write(aClientEphemeral); //always 32 bytes

                // get response from server
                var userFound = _binReader.ReadBoolean();
                if (!userFound)
                {
                    throw new InvalidCredentialException("authentication failed");
                }
                var salt             = _binReader.ReadBytes(32);
                var bServerEphemeral = _binReader.ReadBytes(32);

                // Step 3. Client and server calculate random scramble of ephemeral hash values exchanged.
                var clientScramble = sr.CalculateRandomScramble(aClientEphemeral, bServerEphemeral);

                // Step 4. Client computes session key
                var clientSessionKey = sr.ClientComputeSessionKey(salt, username, password,
                                                                  aClientEphemeral, bServerEphemeral, clientScramble);

                // Step 6. Client creates hash of session key and sends to server. Server creates same key and verifies.
                var clientSessionHash = sr.ClientCreateSessionHash(username, salt, aClientEphemeral,
                                                                   bServerEphemeral, clientSessionKey);
                // send to server and server verifies
                _binWriter.Write((int)MessageType.ZkProof);
                _binWriter.Write(clientSessionHash); //always 32 bytes

                // get response
                var serverVerified = _binReader.ReadBoolean();
                if (!serverVerified)
                {
                    throw new InvalidCredentialException("authentication failed");
                }
                var serverSessionHash       = _binReader.ReadBytes(32);
                var clientServerSessionHash = sr.ServerCreateSessionHash(aClientEphemeral,
                                                                         clientSessionHash, clientSessionKey);
                if (!serverSessionHash.IsEqualTo(clientServerSessionHash))
                {
                    throw new InvalidCredentialException("authentication failed");
                }
                _zkCrypto = new ZkCrypto(clientSessionKey, clientScramble);
            }

            if (!_syncInfoCache.TryGetValue(serviceType, out _syncInfo))
            {
                //write the message type
                _binWriter.Write((int)MessageType.SyncInterface);
                if (null != _zkCrypto)
                {
                    //sync interface with encryption
                    var assemName             = serviceType.FullName;
                    var assemblyNameEncrypted = _zkCrypto.Encrypt(assemName.ConvertToBytes());
                    _binWriter.Write(assemblyNameEncrypted.Length);
                    _binWriter.Write(assemblyNameEncrypted);
                }
                else
                {
                    _binWriter.Write(serviceType.FullName);
                }
                //read sync data
                var len = _binReader.ReadInt32();
                //len is zero when AssemblyQualifiedName not same version or not found
#if (!NET35)
                if (len == 0)
                {
                    throw new TypeAccessException("SyncInterface failed. Type or version of type unknown.");
                }
#else
                if (len == 0)
                {
                    throw new Exception("SyncInterface failed. Type or version of type unknown.");
                }
#endif
                var bytes = _binReader.ReadBytes(len);
                if (null != _zkCrypto)
                {
                    bytes = _zkCrypto.Decrypt(bytes);
                }
                _syncInfo = bytes.ToDeserializedObject <ServiceSyncInfo>();
                _syncInfoCache.AddOrUpdate(serviceType, _syncInfo, (t, info) => _syncInfo);
            }
        }