public ApiRequest PrepareApiRequest(IMessage request, byte[] transmissionKey, byte[] sessionToken = null)
        {
            if (transmissionKey == null)
            {
                transmissionKey = _transmissionKey;
            }

            var payload = new ApiRequestPayload
            {
                ApiVersion = 3,
                Payload    = request.ToByteString()
            };

            if (sessionToken != null)
            {
                payload.EncryptedSessionToken = ByteString.CopyFrom(sessionToken);
            }

            var encPayload = CryptoUtils.EncryptAesV2(payload.ToByteArray(), transmissionKey);
            var encKey     = CryptoUtils.EncryptRsa(transmissionKey, KeeperSettings.KeeperPublicKeys[ServerKeyId]);

            return(new ApiRequest()
            {
                EncryptedTransmissionKey = ByteString.CopyFrom(encKey),
                PublicKeyId = ServerKeyId,
                Locale = Locale,
                EncryptedPayload = ByteString.CopyFrom(encPayload)
            });
        }
            public static async Task <NewUserMinimumParams> GetNewUserParams(this IKeeperEndpoint endpoint, string username)
            {
                var authRequest = new DomainPasswordRulesRequest
                {
                    Username = username
                };
                var payload = new ApiRequestPayload
                {
                    Payload = ByteString.CopyFrom(authRequest.ToByteArray())
                };
                var rs = await endpoint.ExecuteRest("authentication/get_domain_password_rules", payload);

                return(NewUserMinimumParams.Parser.ParseFrom(rs));
            }
        /// <summary>
        /// Executes JSON request.
        /// </summary>
        /// <param name="endpoint">Keeper endpoint interface.</param>
        /// <param name="command">Keeper JSON command.</param>
        /// <param name="responseType">Keeper JSON response type.</param>
        /// <returns>Task returning Keeper JSON response.</returns>
        public static async Task <KeeperApiResponse> ExecuteV2Command(this IKeeperEndpoint endpoint, KeeperApiCommand command, Type responseType)
        {
            if (responseType == null)
            {
                responseType = typeof(KeeperApiResponse);
            }
            else if (!typeof(KeeperApiResponse).IsAssignableFrom(responseType))
            {
                responseType = typeof(KeeperApiResponse);
            }

            command.locale        = endpoint.Locale;
            command.clientVersion = endpoint.ClientVersion;

            byte[] rq;
            using (var ms = new MemoryStream())
            {
                var cmdSerializer = new DataContractJsonSerializer(command.GetType(), JsonUtils.JsonSettings);
                cmdSerializer.WriteObject(ms, command);
                rq = ms.ToArray();
            }

            var apiPayload = new ApiRequestPayload()
            {
                Payload = ByteString.CopyFrom(rq)
            };

#if DEBUG
            Debug.WriteLine("Request: " + Encoding.UTF8.GetString(rq));
#endif
            var rs = await endpoint.ExecuteRest("vault/execute_v2_command", apiPayload);

#if DEBUG
            Debug.WriteLine("Response: " + Encoding.UTF8.GetString(rs));
#endif
            using (var ms = new MemoryStream(rs))
            {
                var rsSerializer = new DataContractJsonSerializer(responseType, JsonUtils.JsonSettings);
                return((KeeperApiResponse)rsSerializer.ReadObject(ms));
            }
        }
        /// <summary>
        /// Executes Keeper Protobuf request.
        /// </summary>
        /// <param name="endpoint">Request endpoint.</param>
        /// <param name="request">Protobuf request.</param>
        /// <param name="responseType">Expected response type</param>
        /// <returns>Task returning Protobuf response.</returns>
        /// <seealso cref="IKeeperEndpoint.ExecuteRest"/>
        public async Task <IMessage> ExecuteAuthRest(string endpoint, IMessage request, Type responseType = null)
        {
#if DEBUG
            Debug.WriteLine($"REST Request: endpoint \"{endpoint}\": {request}");
#endif
            var rq = new ApiRequestPayload
            {
                EncryptedSessionToken = ByteString.CopyFrom(authContext.SessionToken),
                ApiVersion            = 3,
            };
            if (request != null)
            {
                rq.Payload = request.ToByteString();
            }

            var rsBytes = await Endpoint.ExecuteRest(endpoint, rq);

            this.ResetKeepAliveTimer();
            if (responseType == null)
            {
                return(null);
            }

            var responseParser = responseType.GetProperty("Parser", BindingFlags.Static | BindingFlags.Public);
            if (responseParser == null)
            {
                throw new KeeperInvalidParameter("ExecuteAuthRest", "responseType", responseType.Name, "Google Protobuf class expected");
            }
            var mp = (MessageParser)(responseParser.GetMethod.Invoke(null, null));

            var response = mp.ParseFrom(rsBytes);
#if DEBUG
            Debug.WriteLine($"REST response: endpoint \"{endpoint}\": {response}");
#endif
            return(response);
        }
        public async Task <byte[]> ExecuteRest(string endpoint, ApiRequestPayload payload)
        {
            var builder = new UriBuilder(Server)
            {
                Path   = "/api/rest/",
                Scheme = "https",
                Port   = 443
            };
            var uri = new Uri(builder.Uri, endpoint);

            var keyId = ServerKeyId;

            payload.ApiVersion = 3;
            var attempt = 0;

            while (attempt < 3)
            {
                attempt++;

                var request = (HttpWebRequest)WebRequest.Create(uri);
                if (WebProxy != null)
                {
                    request.Proxy = WebProxy;
                }

                request.UserAgent   = "KeeperSDK.Net/" + ClientVersion;
                request.ContentType = "application/octet-stream";
                request.Method      = "POST";


                var encPayload = CryptoUtils.EncryptAesV2(payload.ToByteArray(), _transmissionKey);
                var encKey     = CryptoUtils.EncryptRsa(_transmissionKey, KeeperSettings.KeeperPublicKeys[keyId]);
                var apiRequest = new ApiRequest()
                {
                    EncryptedTransmissionKey = ByteString.CopyFrom(encKey),
                    PublicKeyId      = keyId,
                    Locale           = Locale,
                    EncryptedPayload = ByteString.CopyFrom(encPayload)
                };

                HttpWebResponse response;
                try
                {
                    using (var requestStream = request.GetRequestStream())
                    {
                        var p = apiRequest.ToByteArray();
                        await requestStream.WriteAsync(p, 0, p.Length);
                    }
                    response = (HttpWebResponse)request.GetResponse();
                }

                catch (WebException e)
                {
                    response = (HttpWebResponse)e.Response;
                    if (response == null)
                    {
                        throw;
                    }

                    if (response.StatusCode == HttpStatusCode.ProxyAuthenticationRequired)
                    {
                        throw;
                    }
                }

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    SetConfigurationValid(keyId);
                    if (response.ContentType == "application/octet-stream")
                    {
                        using (var ms = new MemoryStream())
                            using (var rss = response.GetResponseStream())
                            {
                                await rss.CopyToAsync(ms);

                                var bytes = ms.ToArray();
                                if (bytes.Length > 0)
                                {
                                    bytes = CryptoUtils.DecryptAesV2(bytes, _transmissionKey);
                                }

                                return(bytes);
                            }
                    }

                    return(null);
                }

                if (response.ContentType == "application/json")
                {
                    using (var ms = new MemoryStream())
                        using (var rss = response.GetResponseStream())
                        {
                            await rss.CopyToAsync(ms);

                            await ms.FlushAsync();

#if DEBUG
                            var jsonData = ms.ToArray();
                            Debug.WriteLine("Error Response: " + Encoding.UTF8.GetString(jsonData));
#endif
                            ms.Seek(0, SeekOrigin.Begin);

                            var serializer = new DataContractJsonSerializer(typeof(KeeperApiErrorResponse));
                            var keeperRs   = serializer.ReadObject(ms) as KeeperApiErrorResponse;
                            switch (keeperRs.Error)
                            {
                            case "key":
                                if (KeeperSettings.KeeperPublicKeys.ContainsKey(keeperRs.KeyId))
                                {
                                    keyId = keeperRs.KeyId;
                                    continue;
                                }

                                break;

                            case "region_redirect":
                                throw new KeeperRegionRedirect(keeperRs.RegionHost);

                            case "bad_request":
                            case "device_not_registered":
                                throw new KeeperInvalidDeviceToken(keeperRs.AdditionalInfo);

                            case "session_token":
                            case "auth_failed":
                                throw new KeeperAuthFailed();

                            case "login_token_expired":
                                throw new KeeperCanceled();
                            }

                            throw new KeeperApiException(keeperRs.Error, keeperRs.Message);
                        }
                }

                throw new Exception("Keeper Api Http error: " + response.StatusCode);
            }

            throw new Exception("Keeper Api error");
        }
