예제 #1
0
// SessionAnchor returns the decrypted and verified session anchor for KeyInit.
func (ki *KeyInit) SessionAnchor(sigPubKey string) (*SessionAnchor, error) {
	// SIGKEYHASH corresponds to the SIGKEY of the Identity
	pubKey, err := base64.Decode(sigPubKey)
	if err != nil {
		return nil, err
	}
	keyHash := cipher.SHA512(pubKey)
	if ki.Contents.SIGKEYHASH != base64.Encode(cipher.SHA512(keyHash)) {
		log.Error(ErrWrongSigKeyHash)
		return nil, ErrWrongSigKeyHash
	}
	// verify that SESSIONANCHORHASH matches decrypted SESSIONANCHOR
	enc, err := base64.Decode(ki.Contents.SESSIONANCHOR)
	if err != nil {
		return nil, err
	}
	txt := cipher.AES256CTRDecrypt(keyHash[:32], enc)
	var sa SessionAnchor
	if err := json.Unmarshal(txt, &sa); err != nil {
		return nil, log.Error(err)
	}
	if ki.Contents.SESSIONANCHORHASH != base64.Encode(cipher.SHA512(sa.json())) {
		log.Error(ErrSessionAnchor)
		return nil, ErrSessionAnchor
	}
	return &sa, nil
}
예제 #2
0
// GetOutQueue returns the first entry in the outqueue for myID.
// Entries which need to be resend are ignored.
func (msgDB *MsgDB) GetOutQueue(myID string) (
	oqIdx int64,
	msg, nymaddress string,
	minDelay, maxDelay int32,
	envelope bool,
	err error,
) {
	if err := identity.IsMapped(myID); err != nil {
		return 0, "", "", 0, 0, false, log.Error(err)
	}
	var mID int64
	if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&mID); err != nil {
		return 0, "", "", 0, 0, false, log.Error(err)
	}
	var e int64
	err = msgDB.getOutQueueQuery.QueryRow(mID).Scan(&oqIdx, &msg, &nymaddress,
		&minDelay, &maxDelay, &e)
	switch {
	case err == sql.ErrNoRows:
		return 0, "", "", 0, 0, false, nil
	case err != nil:
		return 0, "", "", 0, 0, false, log.Error(err)
	}
	if e > 0 {
		envelope = true
	}
	return
}
예제 #3
0
// ReadKeyfile reads a randomly generated and encrypted AES-256 key from the
// file with the given filename and returns it in unencrypted form.
// The key is protected by a passphrase, which is processed by PBKDF2 to
// derive the AES-256 key to decrypt the generated key.
func ReadKeyfile(filename string, passphrase []byte) (key []byte, err error) {
	// open keyfile
	keyfile, err := os.Open(filename)
	if err != nil {
		return nil, log.Error(err)
	}
	defer keyfile.Close()
	// read iter and convert to int
	var biter = make([]byte, 8)
	if _, err := keyfile.Read(biter); err != nil {
		return nil, log.Error(err)
	}
	uiter := encode.ToUint64(biter)
	if uiter > 2147483647 {
		return nil, log.Errorf("encdb: ReadKeyfile: invalid iter value")
	}
	iter := int(uiter)
	// read salt
	var salt = make([]byte, 32)
	if _, err := keyfile.Read(salt); err != nil {
		return nil, log.Error(err)
	}
	// read encrypted key
	var encKey = make([]byte, 16+32)
	if _, err := keyfile.Read(encKey); err != nil {
		return nil, log.Error(err)
	}
	// compute derived key from passphrase
	dk := pbkdf2.Key([]byte(passphrase), salt, iter, 32, sha256.New)
	// decrypt key
	return cipher.AES256CBCDecrypt([]byte(dk), encKey), nil
}
예제 #4
0
// GetInQueue returns the first entry in the inqueue.
func (msgDB *MsgDB) GetInQueue() (
	iqIdx int64,
	myID, contactID, msg string,
	envelope bool,
	err error,
) {
	var mID int64
	var cID int64
	var env int64
	err = msgDB.getInQueueQuery.QueryRow().Scan(&iqIdx, &mID, &cID, &msg, &env)
	switch {
	case err == sql.ErrNoRows:
		return 0, "", "", "", false, nil
	case err != nil:
		return 0, "", "", "", false, log.Error(err)
	}
	err = msgDB.getNymMappedQuery.QueryRow(mID).Scan(&myID)
	if err != nil {
		return 0, "", "", "", false, log.Error(err)
	}
	if cID > 0 {
		err = msgDB.getContactMappedQuery.QueryRow(mID, cID).Scan(&contactID)
		if err != nil {
			return 0, "", "", "", false, log.Error(err)
		}
	}
	if env > 0 {
		envelope = true
	}
	return
}
예제 #5
0
// ECDH computes a Diffie-Hellman (DH) key exchange over the elliptic curve (EC)
// curve25519. If ownPublicKey is given it is used to check for the key
// reflection attack. Otherwise it is derived from privateKey.
func ECDH(privateKey, peersPublicKey, ownPublicKey *[32]byte) (*[32]byte, error) {
	var (
		sharedKey [32]byte
		pubKey    []byte
	)
	// check mandatory key length
	if privateKey == nil {
		return nil, log.Error("cipher: curve25519.ECDH(): privateKey == nil")
	}
	if peersPublicKey == nil {
		return nil, log.Error("cipher: curve25519.ECDH(): peersPublicKey == nil")
	}
	// check for key reflection attack
	if ownPublicKey != nil {
		pubKey = ownPublicKey[:]
	} else {
		var publicKey [32]byte
		curve25519.ScalarBaseMult(&publicKey, privateKey)
		pubKey = publicKey[:]
	}
	if bytes.Equal(pubKey, peersPublicKey[:]) {
		return nil, log.Errorf("cipher: curve25519.ECDH(): publicKey == peersPublicKey")
	}
	// perform Diffie-Hellman key exchange
	curve25519.ScalarMult(&sharedKey, privateKey, peersPublicKey)
	return &sharedKey, nil
}
예제 #6
0
// GetAccountTime returns the account time for the given myID and contactID
// combination.
func (msgDB *MsgDB) GetAccountTime(
	myID, contactID string,
) (int64, error) {
	if err := identity.IsMapped(myID); err != nil {
		return 0, log.Error(err)
	}
	if contactID != "" {
		if err := identity.IsMapped(contactID); err != nil {
			return 0, log.Error(err)
		}
	}
	// get MyID
	var mID int
	if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&mID); err != nil {
		return 0, log.Error(err)
	}
	// get ContactID
	var cID int
	if contactID != "" {
		err := msgDB.getContactUIDQuery.QueryRow(mID, contactID).Scan(&cID)
		if err != nil {
			return 0, log.Error(err)
		}
	}
	// get load time
	var loadTime int64
	err := msgDB.getAccountTimeQuery.QueryRow(mID, cID).Scan(&loadTime)
	if err != nil {
		return 0, err
	}
	return loadTime, nil
}
예제 #7
0
// RemoveOutQueue remove the message corresponding to oqIdx from the outqueue
// and sets the send time of the corresponding message to date.
func (msgDB *MsgDB) RemoveOutQueue(oqIdx, date int64) error {
	tx, err := msgDB.encDB.Begin()
	if err != nil {
		return log.Error(err)
	}
	var msgID int64
	// get corresponding msgID
	err = tx.Stmt(msgDB.getOutQueueMsgIDQuery).QueryRow(oqIdx).Scan(&msgID)
	if err != nil {
		tx.Rollback()
		return log.Error(err)
	}
	// set date for message
	_, err = tx.Stmt(msgDB.updateMsgDateQuery).Exec(date, msgID)
	if err != nil {
		tx.Rollback()
		return log.Error(err)
	}
	// remove entry from outqueue
	if _, err := tx.Stmt(msgDB.removeOutQueueQuery).Exec(oqIdx); err != nil {
		tx.Rollback()
		return log.Error(err)
	}
	if err := tx.Commit(); err != nil {
		tx.Rollback()
		return log.Error(err)
	}
	return nil
}
예제 #8
0
파일: encdb.go 프로젝트: frankbraun/mute
// Open tries to open an encrypted database with the given passphrase.
// Thereby, dbname is the prefix of the following two database files (which
// must already exist):
//
//  dbname.db
//  dbname.key
//
// In case of error (for example, the database files do not exist or the
// passphrase is wrong) an error is returned.
func Open(dbname string, passphrase []byte) (*sql.DB, error) {
	dbfile := dbname + DBSuffix
	keyfile := dbname + KeySuffix
	// make sure files exists
	if _, err := os.Stat(dbfile); err != nil {
		return nil, log.Error(err)
	}
	if _, err := os.Stat(keyfile); err != nil {
		return nil, log.Error(err)
	}
	// get key from keyfile
	key, err := ReadKeyfile(keyfile, passphrase)
	if err != nil {
		return nil, err
	}
	// open DB
	dbfile += fmt.Sprintf("?_pragma_key=x'%s'&_pragma_cipher_page_size=4096",
		hex.EncodeToString(key))
	// enable foreign key support
	dbfile += "&_pragma_foreign_keys=on"
	db, err := sql.Open("sqlite3", dbfile)
	if err != nil {
		return nil, log.Error(err)
	}
	// test key
	_, err = db.Exec("SELECT count(*) FROM sqlite_master;")
	if err != nil {
		return nil, log.Error(err)
	}
	return db, nil
}
예제 #9
0
파일: outer.go 프로젝트: JonathanLogan/mute
func readOuterHeader(r io.Reader) (*outerHeader, error) {
	var oh outerHeader
	// read Type
	if err := binary.Read(r, binary.BigEndian, &oh.Type); err != nil {
		return nil, log.Error(err)
	}
	// check Type
	if oh.Type != preHeaderPacket &&
		oh.Type != encryptedHeader &&
		oh.Type != cryptoSetup &&
		oh.Type != hmacPacket &&
		oh.Type != encryptedPacket {
		return nil, log.Errorf("msg: invalid outer header type %d", oh.Type)
	}
	// read Plen
	if err := binary.Read(r, binary.BigEndian, &oh.PLen); err != nil {
		return nil, log.Error(err)
	}
	// read PacketCount
	if err := binary.Read(r, binary.BigEndian, &oh.PacketCount); err != nil {
		return nil, log.Error(err)
	}
	// read inner packet
	oh.inner = make([]byte, oh.PLen)
	if _, err := io.ReadFull(r, oh.inner); err != nil {
		return nil, log.Error(err)
	}
	return &oh, nil
}
예제 #10
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
}
예제 #11
0
파일: uid.go 프로젝트: JonathanLogan/mute
// VerifyUserSig verifies that the user-signature of UIDMessage is valid.
func (msg *Message) VerifyUserSig(preMsg *Message) error {
	var ed25519Key cipher.Ed25519Key
	// check message counter
	if preMsg.UIDContent.MSGCOUNT+1 != msg.UIDContent.MSGCOUNT {
		return log.Error(ErrIncrement)
	}
	// get content
	content := msg.UIDContent.JSON()
	// get self-signature
	selfsig, err := base64.Decode(msg.USERSIGNATURE)
	if err != nil {
		return err
	}
	// create ed25519 key
	pubKey, err := base64.Decode(preMsg.UIDContent.SIGKEY.PUBKEY)
	if err != nil {
		return err
	}
	if err := ed25519Key.SetPublicKey(pubKey); err != nil {
		return err
	}
	// verify self-signature
	if !ed25519Key.Verify(content, selfsig) {
		return log.Error(ErrInvalidUserSig)
	}
	return nil
}
예제 #12
0
파일: uid.go 프로젝트: JonathanLogan/mute
// deleteUID deletes a nym.
func (ce *CryptEngine) deleteUID(pseudonym string, force bool) error {
	// map pseudonym
	id, err := identity.Map(pseudonym)
	if err != nil {
		return err
	}

	// get UID from keyDB
	msg, _, err := ce.keyDB.GetPrivateUID(id, false)
	if err != nil {
		return err
	}

	// ask for manual confirmation
	if !force {
		fmt.Fprintf(os.Stderr, "cryptengine: delete user ID %s and all it's key material? ",
			pseudonym)
		var response string
		_, err := fmt.Scanln(&response)
		if err != nil {
			return log.Error(err)
		}
		if !strings.HasPrefix(strings.ToLower(response), "y") {
			return log.Error("cryptengine: user ID deletion aborted")
		}
	}

	// delete UID from keyDB
	if err := ce.keyDB.DelPrivateUID(msg); err != nil {
		return err
	}
	return nil
}
예제 #13
0
파일: encdb.go 프로젝트: frankbraun/mute
// Create tries to create an encrypted database with the given passphrase and
// iter many KDF iterations. Thereby, dbname is the prefix of the following
// two database files which will be created and must not exist already:
//
//  dbname.db
//  dbname.key
//
// The SQL database is initialized with the statements given in createStmts.
// In case of error (for example, the database files do exist already or
// cannot be created) an error is returned.
func Create(dbname string, passphrase []byte, iter int, createStmts []string) error {
	dbfile := dbname + DBSuffix
	keyfile := dbname + KeySuffix
	// make sure files do not exist already
	if _, err := os.Stat(dbfile); err == nil {
		return log.Errorf("encdb: dbfile '%s' exists already", dbfile)
	}
	if _, err := os.Stat(keyfile); err == nil {
		return log.Errorf("encdb: dbfile '%s' exists already", keyfile)
	}
	// create keyfile
	key, err := generateKeyfile(keyfile, passphrase, iter)
	if err != nil {
		return err
	}
	// create DB
	dbfile += fmt.Sprintf("?_pragma_key=x'%s'&_pragma_cipher_page_size=4096",
		hex.EncodeToString(key))
	db, err := sql.Open("sqlite3", dbfile)
	if err != nil {
		return log.Error(err)
	}
	defer db.Close()
	_, err = db.Exec("PRAGMA auto_vacuum = full;")
	if err != nil {
		return log.Error(err)
	}
	return createTables(db, createStmts)
}
예제 #14
0
파일: inner.go 프로젝트: JonathanLogan/mute
func readInnerHeader(r io.Reader) (*innerHeader, error) {
	var ih innerHeader
	// read Type
	if err := binary.Read(r, binary.BigEndian, &ih.Type); err != nil {
		return nil, err
	}
	// check Type
	if ih.Type != paddingType &&
		ih.Type != dataType &&
		ih.Type != dataType|signType &&
		ih.Type != signatureType {
		return nil, log.Errorf("msg: invalid inner header type %d", ih.Type)
	}
	// read Plen
	if err := binary.Read(r, binary.BigEndian, &ih.PLen); err != nil {
		return nil, log.Error(err)
	}
	// read More
	if err := binary.Read(r, binary.BigEndian, &ih.More); err != nil {
		return nil, log.Error(err)
	}
	// read Skip
	if err := binary.Read(r, binary.BigEndian, &ih.Skip); err != nil {
		return nil, log.Error(err)
	}
	// read content
	ih.content = make([]byte, ih.PLen)
	if _, err := io.ReadFull(r, ih.content); err != nil {
		return nil, log.Error(err)
	}
	return &ih, nil
}
예제 #15
0
// SetAccountLastMsg sets the last message time and ID for the given myID and
// contactID combination (contactID can be nil).
func (msgDB *MsgDB) SetAccountLastMsg(
	myID, contactID string,
	lastMessageTime int64,
) error {
	if err := identity.IsMapped(myID); err != nil {
		return log.Error(err)
	}
	if contactID != "" {
		if err := identity.IsMapped(contactID); err != nil {
			return log.Error(err)
		}
	}
	// get MyID
	var mID int
	if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&mID); err != nil {
		return log.Error(err)
	}
	// get ContactID
	var cID int
	if contactID != "" {
		err := msgDB.getContactUIDQuery.QueryRow(mID, contactID).Scan(&cID)
		if err != nil {
			return log.Error(err)
		}
	}
	// set account time
	_, err := msgDB.setAccountLastTimeQuery.Exec(lastMessageTime, mID, cID)
	if err != nil {
		return log.Error(err)
	}
	return nil
}
예제 #16
0
파일: nyms.go 프로젝트: JonathanLogan/mute
// GetNyms returns all unmapped or mapped nyms in msgDB.
func (msgDB *MsgDB) GetNyms(mapped bool) ([]string, error) {
	// get contacts
	rows, err := msgDB.getNymsQuery.Query()
	if err != nil {
		return nil, log.Error(err)
	}
	var nyms []string
	defer rows.Close()
	for rows.Next() {
		var mappedID, unmappedID, fullName string
		if err := rows.Scan(&mappedID, &unmappedID, &fullName); err != nil {
			return nil, log.Error(err)
		}
		if mapped {
			nyms = append(nyms, mappedID)
		} else {
			if fullName == "" {
				nyms = append(nyms, unmappedID)
			} else {
				nyms = append(nyms, fullName+" <"+unmappedID+">")
			}
		}
	}
	if err := rows.Err(); err != nil {
		return nil, log.Error(err)
	}
	return nyms, nil
}
예제 #17
0
// GetUndeliveredMessage returns the oldest undelivered message for myID from
// msgDB.
func (msgDB *MsgDB) GetUndeliveredMessage(myID string) (
	msgNum int64,
	contactID string,
	msg []byte,
	sign bool,
	minDelay, maxDelay int32,
	err error,
) {
	if err := identity.IsMapped(myID); err != nil {
		return 0, "", nil, false, 0, 0, log.Error(err)
	}
	var mID int64
	if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&mID); err != nil {
		return 0, "", nil, false, 0, 0, log.Error(err)
	}
	var cID int64
	var s int64
	err = msgDB.getUndeliveredMsgQuery.QueryRow(mID).Scan(&msgNum, &cID, &msg,
		&s, &minDelay, &maxDelay)
	switch {
	case err == sql.ErrNoRows:
		return 0, "", nil, false, 0, 0, nil
	case err != nil:
		return 0, "", nil, false, 0, 0, log.Error(err)
	}
	if s > 0 {
		sign = true
	}
	err = msgDB.getContactMappedQuery.QueryRow(mID, cID).Scan(&contactID)
	if err != nil {
		return 0, "", nil, false, 0, 0, log.Error(err)
	}
	return
}
예제 #18
0
// GetMsgIDs returns all message IDs (sqlite row IDs) for the user ID myID.
func (msgDB *MsgDB) GetMsgIDs(myID string) ([]*MsgID, error) {
	if err := identity.IsMapped(myID); err != nil {
		return nil, log.Error(err)
	}
	var uid int
	if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&uid); err != nil {
		return nil, log.Error(err)
	}
	rows, err := msgDB.getMsgsQuery.Query(uid)
	if err != nil {
		return nil, log.Error(err)
	}
	var msgIDs []*MsgID
	defer rows.Close()
	for rows.Next() {
		var (
			id      int64
			from    string
			to      string
			d       int64
			s       int64
			date    int64
			subject string
			r       int64
		)
		err = rows.Scan(&id, &from, &to, &d, &s, &date, &subject, &r)
		if err != nil {
			return nil, log.Error(err)
		}
		var (
			incoming bool
			sent     bool
			read     bool
		)
		if d == 0 {
			incoming = true
		}
		if s > 0 {
			sent = true
		}
		if r > 0 {
			read = true
		}
		msgIDs = append(msgIDs, &MsgID{
			MsgID:    id,
			From:     from,
			To:       to,
			Incoming: incoming,
			Sent:     sent,
			Date:     date,
			Subject:  subject,
			Read:     read,
		})
	}
	if err := rows.Err(); err != nil {
		return nil, log.Error(err)
	}
	return msgIDs, nil
}
예제 #19
0
파일: nyms.go 프로젝트: JonathanLogan/mute
// SetUpkeepAccounts sets the last execution time of 'upkeep accounts' to t.
func (msgDB *MsgDB) SetUpkeepAccounts(myID string, t int64) error {
	if err := identity.IsMapped(myID); err != nil {
		return log.Error(err)
	}
	if _, err := msgDB.setUpkeepAccountsQuery.Exec(t, myID); err != nil {
		return log.Error(err)
	}
	return nil
}
예제 #20
0
// DelPrivSessionKey deletes the private key corresponding to the session key
// with given hash from keyDB.
func (keyDB *KeyDB) DelPrivSessionKey(hash string) error {
	if hash == "" {
		return log.Error("keydb: hash must be defined")
	}
	_, err := keyDB.updateSessionKeyQuery.Exec("", hash)
	if err != nil {
		return log.Error(err)
	}
	return nil
}
예제 #21
0
파일: nyms.go 프로젝트: JonathanLogan/mute
// GetUpkeepAccounts retrieves the last execution time of 'upkeep accounts'.
func (msgDB *MsgDB) GetUpkeepAccounts(myID string) (int64, error) {
	if err := identity.IsMapped(myID); err != nil {
		return 0, log.Error(err)
	}
	var t int64
	if err := msgDB.getUpkeepAccountsQuery.QueryRow(myID).Scan(&t); err != nil {
		return 0, log.Error(err)
	}
	return t, nil
}
예제 #22
0
// KeyInit returns a new KeyInit message for the given UID message. It also
// returns the pubKeyHash and privateKey for convenient further use.
// msgcount must increase for each message of the same type and user.
// notafter is the unixtime after which the key(s) should not be used anymore.
// notbefore is the unixtime before which the key(s) should not be used yet.
// fallback determines if the key may serve as a fallback key.
// repoURI is URI of the corresponding KeyInit repository.
// Necessary randomness is read from rand.
func (msg *Message) KeyInit(
	msgcount, notafter, notbefore uint64,
	fallback bool,
	repoURI, mixaddress, nymaddress string,
	rand io.Reader,
) (ki *KeyInit, pubKeyHash, privateKey string, err error) {
	var keyInit KeyInit
	// time checks
	if notbefore >= notafter {
		log.Error(ErrInvalidTimes)
		return nil, "", "", ErrInvalidTimes
	}
	if notafter < uint64(times.Now()) {
		log.Error(ErrExpired)
		return nil, "", "", ErrExpired
	}
	if notafter > uint64(times.Now())+MaxNotAfter {
		log.Error(ErrFuture)
		return nil, "", "", ErrFuture
	}
	// init
	keyInit.Contents.VERSION = ProtocolVersion
	keyInit.Contents.MSGCOUNT = msgcount
	keyInit.Contents.NOTAFTER = notafter
	keyInit.Contents.NOTBEFORE = notbefore
	keyInit.Contents.FALLBACK = fallback
	keyHash, err := base64.Decode(msg.UIDContent.SIGKEY.HASH)
	if err != nil {
		return nil, "", "", err
	}
	keyInit.Contents.SIGKEYHASH = base64.Encode(cipher.SHA512(keyHash))

	// make sure REPOURIS is set to the first REPOURI of UIDContent.REPOURIS
	// TODO: support different KeyInit repository configurations
	if repoURI != msg.UIDContent.REPOURIS[0] {
		return nil, "", "",
			log.Error("uri: repoURI differs from msg.UIDContent.REPOURIS[0]")
	}
	keyInit.Contents.REPOURI = repoURI

	// create SessionAnchor
	sa, sah, pubKeyHash, privateKey, err := msg.sessionAnchor(keyHash,
		mixaddress, nymaddress, rand)
	if err != nil {
		return nil, "", "", err
	}
	keyInit.Contents.SESSIONANCHOR = sa
	keyInit.Contents.SESSIONANCHORHASH = sah
	// sign KeyInit: the content doesn't have to be hashed, because Ed25519 is
	// already taking care of that.
	sig := msg.UIDContent.SIGKEY.ed25519Key.Sign(keyInit.Contents.json())
	keyInit.SIGNATURE = base64.Encode(sig)
	ki = &keyInit
	return
}
예제 #23
0
// Verify verifies that the KeyInit is valid and contains a valid ECDHE25519
// key.
func (ki *KeyInit) Verify(keyInitRepositoryURIs []string, sigPubKey string) error {
	// The REPOURI points to this KeyInit Repository
	if !util.ContainsString(keyInitRepositoryURIs, ki.Contents.REPOURI) {
		log.Error(ErrRepoURI)
		return ErrRepoURI
	}

	// verify that SESSIONANCHORHASH matches decrypted SESSIONANCHOR
	sa, err := ki.SessionAnchor(sigPubKey)
	if err != nil {
		return err
	}

	// get KeyEntry message from SessionAnchor
	ke, err := sa.KeyEntry("ECDHE25519")
	if err != nil {
		return err
	}

	// verify KeyEntry message
	if err := ke.Verify(); err != nil {
		return err
	}

	// NOTAFTER and NOTBEFORE are valid
	if ki.Contents.NOTBEFORE >= ki.Contents.NOTAFTER {
		log.Error(ErrInvalidTimes)
		return ErrInvalidTimes
	}
	// not expired
	if ki.Contents.NOTAFTER < uint64(times.Now()) {
		log.Error(ErrExpired)
		return ErrExpired
	}

	// SIGNATURE was made with UIDMessage.UIDContent.SIGKEY over Contents
	var ed25519Key cipher.Ed25519Key
	sig, err := base64.Decode(ki.SIGNATURE)
	if err != nil {
		return err
	}
	pubKey, err := base64.Decode(sigPubKey)
	if err != nil {
		return err
	}
	// create ed25519 key
	ed25519Key.SetPublicKey(pubKey)
	// verify self-signature
	if !ed25519Key.Verify(ki.Contents.json(), sig) {
		log.Error(ErrInvalidKeyInitSig)
		return ErrInvalidKeyInitSig
	}

	return nil
}
예제 #24
0
func writeConfigFile(homedir, domain string, config []byte) error {
	configdir := filepath.Join(homedir, "config")
	if err := os.MkdirAll(configdir, 0700); err != nil {
		return log.Error(err)
	}
	tmpfile := filepath.Join(configdir, domain+".new")
	os.Remove(tmpfile) // ignore error
	if err := ioutil.WriteFile(tmpfile, config, 0600); err != nil {
		return log.Error(err)
	}
	return os.Rename(tmpfile, filepath.Join(configdir, domain))
}
예제 #25
0
// AddMessage adds message between selfID and peerID to msgDB. If sent is
// true, it is a sent message. Otherwise a received message.
func (msgDB *MsgDB) AddMessage(
	selfID, peerID string,
	date int64,
	sent bool,
	message string,
	sign bool,
	minDelay, maxDelay int32,
) error {
	if err := identity.IsMapped(selfID); err != nil {
		return log.Error(err)
	}
	if err := identity.IsMapped(peerID); err != nil {
		return log.Error(err)
	}
	// get self
	var self int64
	if err := msgDB.getNymUIDQuery.QueryRow(selfID).Scan(&self); err != nil {
		return log.Error(err)
	}
	// get peer
	var peer int64
	err := msgDB.getContactUIDQuery.QueryRow(self, peerID).Scan(&peer)
	if err != nil {
		return log.Error(err)
	}
	// add message
	var d int64
	if sent {
		d = 1
	}
	var s int64
	if sign {
		s = 1
	}
	var from string
	var to string
	if sent {
		from = selfID
		to = peerID
	} else {
		from = peerID
		to = selfID
	}
	parts := strings.SplitN(message, "\n", 2)
	subject := parts[0]
	_, err = msgDB.addMsgQuery.Exec(self, peer, d, d, 0, from, to, date,
		subject, message, s, minDelay, maxDelay)
	if err != nil {
		return log.Error(err)
	}
	return nil
}
예제 #26
0
// ClearResendOutQueue clears the resend status in the outqueue for myID.
func (msgDB *MsgDB) ClearResendOutQueue(myID string) error {
	if err := identity.IsMapped(myID); err != nil {
		return log.Error(err)
	}
	var mID int64
	if err := msgDB.getNymUIDQuery.QueryRow(myID).Scan(&mID); err != nil {
		return log.Error(err)
	}
	if _, err := msgDB.clearResendOutQueueQuery.Exec(mID); err != nil {
		return log.Error(err)
	}
	return nil
}
예제 #27
0
파일: mime.go 프로젝트: JonathanLogan/mute
func multipartMIME(
	writer *multipart.Writer,
	msg string,
	attachments []*Attachment,
) error {
	// write message
	mh := make(textproto.MIMEHeader)
	mh.Add("Content-Type", "text/plain")
	mh.Add("Content-Transfer-Encoding", "base64")
	msgWriter, err := writer.CreatePart(mh)
	if err != nil {
		return log.Error(err)
	}
	_, err = io.WriteString(msgWriter, base64.Encode([]byte(msg)))
	if err != nil {
		return log.Error(err)
	}

	// write attachments
	for _, attachment := range attachments {
		mh = make(textproto.MIMEHeader)
		base := filepath.Base(attachment.Filename)
		if attachment.ContentType != "" {
			mh.Add("Content-Type", attachment.ContentType)
		} else {
			ct := mime.TypeByExtension(filepath.Ext(base))
			if ct != "" {
				mh.Add("Content-Type", ct)
			} else {
				mh.Add("Content-Type", "application/octet-stream")
			}
		}
		mh.Add("Content-Transfer-Encoding", "base64")
		mh.Add("Content-Disposition", "attachment; filename="+base)
		if attachment.Inline {
			mh.Add("Content-Disposition", "inline")
		}
		attachmentWriter, err := writer.CreatePart(mh)
		if err != nil {
			return log.Error(err)
		}
		encoder := base64.NewEncoder(attachmentWriter)
		if _, err := io.Copy(encoder, attachment.Reader); err != nil {
			return log.Error(err)
		}
		if err := encoder.Close(); err != nil {
			return log.Error(err)
		}
	}
	return nil
}
예제 #28
0
func (hp *headerPacket) write(w io.Writer) error {
	//log.Debugf("hp.Nonce: %s", base64.Encode(hp.Nonce[:]))
	if _, err := w.Write(hp.Nonce[:]); err != nil {
		return log.Error(err)
	}
	//log.Debugf("hp.LengthEncryptedHeader: %d", hp.LengthEncryptedHeader)
	if err := binary.Write(w, binary.BigEndian, hp.LengthEncryptedHeader); err != nil {
		return log.Error(err)
	}
	if _, err := w.Write(hp.EncryptedHeader); err != nil {
		return log.Error(err)
	}
	return nil
}
예제 #29
0
func readHeader(
	senderHeaderPub *[32]byte,
	identities []*uid.Message,
	r io.Reader,
) (*uid.Message, *header, error) {
	var hp headerPacket
	// read nonce
	if _, err := io.ReadFull(r, hp.Nonce[:]); err != nil {
		return nil, nil, log.Error(err)
	}
	//log.Debugf("hp.Nonce: %s", base64.Encode(hp.Nonce[:]))
	// read length of encrypted header
	if err := binary.Read(r, binary.BigEndian, &hp.LengthEncryptedHeader); err != nil {
		return nil, nil, log.Error(err)
	}
	//log.Debugf("hp.LengthEncryptedHeader: %d", hp.LengthEncryptedHeader)
	// read encrypted header
	hp.EncryptedHeader = make([]byte, hp.LengthEncryptedHeader)
	if _, err := io.ReadFull(r, hp.EncryptedHeader); err != nil {
		return nil, nil, log.Error(err)
	}
	// try to decrypt header
	var jsn []byte
	var suc bool
	var identity *uid.Message
	for _, uidMsg := range identities {
		log.Debugf("try identity %s (#%d)", uidMsg.Identity(),
			uidMsg.UIDContent.MSGCOUNT)
		log.Debugf("recvPub=%s\n",
			base64.Encode(uidMsg.PubKey().PublicKey32()[:]))
		jsn, suc = box.Open(jsn, hp.EncryptedHeader, &hp.Nonce,
			senderHeaderPub, uidMsg.PubKey().PrivateKey32())
		if suc {
			identity = uidMsg
			break
		}
	}
	if !suc {
		return nil, nil, log.Error(ErrNoPreHeaderKey)
	}
	var h header
	if err := json.Unmarshal(jsn, &h); err != nil {
		return nil, nil, err
	}
	// verify header
	if err := h.verify(); err != nil {
		return nil, nil, err
	}
	return identity, &h, nil
}
예제 #30
0
파일: uid.go 프로젝트: JonathanLogan/mute
// Decrypt decrypts the message reply and returns the resulting UIDIndex and
// UIDMesssage.
func (reply *MessageReply) Decrypt(UIDHash []byte) ([]byte, *Message, error) {
	UIDMessageEncrypted, err := base64.Decode(reply.ENTRY.UIDMESSAGEENCRYPTED)
	if err != nil {
		return nil, nil, log.Error(err)
	}
	UIDIndex := UIDMessageEncrypted[:sha256.Size]
	enc := UIDMessageEncrypted[sha256.Size:]
	Message := cipher.AES256CTRDecrypt(UIDHash, enc)
	uid, err := NewJSON(string(Message))
	if err != nil {
		return nil, nil, log.Error(err)
	}
	return UIDIndex, uid, nil
}