Ejemplo n.º 1
0
        public async Task AddRecord(PasswordRecord record, string folderUid)
        {
            IFolderNode node = null;

            if (!string.IsNullOrEmpty(folderUid))
            {
                userFolders.TryGetValue(folderUid, out node);
            }
            var recordKey = CryptoUtils.GenerateEncryptionKey();
            var recordAdd = new RecordAddCommand
            {
                recordUid  = CryptoUtils.GenerateUid(),
                recordKey  = CryptoUtils.EncryptAesV1(recordKey, Auth.DataKey).Base64UrlEncode(),
                recordType = "password"
            };

            if (node == null)
            {
                recordAdd.folderType = "user_folder";
            }
            else
            {
                switch (node.Type)
                {
                case FolderType.UserFolder:
                    recordAdd.folderType = "user_folder";
                    recordAdd.folderUid  = node.FolderUid;
                    break;

                case FolderType.SharedFolder:
                case FolderType.SharedFolderForder:
                    recordAdd.folderUid  = node.FolderUid;
                    recordAdd.folderType = node.Type == FolderType.SharedFolder ? "shared_folder" : "shared_folder_folder";
                    if (node is ISharedFolderNode sfn)
                    {
                        if (sharedFolders.TryGetValue(sfn.SharedFolderUid, out SyncDownSharedFolder sf))
                        {
                            recordAdd.folderKey = CryptoUtils.EncryptAesV1(recordKey, sf.unencryptedSharedFolderKey).Base64UrlEncode();
                        }
                    }
                    if (string.IsNullOrEmpty(recordAdd.folderKey))
                    {
                        throw new Exception(string.Format("Cannot resolve shared folder for folder UID", folderUid));
                    }
                    break;
                }
            }
            var settings = new DataContractJsonSerializerSettings
            {
                UseSimpleDictionaryFormat = true
            };
            var dataSerializer = new DataContractJsonSerializer(typeof(RecordData), settings);
            var data           = record.ExtractRecordData();

            using (var ms = new MemoryStream())
            {
                dataSerializer.WriteObject(ms, data);
                recordAdd.data = CryptoUtils.EncryptAesV1(ms.ToArray(), recordKey).Base64UrlEncode();
            }

            await Auth.ExecuteAuthCommand <RecordAddCommand>(recordAdd);

            await this.SyncDown();
        }
Ejemplo n.º 2
0
        public async Task SaveRecord(PasswordRecord record, bool skipData = false, bool skipExtra = true)
        {
            SyncDownRecord existingRecord = null;

            if (!string.IsNullOrEmpty(record.Uid))
            {
                records.TryGetValue(record.Uid, out existingRecord);
            }
            var updateRecord = new RecordUpdateRecord();

            byte[] recordKey = null;
            if (existingRecord != null)
            {
                updateRecord.recordUid = existingRecord.recordUid;
                recordKey = existingRecord.unencryptedRecordKey;
                if (metaData.TryGetValue(existingRecord.recordUid, out SyncDownRecordMetaData sdrmd))
                {
                    if (sdrmd.recordKeyType == 2)
                    {
                        updateRecord.recordKey = CryptoUtils.EncryptAesV1(recordKey, Auth.DataKey).Base64UrlEncode();
                    }
                }
                updateRecord.revision = existingRecord.revision;
                ResolveRecordAccessPath(updateRecord);
            }
            else
            {
                updateRecord.recordUid = CryptoUtils.GenerateUid();
                recordKey = CryptoUtils.GenerateEncryptionKey();
                updateRecord.recordKey = CryptoUtils.EncryptAesV1(recordKey, Auth.DataKey).Base64UrlEncode();
                updateRecord.revision  = 0;
            }
            var settings = new DataContractJsonSerializerSettings
            {
                UseSimpleDictionaryFormat = true
            };

            if (!skipData)
            {
                var        dataSerializer = new DataContractJsonSerializer(typeof(RecordData), settings);
                RecordData existingData   = null;
                if (existingRecord != null)
                {
                    try
                    {
                        var unencrypted_data = CryptoUtils.DecryptAesV1(existingRecord.data.Base64UrlDecode(), existingRecord.unencryptedRecordKey);
                        using (var ms = new MemoryStream(unencrypted_data))
                        {
                            existingData = (RecordData)dataSerializer.ReadObject(ms);
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", existingRecord.recordUid, e.GetType().Name, e.Message);
                    }
                }
                var data = record.ExtractRecordData(existingData);
                using (var ms = new MemoryStream())
                {
                    dataSerializer.WriteObject(ms, data);
                    updateRecord.data = CryptoUtils.EncryptAesV1(ms.ToArray(), recordKey).Base64UrlEncode();
                }
            }
            if (!skipExtra)
            {
                var         extraSerializer = new DataContractJsonSerializer(typeof(RecordExtra), settings);
                RecordExtra existingExtra   = null;
                if (existingRecord != null)
                {
                    try
                    {
                        var unencrypted_extra = CryptoUtils.DecryptAesV1(existingRecord.extra.Base64UrlDecode(), existingRecord.unencryptedRecordKey);
                        using (var ms = new MemoryStream(unencrypted_extra))
                        {
                            existingExtra = (RecordExtra)extraSerializer.ReadObject(ms);
                        }
                    }
                    catch (Exception e)
                    {
                        Trace.TraceError("Decrypt Record: UID: {0}, {1}: \"{2}\"", existingRecord.recordUid, e.GetType().Name, e.Message);
                    }
                }
                var extra = record.ExtractRecordExtra(existingExtra);
                using (var ms = new MemoryStream())
                {
                    extraSerializer.WriteObject(ms, extra);
                    updateRecord.extra = CryptoUtils.EncryptAesV1(ms.ToArray(), recordKey).Base64UrlEncode();
                }
                var udata = new RecordUpdateUData();
                var ids   = new HashSet <string>();
                if (record.Attachments != null)
                {
                    foreach (var atta in record.Attachments)
                    {
                        ids.Add(atta.Id);
                        if (atta.Thumbnails != null)
                        {
                            foreach (var thumb in atta.Thumbnails)
                            {
                                ids.Add(thumb.Id);
                            }
                        }
                    }
                }
                udata.fileIds      = ids.ToArray();
                updateRecord.udata = udata;
            }

            var command = new RecordUpdateCommand();

            if (existingRecord != null)
            {
                command.updateRecords = new RecordUpdateRecord[] { updateRecord };
            }
            else
            {
                command.addRecords = new RecordUpdateRecord[] { updateRecord };
            }

            var rs = await Auth.ExecuteAuthCommand <RecordUpdateCommand, RecordUpdateResponse>(command);

            await this.SyncDown();
        }
Ejemplo n.º 3
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);
                }
            }
        }