예제 #1
0
파일: db.go 프로젝트: JonathanLogan/mute
// 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
}
예제 #2
0
// 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)
}
예제 #3
0
파일: db.go 프로젝트: JonathanLogan/mute
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
}
예제 #4
0
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
}
예제 #5
0
파일: db.go 프로젝트: JonathanLogan/mute
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
}
예제 #6
0
파일: keys.go 프로젝트: JonathanLogan/mute
// 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
}
예제 #7
0
파일: uid.go 프로젝트: JonathanLogan/mute
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
}
예제 #8
0
파일: db.go 프로젝트: JonathanLogan/mute
// 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
}
예제 #9
0
파일: db.go 프로젝트: JonathanLogan/mute
// 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
}