// UnlockKeys decrypts the item encryption keys for // a vault using the master password and returns a dictionary // mapping key name to key data or an instance of DecryptError // if the password is wrong func UnlockKeys(vaultPath string, pwd string) (KeyDict, error) { var keyList encryptionKeys err := jsonutil.ReadFile(vaultDataDir(vaultPath)+"/encryptionKeys.js", &keyList) if err != nil { return KeyDict{}, errors.New("Failed to read encryption key file") } keys := KeyDict{} for _, entry := range keyList.List { if len(entry.Data) != 1056 { return KeyDict{}, fmt.Errorf("Unexpected encrypted key length: %d", len(entry.Data)) } salt, encryptedKey, err := extractSaltAndCipherText(entry.Data) if err != nil { return KeyDict{}, fmt.Errorf("Invalid encrypted data: %v", err) } decryptedKey, err := decryptKey([]byte(pwd), encryptedKey, salt, entry.Iterations, entry.Validation) if err != nil { return KeyDict{}, DecryptError{err: fmt.Errorf("Failed to decrypt main key: %v", err)} } keys[entry.Level] = decryptedKey } return keys, nil }
func (vault *Vault) LoadItem(uuid string) (Item, error) { item := Item{ vault: vault, } err := jsonutil.ReadFile(vault.DataDir()+"/"+uuid+".1password", &item) if err != nil { return Item{}, err } return item, nil }
// Returns a list of all items in the vault. // Returned items have their main content still encrypted func (vault *Vault) ListItems() ([]Item, error) { items := []Item{} dirEntries, err := ioutil.ReadDir(vault.DataDir()) if err != nil { return items, err } for _, item := range dirEntries { if path.Ext(item.Name()) == ".1password" { itemData := Item{vault: vault} err := jsonutil.ReadFile(vault.DataDir()+"/"+item.Name(), &itemData) if err != nil { fmt.Printf("Failed to read item: %s: %v\n", item.Name(), err) } else if itemData.TypeName != "system.Tombstone" { items = append(items, itemData) } } } return items, nil }
// Save item to the vault. The item's UpdatedAt // timestamp is updated to the current time and // CreatedAt is also set to the current time if // it was not previously set. func (item *Item) Save() error { if len(item.Encrypted) == 0 { return fmt.Errorf("Item content not set") } item.UpdatedAt = uint64(time.Now().Unix()) if item.CreatedAt == 0 { item.CreatedAt = item.UpdatedAt } // save item to .1password file itemPath := item.Path() err := jsonutil.WriteFile(itemPath, item) if err != nil { return fmt.Errorf("Failed to save item %s: %v", item.Title, err) } // update contents.js entry contentsFilePath := item.vault.DataDir() + "/contents.js" var contentsEntries [][]interface{} err = jsonutil.ReadFile(contentsFilePath, &contentsEntries) if err != nil { return fmt.Errorf("Failed to read contents.js: %v", err) } foundExisting := false for i, entry := range contentsEntries { tmpItem := readContentsEntry(entry) if tmpItem.Uuid == item.Uuid { contentsEntries[i] = item.contentsEntry() foundExisting = true break } } if !foundExisting { contentsEntries = append(contentsEntries, item.contentsEntry()) } err = jsonutil.WriteFile(contentsFilePath, contentsEntries) if err != nil { return fmt.Errorf("Failed to update contents.js: %v", err) } return nil }
// Changes the master password for the vault. The main encryption key // is first decrypted using the current password, then re-encrypted // using the new password func (vault *Vault) SetMasterPassword(currentPwd string, newPwd string) error { var keyList encryptionKeys keyFilePath := vault.DataDir() + "/encryptionKeys.js" err := jsonutil.ReadFile(keyFilePath, &keyList) if err != nil { return errors.New("Failed to read encryption key file") } for i, entry := range keyList.List { if len(entry.Data) != 1056 { return fmt.Errorf("Unexpected encrypted key length: %d", len(entry.Data)) } salt, encryptedKey, err := extractSaltAndCipherText(entry.Data) if err != nil { return fmt.Errorf("Invalid encrypted key: %v", err) } decryptedKey, err := decryptKey([]byte(currentPwd), encryptedKey, salt, entry.Iterations, entry.Validation) if err != nil { return fmt.Errorf("Failed to decrypt main key: %v", err) } // re-encrypt key with new password newSalt := randomBytes(8) newEncryptedKey, newValidation, err := encryptKey([]byte(newPwd), decryptedKey, newSalt, entry.Iterations) if err != nil { return fmt.Errorf("Failed to re-encrypt main key: %v", err) } entry.Data = []byte(fmt.Sprintf("Salted__%s%s", newSalt, newEncryptedKey)) entry.Validation = newValidation keyList.List[i] = entry } err = saveEncryptionKeys(vault.DataDir(), keyList) if err != nil { return fmt.Errorf("Failed to save updated keys: %v", err) } return nil }
// Remove the item's data files from the vault func (item *Item) removeDataFiles() error { itemDataFile := item.Path() // remove contents.js entry contentsFilePath := item.vault.DataDir() + "/contents.js" var contentsEntries [][]interface{} err := jsonutil.ReadFile(contentsFilePath, &contentsEntries) if err != nil { return fmt.Errorf("Failed to read contents.js: %v", err) } foundExisting := false newContentsEntries := [][]interface{}{} for _, entry := range contentsEntries { tmpItem := readContentsEntry(entry) if tmpItem.Uuid == item.Uuid { foundExisting = true } else { newContentsEntries = append(newContentsEntries, entry) } } if !foundExisting { return fmt.Errorf("Entry '%s' (ID: %s) not found", item.Title, item.Uuid) } err = jsonutil.WriteFile(contentsFilePath, newContentsEntries) if err != nil { return fmt.Errorf("Failed to update contents.js: %v", err) } // remove .1password data file err = os.Remove(itemDataFile) if err != nil { return fmt.Errorf("Failed to remove item data file: %s: %v", itemDataFile, err) } return nil }
func readConfig() clientConfig { var config clientConfig _ = jsonutil.ReadFile(configPath, &config) return config }