func initStore(path string, m secret.ScryptMode) error { passphrase, err := util.PassPrompt("Secrets passphrase> ") if err != nil { util.Errorf("Failed to read passphrase: %v", err) return err } if len(passphrase) == 0 { return fmt.Errorf("No passphrase provided.") } defer util.Zero(passphrase) passwords := store.NewSecretStore(passphrase) if passwords == nil { return fmt.Errorf("failed to create store") } fmt.Println("creating store...") fileData, ok := store.MarshalSecretStore(passwords, m) if !ok { return fmt.Errorf("failed to marshal store") } err = util.WriteFile(fileData, path) if err != nil { return err } passwords, ok = store.UnmarshalSecretStore(fileData, passphrase, m) if !ok { err = fmt.Errorf("failed to unmarshal store") } return err }
func merge(ps *store.SecretStore, cfg *config, m secret.ScryptMode) error { otherPath := cfg.Args[0] passphrase, err := util.PassPrompt("Passphrase for other store> ") if err != nil { return err } otherData, err := util.ReadFile(otherPath) if err != nil { return err } otherStore, ok := store.UnmarshalSecretStore(otherData, passphrase, m) if !ok { return errors.New("failed to open other password store") } mergeList := ps.Merge(otherStore) fmt.Printf("%+v\n", mergeList) if len(mergeList) > 0 { sort.Strings(mergeList) for _, label := range mergeList { fmt.Printf("Merged '%s'\n", label) } } return nil }
func loadStore(path string, m secret.ScryptMode) *store.SecretStore { passphrase, err := util.PassPrompt("Secrets passphrase> ") if err != nil { util.Errorf("Failed to read passphrase: %v", err) return nil } var passwords *store.SecretStore if ok, _ := util.Exists(path); ok { defer util.Zero(passphrase) fileData, err := util.ReadFile(path) if err != nil { util.Errorf("%v", err) return nil } var ok bool passwords, ok = store.UnmarshalSecretStore(fileData, passphrase, m) if !ok { return nil } return passwords } util.Errorf("could not find %s", path) return nil }
func passwd(args []string) error { newPass, err := util.PassPrompt("New password: "******"Confirm: ") if err != nil { return err } if !bytes.Equal(confirmPass, newPass) { return errors.New("passwords don't match") } util.Zero(confirmPass) session.Store.ChangePassword(newPass) fmt.Println("[+] Password updated.") return nil }
func loadStore(path string) *store.KeyStore { // If keystore is newly created, we'll want to write it to // disk before leaving this function. var flush bool if exists, _ := util.Exists(path); !exists { flush = true } passphrase, err := util.PassPrompt("keystore passphrase> ") if err != nil { util.Errorf("%v", err) return nil } defer util.Zero(passphrase) keystore, ok := store.LoadKeyStore(path, true) if !ok { fmt.Printf("error in LoadKeyStore") return nil } if !keystore.Valid(false) { fmt.Println("keystore not valid") return nil } if !flush { if !keystore.Unlock(passphrase) { return nil } return keystore } if !keystore.LockWith(passphrase) { util.Errorf("Failed to set initial passphrase.") return nil } else if !keystore.Unlock(passphrase) { util.Errorf("Flushing keystore failed.") return nil } out, err := keystore.Dump() if err != nil { log.Printf("WARNING: failed to dump keystore: %v", err) return nil } err = ioutil.WriteFile(path, out, 0644) if err != nil { log.Printf("WARNING: failed to write keystore: %v", err) } return keystore }
func main() { baseFile := filepath.Join(os.Getenv("HOME"), ".secrets.db") flag.StringVar(&session.Path, "f", baseFile, "path to password store") flag.DurationVar(&defaultTimeout, "t", defaultTimeout, "`timeout`") scryptInteractive := flag.Bool("i", false, "use scrypt interactive") flag.Parse() if defaultTimeout > maxTimeout { fmt.Fprintf(os.Stderr, "[!] timeout is too long (max is %s).\n", maxTimeout) os.Exit(1) } session.Scrypt = secret.ScryptStandard if *scryptInteractive { session.Scrypt = secret.ScryptInteractive } prompt := fmt.Sprintf("Passphrase to unlock %s: ", session.Path) passphrase, err := util.PassPrompt(prompt) if err != nil { fmt.Fprintf(os.Stderr, "[!] %v\n", err) os.Exit(1) } fileData, err := ioutil.ReadFile(session.Path) if err != nil { fmt.Fprintf(os.Stderr, "[!] %v\n", err) os.Exit(1) } var ok bool session.Store, ok = store.UnmarshalSecretStore(fileData, passphrase, session.Scrypt) if !ok { fmt.Fprintf(os.Stderr, "[!] failed to unlocked store.\n") os.Exit(1) } defer shutdown() inputLoop(session.Path) }
func multi(ps *store.SecretStore, cfg *config, m secret.ScryptMode) error { fmt.Println("Use an empty name to indicate that you are done.") for { name, err := util.ReadLine("Name: ") if err != nil { return err } else if name == "" { break } var rec *store.SecretRecord if ps.Has(name) { if !cfg.Overwrite { util.Errorf("Entry exists, not forcing overwrite.") continue } else { util.Errorf("*** WARNING: overwriting password") } rec = ps.Store[name] } else { rec = &store.SecretRecord{ Label: name, } } password, err := util.PassPrompt("Password: "******"No password entered.") continue } rec.Secret = password rec.Timestamp = time.Now().Unix() ps.Store[name] = rec } return nil }
func unlockStore(ks *store.KeyStore) bool { if !ks.Locked() { return true } passphrase, err := util.PassPrompt("keystore passphrase> ") if err != nil { util.Errorf("%v", err) return false } defer util.Zero(passphrase) if !ks.Locked() && ks.PrivateKey == nil { if !ks.LockWith(passphrase) { util.Errorf("Failed to set initial passphrase.") return false } } if !ks.Unlock(passphrase) { util.Errorf("Unlock failed (bad passphrase?)") return false } return true }
func addSecret(ps *store.SecretStore, cfg *config) error { label := cfg.Args[0] if ps.Has(label) { if cfg.Overwrite { util.Errorf("WARNING: a token already exists under this label!") } else { return errors.New("token already exists under label") } } // Default prompt is echoing, which we want here. secret, err := util.PassPrompt("Secret: ") if err != nil { return err } var rec *store.SecretRecord secret = sanitiseSecret(secret) switch cfg.OTPType { case HOTP: in, err := util.ReadLine("Initial counter (0): ") if err != nil { return err } if in == "" { in = "0" } d, err := strconv.Atoi(in) if err != nil { return err } in, err = util.ReadLine("Digits (6 or 8): ") if err != nil { return err } else if in == "" { in = "6" } digits, err := strconv.Atoi(in) if err != nil { return err } key, err := base32.StdEncoding.DecodeString(string(secret)) if err != nil { fmt.Printf("%s", secret) return err } var hotp *twofactor.HOTP hotp = twofactor.NewHOTP(key, uint64(d), digits) confirmation := hotp.OTP() fmt.Printf("Confirmation: %s\n", confirmation) rec = &store.SecretRecord{ Label: label, Secret: []byte(hotp.URL(label)), Timestamp: time.Now().Unix(), Metadata: map[string][]byte{ "key": secret, "type": []byte("HOTP"), "confirmation": []byte(confirmation), }, } case TOTP: in, err := util.ReadLine("Time step (30s): ") if err != nil { return err } if in == "" { in = "30s" } d, err := time.ParseDuration(in) if err != nil { return err } in, err = util.ReadLine("Digits (6 or 8): ") if err != nil { return err } else if in == "" { in = "6" } digits, err := strconv.Atoi(in) if err != nil { return err } key, err := base32.StdEncoding.DecodeString(string(secret)) if err != nil { return err } var totp *twofactor.TOTP totp = twofactor.NewTOTPSHA1(key, 0, uint64(d.Seconds()), digits) confirmation := totp.OTP() fmt.Printf("Confirmation: %s\n", confirmation) rec = &store.SecretRecord{ Label: label, Secret: []byte(totp.URL(label)), Timestamp: time.Now().Unix(), Metadata: map[string][]byte{ "key": secret, "type": []byte("TOTP-SHA1"), "step": []byte(d.String()), "confirmation": []byte(confirmation), }, } case GoogleTOTP: var totp *twofactor.TOTP totp, err = twofactor.NewGoogleTOTP(string(secret)) if err != nil { return err } confirmation := totp.OTP() fmt.Printf("Confirmation: %s\n", confirmation) rec = &store.SecretRecord{ Label: label, Secret: []byte(totp.URL(label)), Timestamp: time.Now().Unix(), Metadata: map[string][]byte{ "key": secret, "type": []byte("TOTP-GOOGLE"), "step": []byte("30s"), "confirmation": []byte(confirmation), }, } default: return errors.New("unrecognised OTP type") } ps.Store[label] = rec return nil }