// create a new KeyDB. func (ce *CryptEngine) dbCreate(homedir string, iterations int) error { keydbname := filepath.Join(homedir, "keys") // read passphrase log.Infof("read passphrase from fd %d", ce.fileTable.PassphraseFD) scanner := bufio.NewScanner(ce.fileTable.PassphraseFP) var passphrase []byte defer bzero.Bytes(passphrase) if scanner.Scan() { passphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } // read passphrase again log.Infof("read passphrase from fd %d again", ce.fileTable.PassphraseFD) var passphrase2 []byte defer bzero.Bytes(passphrase2) if scanner.Scan() { passphrase2 = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } // compare passphrases if !bytes.Equal(passphrase, passphrase2) { return log.Error("passphrases differ") } // create keyDB log.Infof("create keyDB '%s'", keydbname) if err := keydb.Create(keydbname, passphrase, iterations); err != nil { return err } return nil }
// Close the underlying database of the CtrlEngine. func (ce *CtrlEngine) Close() { if ce.msgDB != nil { // stop service guard client before we close the DB if ce.client != nil { ce.client.GoOffline() } ce.msgDB.Close() ce.msgDB = nil } bzero.Bytes(ce.passphrase) }
func createKeyDB( c *cli.Context, w io.Writer, outputFD uintptr, passphrase []byte, ) error { args := []string{ "--output-fd", strconv.Itoa(int(outputFD)), "--passphrase-fd", "stdin", "--homedir", c.GlobalString("homedir"), "--loglevel", c.GlobalString("loglevel"), "--logdir", c.GlobalString("logdir"), } if c.GlobalBool("logconsole") { args = append(args, "--logconsole") } args = append(args, "db", "create", "--iterations", strconv.Itoa(c.Int("iterations")), ) cmd := exec.Command("mutecrypt", args...) stdin, err := cmd.StdinPipe() if err != nil { return err } var errbuf bytes.Buffer cmd.Stdout = w cmd.Stderr = &errbuf if err := cmd.Start(); err != nil { return err } plen := len(passphrase) buf := make([]byte, plen+1+plen+1) defer bzero.Bytes(buf) copy(buf, passphrase) copy(buf[plen:], []byte("\n")) copy(buf[plen+1:], passphrase) copy(buf[plen+1+plen:], []byte("\n")) if _, err := stdin.Write(buf); err != nil { return err } stdin.Close() if err := cmd.Wait(); err != nil { return fmt.Errorf("%s: %s", err, strings.TrimSpace(errbuf.String())) } return nil }
func (ce *CryptEngine) openKeyDB() error { // read passphrase log.Infof("read passphrase from fd %d", ce.fileTable.PassphraseFD) passphrase, err := util.Readline(ce.fileTable.PassphraseFP) if err != nil { return err } defer bzero.Bytes(passphrase) log.Info("done") // open keyDB keydbname := filepath.Join(ce.homedir, "keys") log.Infof("open keyDB %s", keydbname) ce.keyDB, err = keydb.Open(keydbname, passphrase) if err != nil { return err } return nil }
func rekeyKeyDB(c *cli.Context, oldPassphrase, newPassphrase []byte) error { cmd := exec.Command("mutecrypt", "--passphrase-fd", "stdin", "--homedir", c.GlobalString("homedir"), "--loglevel", c.GlobalString("loglevel"), "--logdir", c.GlobalString("logdir"), "db", "rekey", "--iterations", strconv.Itoa(c.Int("iterations"))) stdin, err := cmd.StdinPipe() if err != nil { return err } var errbuf bytes.Buffer cmd.Stderr = &errbuf if err := cmd.Start(); err != nil { return err } olen := len(oldPassphrase) nlen := len(newPassphrase) buf := make([]byte, olen+1+nlen+1+nlen+1) defer bzero.Bytes(buf) copy(buf, oldPassphrase) copy(buf[olen:], []byte("\n")) copy(buf[olen+1:], newPassphrase) copy(buf[olen+1+nlen:], []byte("\n")) copy(buf[olen+1+nlen+1:], newPassphrase) copy(buf[olen+1+nlen+1+nlen:], []byte("\n")) if _, err := stdin.Write(buf); err != nil { return err } stdin.Close() if err := cmd.Wait(); err != nil { return fmt.Errorf("%s: %s", err, strings.TrimSpace(errbuf.String())) } return nil }
// generateMessageKeys generates the next numOfKeys many session keys from // from rootKey for given senderIdentity and recipientIdentity. // If recipientKeys is true the generated sender and reciever keys are stored in // reverse order. // It uses senderSessionPub and recipientPub in the process and calls // keyStore.StoresSession and keyStore.SetSessionState to store the result. func generateMessageKeys( senderIdentity, recipientIdentity string, senderIdentityPubkeyHash, recipientIdentityPubkeyHash string, rootKey *[32]byte, recipientKeys bool, senderSessionPub, recipientPub *[32]byte, numOfKeys uint64, keyStore session.Store, ) error { var ( identities string send []string recv []string ) // identity_fix = HASH(SORT(SenderNym, RecipientNym)) if senderIdentity < recipientIdentity { identities = senderIdentity + recipientIdentity } else { identities = recipientIdentity + senderIdentity } identityFix := cipher.SHA512([]byte(identities)) recipientPubHash := cipher.SHA512(recipientPub[:]) senderSessionPubHash := cipher.SHA512(senderSessionPub[:]) chainKey := rootKey[:] for i := uint64(0); i < numOfKeys; i++ { // messagekey_send[i] = HMAC_HASH(chainkey, "MESSAGE" | HASH(RecipientPub) | identity_fix) buffer := append([]byte("MESSAGE"), recipientPubHash...) buffer = append(buffer, identityFix...) send = append(send, base64.Encode(cipher.HMAC(chainKey, buffer))) // messagekey_recv[i] = HMAC_HASH(chainkey, "MESSAGE" | HASH(SenderSessionPub) | identity_fix) buffer = append([]byte("MESSAGE"), senderSessionPubHash...) buffer = append(buffer, identityFix...) recv = append(recv, base64.Encode(cipher.HMAC(chainKey, buffer))) // chainkey = HMAC_HASH(chainkey, "CHAIN" ) chainKey = cipher.HMAC(chainKey, []byte("CHAIN"))[:32] } // calculate root key hash rootKeyHash := base64.Encode(cipher.SHA512(rootKey[:])) bzero.Bytes(rootKey[:]) // reverse key material, if necessary if recipientKeys { send, recv = recv, send } // store session var sessionKey string if recipientKeys { key := recipientIdentityPubkeyHash key += senderIdentityPubkeyHash key += base64.Encode(cipher.SHA512(recipientPub[:])) key += base64.Encode(cipher.SHA512(senderSessionPub[:])) sessionKey = base64.Encode(cipher.SHA512([]byte(key))) } else { key := senderIdentityPubkeyHash key += recipientIdentityPubkeyHash key += base64.Encode(cipher.SHA512(senderSessionPub[:])) key += base64.Encode(cipher.SHA512(recipientPub[:])) sessionKey = base64.Encode(cipher.SHA512([]byte(key))) } err := keyStore.StoreSession(sessionKey, rootKeyHash, base64.Encode(chainKey), send, recv) if err != nil { return err } return nil }
func mutecryptNewUID( c *cli.Context, passphrase []byte, id, domain, host, mixaddress, nymaddress string, client *client.Client, ) error { log.Infof("mutecryptNewUID(): id=%s, domain=%s", id, domain) args := []string{ "--homedir", c.GlobalString("homedir"), "--loglevel", c.GlobalString("loglevel"), "--logdir", c.GlobalString("logdir"), } if host != "" { args = append(args, "--keyhost", host, "--keyport", ":8080") // TODO: remove keyport hack! } cmd := exec.Command("mutecrypt", args...) stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } scanner := bufio.NewScanner(stderr) passphraseReader, passphraseWriter, err := os.Pipe() if err != nil { return err } cmd.ExtraFiles = append(cmd.ExtraFiles, passphraseReader) commandReader, commandWriter, err := os.Pipe() if err != nil { return err } cmd.ExtraFiles = append(cmd.ExtraFiles, commandReader) // generate UID _, err = io.WriteString(commandWriter, strings.Join([]string{ "uid", "generate", "--id", id + "\n", }, " ")) if err != nil { return err } // start process if err := cmd.Start(); err != nil { return err } // write passphrase plen := len(passphrase) buf := make([]byte, plen+1) defer bzero.Bytes(buf) copy(buf, passphrase) copy(buf[plen:], []byte("\n")) if _, err := passphraseWriter.Write(buf); err != nil { return err } passphraseWriter.Close() // check for errors on stderr for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } // get capabilities args = []string{"caps", "show", "--domain", domain} if host := c.String("host"); host != "" { args = append(args, "--host", host) } args = append(args, "\n") _, err = io.WriteString(commandWriter, strings.Join(args, " ")) if err != nil { return err } for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } var caps capabilities.Capabilities decoder := json.NewDecoder(stdout) if err := decoder.Decode(&caps); err != nil { return err } /* // pretty-print capabilities jsn, err := json.MarshalIndent(caps, "", " ") if err != nil { return err } fmt.Println(string(jsn)) */ owner, err := decodeED25519PubKeyBase64(caps.TKNPUBKEY) if err != nil { return err } // get token from wallet token, err := wallet.GetToken(client, "UID", owner) if err != nil { return err } // try to register UID _, err = io.WriteString(commandWriter, strings.Join([]string{ "uid", "register", "--id", id, "--token", base64.Encode(token.Token) + "\n", }, " ")) if err != nil { client.UnlockToken(token.Hash) return err } var cryptErr error for scanner.Scan() { line := scanner.Text() if line != "READY." { cryptErr = errors.New(line) } else { break } } if err := scanner.Err(); err != nil { client.UnlockToken(token.Hash) return err } // delete UID, if registration was not successful if cryptErr != nil { client.UnlockToken(token.Hash) _, err = io.WriteString(commandWriter, strings.Join([]string{ "uid", "delete", "--force", "--id", id + "\n", }, " ")) if err != nil { return err } for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } } else { client.DelToken(token.Hash) } // add KeyInit messages token, err = wallet.GetToken(client, "Message", owner) if err != nil { return err } _, err = io.WriteString(commandWriter, strings.Join([]string{ "keyinit", "add", "--id", id, "--mixaddress", mixaddress, "--nymaddress", nymaddress, "--token", base64.Encode(token.Token) + "\n", }, " ")) if err != nil { client.UnlockToken(token.Hash) return err } for scanner.Scan() { line := scanner.Text() if line != "READY." { return errors.New(line) } break } if err := scanner.Err(); err != nil { client.UnlockToken(token.Hash) return err } client.DelToken(token.Hash) // quit mutecrypt if _, err := io.WriteString(commandWriter, "quit\n"); err != nil { return err } for scanner.Scan() { line := scanner.Text() if line != "QUITTING" { return errors.New(line) } break } if err := scanner.Err(); err != nil { return err } if err := cmd.Wait(); err != nil { return err } // propagate error if cryptErr != nil { return cryptErr } return nil }
// create a new MsgDB and KeyDB. func (ce *CtrlEngine) dbCreate( w, statusfp io.Writer, homedir string, c *cli.Context, ) error { msgdbname := filepath.Join(c.GlobalString("homedir"), "msgs") // read passphrase fmt.Fprintf(statusfp, "read passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) var ( scanner *bufio.Scanner passphrase []byte passphrase2 []byte err error ) defer bzero.Bytes(passphrase) defer bzero.Bytes(passphrase2) isTerminal := terminal.IsTerminal(int(ce.fileTable.PassphraseFD)) if isTerminal { passphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { scanner = bufio.NewScanner(ce.fileTable.PassphraseFP) if scanner.Scan() { passphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // read passphrase again fmt.Fprintf(statusfp, "read passphrase from fd %d again (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read passphrase from fd %d again (not echoed)", ce.fileTable.PassphraseFD) if isTerminal { passphrase2, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { if scanner.Scan() { passphrase2 = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // compare passphrases if !bytes.Equal(passphrase, passphrase2) { return log.Error(ErrPassphrasesDiffer) } // create msgDB log.Infof("create msgDB '%s'", msgdbname) if err := msgdb.Create(msgdbname, passphrase, c.Int("iterations")); err != nil { return err } // open msgDB msgDB, err := msgdb.Open(msgdbname, passphrase) if err != nil { return err } defer msgDB.Close() // configure to make sure mutecrypt has config file err = ce.upkeepFetchconf(msgDB, homedir, false, nil, statusfp) if err != nil { return err } // create keyDB log.Info("create keyDB") if err := createKeyDB(c, w, ce.fileTable.OutputFD, passphrase); err != nil { return err } // status fmt.Fprintf(statusfp, "database files created\n") log.Info("database files created") // determine private walletKey walletKey := c.String("walletkey") if walletKey == "" { // generate wallet key _, privateKey, err := ed25519.GenerateKey(cipher.RandReader) if err != nil { return err } walletKey = base64.Encode(privateKey[:]) } // store wallet key if err := msgDB.AddValue(msgdb.WalletKey, walletKey); err != nil { return err } // print wallet key if err := printWalletKey(w, walletKey); err != nil { return err } return nil }
// rekey MsgDB and KeyDB. func (ce *CtrlEngine) dbRekey(statusfp io.Writer, c *cli.Context) error { msgdbname := filepath.Join(c.GlobalString("homedir"), "msgs") // read old passphrase fmt.Fprintf(statusfp, "read old passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read old passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) var ( scanner *bufio.Scanner oldPassphrase []byte newPassphrase []byte newPassphrase2 []byte err error ) defer bzero.Bytes(oldPassphrase) defer bzero.Bytes(newPassphrase) defer bzero.Bytes(newPassphrase2) isTerminal := terminal.IsTerminal(int(ce.fileTable.PassphraseFD)) if isTerminal { oldPassphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { scanner = bufio.NewScanner(ce.fileTable.PassphraseFP) if scanner.Scan() { oldPassphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // read new passphrase fmt.Fprintf(statusfp, "read new passphrase from fd %d (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read new passphrase from fd %d (not echoed)", ce.fileTable.PassphraseFD) if isTerminal { newPassphrase, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { if scanner.Scan() { newPassphrase = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // read new passphrase again fmt.Fprintf(statusfp, "read new passphrase from fd %d again (not echoed)\n", ce.fileTable.PassphraseFD) log.Infof("read new passphrase from fd %d again (not echoed)", ce.fileTable.PassphraseFD) if isTerminal { newPassphrase2, err = terminal.ReadPassword(int(ce.fileTable.PassphraseFD)) if err != nil { return log.Error(err) } } else { if scanner.Scan() { newPassphrase2 = scanner.Bytes() } else if err := scanner.Err(); err != nil { return log.Error(err) } } log.Info("done") // compare new passphrases if !bytes.Equal(newPassphrase, newPassphrase2) { return log.Error(ErrPassphrasesDiffer) } // rekey msgDB log.Infof("rekey msgDB '%s'", msgdbname) if err := msgdb.Rekey(msgdbname, oldPassphrase, newPassphrase, c.Int("iterations")); err != nil { return err } // rekey keyDB log.Info("rekey keyDB") if err := rekeyKeyDB(c, oldPassphrase, newPassphrase); err != nil { return err } return nil }