예제 #1
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");
        }
예제 #2
0
        public async Task Login(IUserConfiguration user = null)
        {
            var configuration = Api.Storage.Get();

            user = await ResolveUserConfiguration(user, configuration);

            var username = user?.Username;
            var password = user?.Password;

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            {
                return;
            }
            var token     = user.TwoFactorToken;
            var tokenType = "device_token";

            string           authHash = null;
            PreLoginResponse preLogin = null;

            while (true)
            {
                if (preLogin == null)
                {
                    preLogin = await Api.GetPreLogin(username);

                    authHash = null;
                }

                var    authParams = preLogin.Salt[0];
                int    iterations = authParams.Iterations;
                byte[] salt       = authParams.Salt_.ToByteArray();
                if (authHash == null)
                {
                    authHash = CryptoUtils.DeriveV1KeyHash(password, salt, iterations).Base64UrlEncode();
                }

                var command = new LoginCommand();
                command.username                 = username;
                command.authResponse             = authHash;
                command.include                  = new[] { "keys", "settings", "enforcements", "is_enterprise_admin" };
                command.twoFactorToken           = token;
                command.twoFactorType            = !string.IsNullOrEmpty(token) ? tokenType : null;
                command.deviceTokenExpiresInDays = !string.IsNullOrEmpty(token) && tokenType != "device_token" ? 9999 : (int?)null;

                var loginRs = await Api.ExecuteV2Command <LoginCommand, LoginResponse>(command);

                if (!loginRs.IsSuccess && loginRs.resultCode == "auth_failed") // invalid password
                {
                    throw new Exception("Invalid user name or password");
                }
                else
                {
                    if (!string.IsNullOrEmpty(loginRs.deviceToken))
                    {
                        token     = loginRs.deviceToken;
                        tokenType = "device_token";
                    }

                    SessionToken    = loginRs.sessionToken;
                    Username        = username;
                    accountSettings = loginRs.accountSettings;

                    if (loginRs.keys != null)
                    {
                        if (loginRs.keys.encryptedDataKey != null)
                        {
                            var key = CryptoUtils.DeriveKeyV2("data_key", password, salt, iterations);
                            DataKey = CryptoUtils.DecryptAesV2(loginRs.keys.encryptedDataKey.Base64UrlDecode(), key);
                        }
                        else
                        if (loginRs.keys.encryptionParams != null)
                        {
                            DataKey = CryptoUtils.DecryptEncryptionParams(password, loginRs.keys.encryptionParams.Base64UrlDecode());
                        }
                        else
                        {
                            throw new Exception("Missing data key");
                        }
                        if (loginRs.keys.encryptedPrivateKey != null)
                        {
                            privateKeyData = CryptoUtils.DecryptAesV1(loginRs.keys.encryptedPrivateKey.Base64UrlDecode(), DataKey);
                            privateKey     = null;
                        }
                    }
                    if (loginRs.IsSuccess)
                    {
                        EncryptedPassword = CryptoUtils.EncryptAesV2(Encoding.UTF8.GetBytes(password), DataKey);
                        TwoFactorToken    = token;
                        authResponse      = authHash;
                        IsEnterpriseAdmin = loginRs.isEnterpriseAdmin ?? false;
                        enforcements      = loginRs.enforcements;
                        StoreConfigurationIfChanged(configuration);
                        break;
                    }
                    switch (loginRs.resultCode)
                    {
                    case "need_totp":
                    case "invalid_device_token":
                    case "invalid_totp":
                        token = await Ui.GetTwoFactorCode();

                        if (!string.IsNullOrEmpty(token))
                        {
                            tokenType = "one_time";
                            continue;
                        }
                        break;

                    case "auth_expired":
                        await Ui.DisplayDialog(DialogType.Information, loginRs.message);

                        password = await this.ChangeMasterPassword(iterations);

                        if (!string.IsNullOrEmpty(password))
                        {
                            preLogin = null;
                            continue;
                        }
                        break;

                    case "auth_expired_transfer":
                        var shareAccountTo = loginRs.accountSettings.shareAccountTo;
                        if (await Ui.DisplayDialog(DialogType.Confirmation, "Do you accept Account Transfer policy?"))
                        {
                            await this.ShareAccount();

                            continue;
                        }
                        break;
                    }
                    throw new KeeperApiException(loginRs.resultCode, loginRs.message);
                }
            }
        }