Example #6
0
        public async Task <byte[]> ExecuteRest(string endpoint, byte[] payload)
        {
            var builder = new UriBuilder(Server ?? "keepersecurity.com")
            {
                Path   = "/api/rest/",
                Scheme = "https",
                Port   = 443
            };
            var uri = new Uri(builder.Uri, endpoint);

            var apiPayload = new ApiRequestPayload()
            {
                Payload = ByteString.CopyFrom(payload)
            };

            var attempt = 0;

            while (attempt < 3)
            {
                attempt++;

                var request = WebRequest.Create(uri);

                request.ContentType = "application/octet-stream";
                request.Method      = "POST";

                var encPayload = CryptoUtils.EncryptAesV2(apiPayload.ToByteArray(), transmissionKey);
                var encKey     = CryptoUtils.EncryptRsa(transmissionKey, KeeperSettings.KeeperPublicKeys[ServerKeyId]);
                var apiRequest = new ApiRequest()
                {
                    EncryptedTransmissionKey = ByteString.CopyFrom(encKey),
                    PublicKeyId      = ServerKeyId,
                    Locale           = Locale,
                    EncryptedPayload = ByteString.CopyFrom(encPayload)
                };

                using (var requestStream = request.GetRequestStream())
                {
                    var p = apiRequest.ToByteArray();
                    await requestStream.WriteAsync(p, 0, p.Length);
                }

                HttpWebResponse response;
                try
                {
                    response = (HttpWebResponse)request.GetResponse();
                }
                catch (WebException e)
                {
                    response = (HttpWebResponse)e.Response;
                }

                if (response.StatusCode == HttpStatusCode.OK && response.ContentType == "application/octet-stream")
                {
                    using (var ms = new MemoryStream())
                        using (var rss = response.GetResponseStream())
                        {
                            await rss.CopyToAsync(ms);

                            var bytes = ms.ToArray();
                            return(CryptoUtils.DecryptAesV2(bytes, transmissionKey));
                        }
                }

                if (response.ContentType == "application/json")
                {
                    var serializer = new DataContractJsonSerializer(typeof(KeeperApiErrorResponse));
                    using (var rss = response.GetResponseStream())
                    {
                        var keeperRs = serializer.ReadObject(rss) as KeeperApiErrorResponse;
                        switch (keeperRs.Error)
                        {
                        case "key":
                            if (KeeperSettings.KeeperPublicKeys.ContainsKey(keeperRs.KeyId))
                            {
                                ServerKeyId = keeperRs.KeyId;
                                continue;
                            }
                            break;

                        case "region_redirect":
                            throw new KeeperRegionRedirect(keeperRs.RegionHost);

                        case "bad_request":
                            throw new KeeperInvalidDeviceToken();
                        }
                        throw new KeeperApiException(keeperRs.resultCode, keeperRs.message);
                    }
                }
                throw new Exception("Keeper Api Http error: " + response.StatusCode);
            }
            throw new Exception("Keeper Api error");
        }
        protected Task <byte[]> MockExecuteRest(string endpoint, ApiRequestPayload payload, IAuth auth)
        {
            if (auth.Endpoint.Server != DataVault.DefaultEnvironment)
            {
                return(Task.FromException <byte[]>(new KeeperRegionRedirect(DataVault.DefaultEnvironment)));
            }

            byte[] response = null;
            switch (endpoint)
            {
            case "authentication/register_device":
            {
                var device = new Device()
                {
                    EncryptedDeviceToken = ByteString.CopyFrom(CryptoUtils.GetRandomBytes(64)),
                };
                response = device.ToByteArray();
            }
            break;

            case "authentication/start_login":
            {
                var lrs = new LoginResponse
                {
                    EncryptedLoginToken = ByteString.CopyFrom(DataVault.EncryptedLoginToken),
                };
                if (StopAtDeviceApproval)
                {
                    lrs.LoginState = LoginState.DeviceApprovalRequired;
                }
                else if (StopAtTwoFactor)
                {
                    lrs.LoginState = LoginState.Requires2Fa;
                    lrs.Channels.Add(new TwoFactorChannelInfo
                        {
                            ChannelType = TwoFactorChannelType.TwoFaCtTotp,
                            ChannelUid  = ByteString.CopyFrom(CryptoUtils.GetRandomBytes(8)),
                            ChannelName = "Mock",
                        });
                }
                else if (StopAtPassword)
                {
                    lrs.LoginState = LoginState.RequiresAuthHash;
                    lrs.Salt.Add(new Salt
                        {
                            Iterations = DataVault.UserIterations,
                            Salt_      = ByteString.CopyFrom(DataVault.UserSalt),
                            Name       = "Mock",
                            Uid        = ByteString.CopyFrom(CryptoUtils.GetRandomBytes(8)),
                        });
                }
                else
                {
                    lrs.LoginState            = LoginState.LoggedIn;
                    lrs.AccountUid            = ByteString.CopyFrom(DataVault.AccountUid);
                    lrs.PrimaryUsername       = DataVault.UserName;
                    lrs.CloneCode             = ByteString.CopyFrom(CryptoUtils.GetRandomBytes(8));
                    lrs.EncryptedSessionToken = ByteString.CopyFrom(DataVault.SessionToken);
                    var device           = auth.Storage.Devices.List.FirstOrDefault();
                    var devicePrivateKey = CryptoUtils.LoadPrivateEcKey(device.DeviceKey);
                    var devicePublicKey  = CryptoUtils.GetPublicEcKey(devicePrivateKey);
                    lrs.EncryptedDataKey     = ByteString.CopyFrom(CryptoUtils.EncryptEc(DataVault.UserDataKey, devicePublicKey));
                    lrs.EncryptedDataKeyType = EncryptedDataKeyType.ByDevicePublicKey;
                }

                response = lrs.ToByteArray();
            }
            break;

            case "authentication/validate_auth_hash":
            {
                var request          = ValidateAuthHashRequest.Parser.ParseFrom(payload.Payload);
                var expectedPassword = CryptoUtils.DeriveV1KeyHash(DataVault.UserPassword, DataVault.UserSalt, DataVault.UserIterations);
                if (request.AuthResponse.SequenceEqual(expectedPassword))
                {
                    var lrs = new LoginResponse
                    {
                        LoginState            = LoginState.LoggedIn,
                        EncryptedLoginToken   = ByteString.CopyFrom(DataVault.EncryptedLoginToken),
                        AccountUid            = ByteString.CopyFrom(DataVault.AccountUid),
                        PrimaryUsername       = DataVault.UserName,
                        CloneCode             = ByteString.CopyFrom(CryptoUtils.GetRandomBytes(8)),
                        EncryptedSessionToken = ByteString.CopyFrom(DataVault.SessionToken),
                        EncryptedDataKey      = ByteString.CopyFrom(DataVault.EncryptionParams),
                        EncryptedDataKeyType  = EncryptedDataKeyType.ByPassword,
                    };
                    response = lrs.ToByteArray();
                }
                else
                {
                    return(Task.FromException <byte[]>(new KeeperAuthFailed()));
                }
            }
            break;

            case "authentication/request_device_verification":
                StopAtDeviceApproval = false;
                response             = new byte[0];
                break;

            case "authentication/2fa_send_push":
                if (StopAtDeviceApproval)
                {
                    StopAtDeviceApproval = false;
                }

                response = new byte[0];
                break;

            case "authentication/2fa_validate":
                var tfvr = TwoFactorValidateRequest.Parser.ParseFrom(payload.Payload);
                if (tfvr.Value == DataVault.TwoFactorOneTimeToken)
                {
                    StopAtTwoFactor = false;
                    var tfars = new TwoFactorValidateResponse
                    {
                        EncryptedLoginToken = tfvr.EncryptedLoginToken
                    };
                    response = tfars.ToByteArray();
                }
                else
                {
                    return(Task.FromException <byte[]>(new KeeperAuthFailed()));
                }

                break;

            case "vault/execute_v2_command":
                break;

            case "authentication/validate_device_verification_code":
                var vdvcr = ValidateDeviceVerificationCodeRequest.Parser.ParseFrom(payload.Payload);
                if (vdvcr.VerificationCode == DataVault.DeviceVerificationEmailCode)
                {
                    StopAtDeviceApproval = false;
                    response             = new byte[0];
                }
                else
                {
                    return(Task.FromException <byte[]>(new KeeperAuthFailed()));
                }

                break;

            case "login/account_summary":
            {
                response = auth.ProcessAccountSummary().ToByteArray();
            }
            break;
            }

            if (response != null)
            {
                return(Task.FromResult(response));
            }

            return(Task.FromException <byte[]>(new KeeperCanceled()));
        }