コード例 #1
0
ファイル: keyinit.go プロジェクト: JonathanLogan/mute
// 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
ファイル: encrypt.go プロジェクト: JonathanLogan/mute
func rootKeyAgreementSender(
	senderHeaderPub *[32]byte,
	senderIdentity, recipientIdentity string,
	senderSession, senderID, recipientKI, recipientID *uid.KeyEntry,
	previousRootKeyHash *[64]byte,
	numOfKeys uint64,
	keyStore session.Store,
) error {
	senderIdentityPub := senderID.PublicKey32()
	senderIdentityPriv := senderID.PrivateKey32()
	senderSessionPub := senderSession.PublicKey32()
	senderSessionPriv := senderSession.PrivateKey32()
	recipientIdentityPub := recipientID.PublicKey32()
	recipientKeyInitPub := recipientKI.PublicKey32()

	log.Debugf("senderIdentityPub:    %s", base64.Encode(senderIdentityPub[:]))
	log.Debugf("senderSessionPub:     %s", base64.Encode(senderSessionPub[:]))
	log.Debugf("recipientIdentityPub: %s", base64.Encode(recipientIdentityPub[:]))
	log.Debugf("recipientKeyInitPub:  %s", base64.Encode(recipientKeyInitPub[:]))

	// check keys to prevent reflection attacks and replays
	err := checkKeys(senderHeaderPub, senderIdentityPub, senderSessionPub,
		recipientIdentityPub, recipientKeyInitPub)
	if err != nil {
		return err
	}

	// compute t1
	t1, err := cipher.ECDH(senderIdentityPriv, recipientKeyInitPub, senderIdentityPub)
	if err != nil {
		return err
	}

	// compute t2
	t2, err := cipher.ECDH(senderSessionPriv, recipientKeyInitPub, senderSessionPub)
	if err != nil {
		return err
	}

	// compute t3
	t3, err := cipher.ECDH(senderSessionPriv, recipientIdentityPub, senderSessionPub)
	if err != nil {
		return err
	}

	// derive root key
	rootKey, err := deriveRootKey(t1, t2, t3, previousRootKeyHash)
	if err != nil {
		return err
	}

	// generate message keys
	err = generateMessageKeys(senderIdentity, recipientIdentity,
		senderID.HASH, recipientID.HASH, rootKey, false, senderSessionPub,
		recipientKeyInitPub, numOfKeys, keyStore)
	if err != nil {
		return err
	}
	return nil
}
コード例 #3
0
ファイル: keyinit.go プロジェクト: JonathanLogan/mute
// 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
}
コード例 #4
0
ファイル: session_test.go プロジェクト: JonathanLogan/mute
func deriveKeys(chainKey []byte, kdf io.Reader) (send, recv []string, err error) {
	buffer := make([]byte, 64)
	for i := 0; i < msg.NumOfFutureKeys; i++ {
		if _, err := io.ReadFull(kdf, buffer); err != nil {
			return nil, nil, err
		}
		send = append(send, base64.Encode(cipher.HMAC(chainKey, buffer)))
		if _, err := io.ReadFull(kdf, buffer); err != nil {
			return nil, nil, err
		}
		recv = append(recv, base64.Encode(cipher.HMAC(chainKey, buffer)))
	}
	return
}
コード例 #5
0
ファイル: uid.go プロジェクト: JonathanLogan/mute
// SigKeyHash returns the SIGKEYHASH which corresponds to the sigPubKey.
func SigKeyHash(sigPubKey string) (string, error) {
	keyHash, err := base64.Decode(sigPubKey)
	if err != nil {
		return "", err
	}
	return base64.Encode(cipher.SHA512(keyHash)), nil
}
コード例 #6
0
ファイル: uid_test.go プロジェクト: JonathanLogan/mute
func TestSigKeyHash(t *testing.T) {
	msg, err := Create("*****@*****.**", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if msg.Identity() != "*****@*****.**" {
		t.Error("wrong identity")
	}
	sigKeyHash, err := msg.SigKeyHash()
	if err != nil {
		t.Fatal(err)
	}
	sigPubKey, err := base64.Decode(msg.SigPubKey())
	if err != nil {
		t.Fatal(err)
	}
	if sigKeyHash != base64.Encode(cipher.SHA512(cipher.SHA512(sigPubKey))) {
		t.Fatal("SIGKEYHASHs differ")
	}

	privKey := msg.PrivateEncKey()
	if err := msg.SetPrivateEncKey(privKey); err != nil {
		t.Fatal(err)
	}
	if privKey != msg.PrivateEncKey() {
		t.Error("private keys differ")
	}
}
コード例 #7
0
ファイル: randpass.go プロジェクト: JonathanLogan/mute
// RandPass returns a random 256-bit password in base64 encoding.
func RandPass(rand io.Reader) string {
	var pass = make([]byte, 32)
	if _, err := io.ReadFull(rand, pass); err != nil {
		panic(log.Critical(err))
	}
	return base64.Encode(pass)
}
コード例 #8
0
ファイル: wallet.go プロジェクト: JonathanLogan/mute
func printWalletKey(w io.Writer, privkey string) error {
	pk, err := base64.Decode(privkey)
	if err != nil {
		return err
	}
	fmt.Fprintf(w, "WALLETPUBKEY:\t%s\n", base64.Encode(pk[32:]))
	return nil
}
コード例 #9
0
ファイル: keyentry_test.go プロジェクト: JonathanLogan/mute
func TestKeyEntry(t *testing.T) {
	// create UID message
	msg, err := Create("*****@*****.**", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}

	// KeyInit
	now := uint64(times.Now())
	ki, _, privateKey, err := msg.KeyInit(1, now+times.Day, now-times.Day,
		false, "mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}

	// KeyEntry
	ke, err := ki.KeyEntryECDHE25519(msg.SigPubKey())
	if err != nil {
		t.Fatal(err)
	}

	// verify consistency
	if err := ke.Verify(); err != nil {
		t.Fatal(err)
	}

	// equal
	if !KeyEntryEqual(ke, ke) {
		t.Error("ke should be equal to itself")
	}
	a := ke
	var b KeyEntry
	b.CIPHERSUITE = a.CIPHERSUITE
	b.FUNCTION = a.FUNCTION
	b.HASH = a.HASH
	b.PUBKEY = a.PUBKEY
	if !KeyEntryEqual(a, &b) {
		t.Error("a and b should be equal to itself")
	}

	// private key check
	if err := ke.SetPrivateKey(privateKey); err != nil {
		t.Fatal(err)
	}
	privKey := ke.PrivateKey32()
	if privateKey != base64.Encode(privKey[:]) {
		t.Error("private keys differ")
	}

	// public key check
	var publicKey [32]byte
	curve25519.ScalarBaseMult(&publicKey, privKey)
	pubKey := ke.PublicKey32()
	if !bytes.Equal(publicKey[:], pubKey[:]) {
		t.Error("public keys differ")
	}
}
コード例 #10
0
ファイル: keyinit.go プロジェクト: JonathanLogan/mute
func (msg *Message) sessionAnchor(
	key []byte,
	mixaddress, nymaddress string,
	rand io.Reader,
) (sessionAnchor, sessionAnchorHash, pubKeyHash, privateKey string, err error) {
	var sa SessionAnchor
	sa.MIXADDRESS = mixaddress
	sa.NYMADDRESS = nymaddress
	sa.PFKEYS = make([]KeyEntry, 1)
	if err := sa.PFKEYS[0].InitDHKey(rand); err != nil {
		return "", "", "", "", err
	}
	jsn := sa.json()
	hash := cipher.SHA512(jsn)
	// SESSIONANCHOR = AES256_CTR(key=UIDMessage.UIDContent.SIGKEY.HASH, SessionAnchor)
	enc := base64.Encode(cipher.AES256CTREncrypt(key[:32], jsn, rand))
	return enc, base64.Encode(hash), sa.PFKEYS[0].HASH, base64.Encode(sa.PFKEYS[0].PrivateKey32()[:]), nil
}
コード例 #11
0
ファイル: padding_test.go プロジェクト: JonathanLogan/mute
func TestGenerateShort(t *testing.T) {
	t.Parallel()
	padding, err := Generate(32, cipher.RandZero)
	if err != nil {
		t.Fatal(err)
	}
	if base64.Encode(padding) != "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" {
		t.Error("wrong padding")
	}
}
コード例 #12
0
ファイル: padding_test.go プロジェクト: JonathanLogan/mute
func TestGenerateLong(t *testing.T) {
	t.Parallel()
	padding, err := Generate(33, cipher.RandZero)
	if err != nil {
		t.Fatal(err)
	}
	if base64.Encode(padding) != "3JXAeKJAiYmtSKIUkoQgh1MPivvHRTa5qWO08cTLc4vO" {
		t.Error("wrong padding")
	}
}
コード例 #13
0
ファイル: session.go プロジェクト: JonathanLogan/mute
// CalcKey computes the session key from senderIdentityHash,
// recipientIdentityHash, senderSessionHash, and recipientSessionHash.
func CalcKey(
	senderIdentityHash string,
	recipientIdentityHash string,
	senderSessionHash string,
	recipientSessionHash string,
) string {
	key := senderIdentityHash + recipientIdentityHash
	key += senderSessionHash + recipientSessionHash
	return base64.Encode(cipher.SHA512([]byte(key)))
}
コード例 #14
0
ファイル: hashchain.go プロジェクト: JonathanLogan/mute
func (ce *CryptEngine) fetchUID(
	domain string,
	UIDIndex []byte,
) (*uid.MessageReply, error) {
	// get JSON-RPC client
	client, _, err := ce.cache.Get(domain, ce.keydPort, ce.keydHost, ce.homedir,
		"KeyRepository.FetchUID")
	if err != nil {
		return nil, err
	}
	// Call KeyRepository.FetchUID
	content := make(map[string]interface{})
	content["UIDIndex"] = base64.Encode(UIDIndex)
	reply, err := client.JSONRPCRequest("KeyRepository.FetchUID", content)
	if err != nil {
		return nil, err
	}

	// Parse entry
	var entry uid.Entry
	rep, ok := reply["UIDMessageReply"].(map[string]interface{})
	if !ok {
		return nil, log.Error("cryptengine: KeyRepository.FetchUID reply has the wrong return type")
	}
	e, ok := rep["ENTRY"].(map[string]interface{})
	if !ok {
		return nil, log.Error("cryptengine: KeyRepository.FetchUID ENTRY has the wrong type")
	}
	entry.UIDMESSAGEENCRYPTED, ok = e["UIDMESSAGEENCRYPTED"].(string)
	if !ok {
		return nil, log.Error("cryptengine: KeyRepository.FetchUID UIDMESSAGEENCRYPTED has the wrong type")
	}
	log.Debugf("cryptengine: UIDMessageEncrypted=%s", entry.UIDMESSAGEENCRYPTED)
	entry.HASHCHAINENTRY, ok = e["HASHCHAINENTRY"].(string)
	if !ok {
		return nil, log.Error("cryptengine: KeyRepository.FetchUID HASHCHAINENTRY has the wrong type")
	}
	hcPos, ok := e["HASHCHAINPOS"].(float64)
	if !ok {
		return nil, log.Error("cryptengine: KeyRepository.FetchUID HASHCHAINPOS has the wrong type")
	}
	entry.HASHCHAINPOS = uint64(hcPos)

	// Parse server signature
	srvSig, ok := rep["SERVERSIGNATURE"].(string)
	if !ok {
		return nil, log.Error("cryptengine: KeyRepository.FetchUID SERVERSIGNATURE has the wrong type")
	}

	msgReply := &uid.MessageReply{
		ENTRY:           entry,
		SERVERSIGNATURE: srvSig,
	}
	return msgReply, err
}
コード例 #15
0
ファイル: uid.go プロジェクト: JonathanLogan/mute
// Update generates an updated version of the given UID message, signs it with
// the private signature key, and returns it.
func (msg *Message) Update(rand io.Reader) (*Message, error) {
	var up Message
	// copy
	up = *msg
	// increase counter
	up.UIDContent.MSGCOUNT++
	// update signature key
	if err := up.UIDContent.SIGKEY.initSigKey(rand); err != nil {
		return nil, err
	}
	err := up.UIDContent.PUBKEYS[0].setPrivateKey(msg.UIDContent.PUBKEYS[0].PrivateKey32()[:])
	if err != nil {
		return nil, err
	}
	// self-signature
	selfsig := up.UIDContent.SIGKEY.ed25519Key.Sign(up.UIDContent.JSON())
	up.SELFSIGNATURE = base64.Encode(selfsig)
	// sign with previous key
	prevsig := msg.UIDContent.SIGKEY.ed25519Key.Sign(up.UIDContent.JSON())
	up.USERSIGNATURE = base64.Encode(prevsig)
	return &up, nil
}
コード例 #16
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
}
コード例 #17
0
ファイル: header.go プロジェクト: JonathanLogan/mute
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
}
コード例 #18
0
ファイル: uid_test.go プロジェクト: JonathanLogan/mute
func TestUIDMessage(t *testing.T) {
	uid, err := Create("*****@*****.**", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if err := uid.Check(); err != nil {
		t.Error(err)
	}
	if uid.Localpart() != "test" {
		t.Errorf("wrong localpart")
	}
	if uid.Domain() != "mute.berlin" {
		t.Errorf("wrong domain")
	}
	if err := uid.VerifySelfSig(); err != nil {
		t.Error(err)
	}
	privkey := uid.PrivateSigKey()
	if err := uid.SetPrivateSigKey(privkey); err != nil {
		t.Fatal(err)
	}
	if privkey != uid.PrivateSigKey() {
		t.Error("private keys differ")
	}
	if privkey != base64.Encode(uid.PrivateSigKey64()[:]) {
		t.Error("private keys differ")
	}
	jsn := uid.JSON()
	jsnUID, err := NewJSON(string(jsn))
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(jsn, jsnUID.JSON()) {
		t.Errorf("UIDs differ")
	}
	if err := jsnUID.SetPrivateSigKey(privkey); err != nil {
		t.Fatal(err)
	}
	if err := jsnUID.SetPrivateSigKey("!"); err == nil {
		t.Error("should fail")
	}
	up, err := uid.Update(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if err := up.VerifyUserSig(uid); err != nil {
		t.Error(err)
	}
}
コード例 #19
0
ファイル: uid.go プロジェクト: JonathanLogan/mute
// Encrypt encryptes the given UID message.
func (msg *Message) Encrypt() (UIDHash, UIDIndex []byte, UIDMessageEncrypted string) {
	Message := msg.JSON()
	// Calculate hash: UIDHash = sha256(UIDMessage)
	UIDHash = cipher.SHA256(Message)
	// Calculate hash: UIDIndex = sha256(UIDHash)
	UIDIndex = cipher.SHA256(UIDHash)
	// Encrypt UIDMessage: UIDMessageEncrypted = UIDIndex | nonce | aes_ctr(nonce, key=UIDHash, UIDMessage)
	enc := cipher.AES256CTREncrypt(UIDHash, Message, cipher.RandReader)
	uidEnc := make([]byte, sha256.Size+len(enc))
	copy(uidEnc, UIDIndex)
	copy(uidEnc[sha256.Size:], enc)
	UIDMessageEncrypted = base64.Encode(uidEnc)
	return
}
コード例 #20
0
ファイル: keyinit_test.go プロジェクト: JonathanLogan/mute
func TestVerifySrvSigfailure(t *testing.T) {
	msg, err := Create("*****@*****.**", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(1, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// sign
	sigKey, err := cipher.Ed25519Generate(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	sig := ki.Sign(sigKey)
	pubKey := base64.Encode(sigKey.PublicKey()[:])
	// invalid signature
	if err := ki.VerifySrvSig("!", pubKey); err == nil {
		t.Error("should fail")
	}
	// invalid public key
	if err := ki.VerifySrvSig(sig, "!"); err == nil {
		t.Error("should fail")
	}
	// invalid signature
	var signature [ed25519.PrivateKeySize]byte
	if _, err := io.ReadFull(cipher.RandReader, signature[:]); err != nil {
		t.Fatal(err)
	}
	sig = base64.Encode(signature[:])
	if err := ki.VerifySrvSig(sig, pubKey); err == nil {
		t.Error("should fail")
	}
}
コード例 #21
0
ファイル: keyinit_test.go プロジェクト: JonathanLogan/mute
func TestKeyInitSuccess(t *testing.T) {
	msg, err := Create("*****@*****.**", false, "", "", Strict,
		hashchain.TestEntry, cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	// success
	ki, _, _, err := msg.KeyInit(0, uint64(times.NinetyDaysLater()), 0, false,
		"mute.berlin", "", "", cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	if err := ki.Check(); err != nil {
		t.Error(err)
	}
	// getter methods
	if ki.MsgCount() != ki.Contents.MSGCOUNT {
		t.Error("msgCount mismatch")
	}
	if ki.SigKeyHash() != ki.Contents.SIGKEYHASH {
		t.Error("sigKeyHash mismatch")
	}
	// JSON conversion
	jsn := ki.JSON()
	jsnKI, err := NewJSONKeyInit(jsn)
	if err != nil {
		t.Fatal(err)
	}
	if !bytes.Equal(jsn, jsnKI.JSON()) {
		t.Errorf("KeyInits differ")
	}
	// verify
	uris := make([]string, 1)
	uris[0] = "mute.berlin"
	if err := ki.Verify(uris, msg.UIDContent.SIGKEY.PUBKEY); err != nil {
		t.Error(err)
	}
	// sign
	sigKey, err := cipher.Ed25519Generate(cipher.RandReader)
	if err != nil {
		t.Fatal(err)
	}
	sig := ki.Sign(sigKey)
	// verify signature
	pubKey := base64.Encode(sigKey.PublicKey()[:])
	if err := ki.VerifySrvSig(sig, pubKey); err != nil {
		t.Error(err)
	}
}
コード例 #22
0
ファイル: accounts.go プロジェクト: JonathanLogan/mute
// AddAccount adds an account for myID and contactID (which can be nil) with
// given privkey on server.
func (msgDB *MsgDB) AddAccount(
	myID, contactID string,
	privkey *[ed25519.PrivateKeySize]byte,
	server string,
	secret *[64]byte,
	minDelay, maxDelay int32,
) 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)
		}
	}
	// add account
	_, err := msgDB.addAccountQuery.Exec(mID, cID, base64.Encode(privkey[:]),
		server, base64.Encode(secret[:]), minDelay, maxDelay, 0, 0)
	if err != nil {
		return log.Error(err)
	}
	return nil
}
コード例 #23
0
ファイル: msg.go プロジェクト: JonathanLogan/mute
func (ce *CtrlEngine) msgFetch(
	c *cli.Context,
	id string,
	all bool,
	host string,
) error {
	// process old messages in inqueue
	if err := ce.procInQueue(c, host); err != nil {
		return err
	}

	nyms, err := ce.getNyms(id, all)
	if err != nil {
		return err
	}

	// put new messages from server into in inqueue
	for _, nym := range nyms {
		contacts, err := ce.msgDB.GetAccounts(nym)
		if err != nil {
			return err
		}
		for _, contact := range contacts {
			privkey, server, _, _, _, lastMessageTime, err := ce.msgDB.GetAccount(nym, contact)
			if err != nil {
				return err
			}
			newMessageTime, err := muteprotoFetch(nym, contact, ce.msgDB, c,
				base64.Encode(privkey[:]), server, lastMessageTime)
			if err != nil {
				return log.Error(err)
			}
			if newMessageTime > 0 {
				err = ce.msgDB.SetAccountLastMsg(nym, contact, newMessageTime)
				if err != nil {
					return log.Error(err)
				}
			}
		}
	}

	// process new messages in inqueue
	if err := ce.procInQueue(c, host); err != nil {
		return err
	}
	return nil
}
コード例 #24
0
ファイル: memstore_test.go プロジェクト: JonathanLogan/mute
func TestSessionState(t *testing.T) {
	ms := New()
	ss := &session.State{
		SenderSessionCount: 1,
		SenderMessageCount: 2,
	}
	sessionStateKey := base64.Encode(cipher.SHA512([]byte("sessionstatekey")))
	err := ms.SetSessionState(sessionStateKey, ss)
	if err != nil {
		t.Fatal(err)
	}
	sss, err := ms.GetSessionState(sessionStateKey)
	if err != nil {
		t.Fatal(err)
	}
	if ss != sss {
		t.Error("session states differ")
	}
}
コード例 #25
0
ファイル: ctrlengine.go プロジェクト: frankbraun/mute
func (ce *CtrlEngine) translateError(err error) error {
	switch err {
	case client.ErrNoUser:
		var walletPubkey string
		var pk []byte
		privkey, err := ce.msgDB.GetValue(msgdb.WalletKey)
		if err == nil {
			pk, err = base64.Decode(privkey)
		}
		if err == nil {
			walletPubkey = base64.Encode(pk[32:])
		}
		return fmt.Errorf("Unfortunately, you do not have tokens, yet!\n"+
			"Please send your \n"+
			"WALLETPUBKEY\t%s\n"+
			"per email to [email protected] and stay tuned!", walletPubkey)
	default:
		return err
	}
}
コード例 #26
0
ファイル: nymaddr.go プロジェクト: JonathanLogan/mute
// NewNymAddress generates a new nym address.
func NewNymAddress(
	domain string,
	secret []byte,
	expire int64,
	singleUse bool,
	minDelay, maxDelay int32,
	id string,
	pubkey *[ed25519.PublicKeySize]byte,
	server string,
	caCert []byte,
) (mixaddress, nymaddress string, err error) {
	if err := identity.IsMapped(id); err != nil {
		return "", "", log.Error(err)
	}
	if MixAddress == "" {
		return "", "", log.Error("util: MixAddress undefined")
	}
	mixAddresses, err := client.GetMixKeys(MixAddress, caCert)
	if err != nil {
		return "", "", log.Error(err)
	}
	tmp := nymaddr.AddressTemplate{
		Secret:        secret,
		System:        0,
		MixCandidates: mixAddresses.Addresses,
		Expire:        expire,
		SingleUse:     singleUse,
		MinDelay:      minDelay,
		MaxDelay:      maxDelay,
	}
	nymAddress, err := tmp.NewAddress(MailboxAddress(pubkey, server),
		cipher.SHA256([]byte(id)))
	if err != nil {
		return "", "", log.Error(err)
	}
	addr, err := nymaddr.ParseAddress(nymAddress)
	if err != nil {
		return "", "", log.Error(err)
	}
	return string(addr.MixAddress), base64.Encode(nymAddress), nil
}
コード例 #27
0
ファイル: create.go プロジェクト: JonathanLogan/mute
func (pe *ProtoEngine) create(
	w io.Writer,
	minDelay, maxDelay int32,
	tokenString, nymaddress string,
	r io.Reader,
) error {
	msg, err := ioutil.ReadAll(r)
	if err != nil {
		return log.Error(err)
	}
	message, err := base64.Decode(string(msg))
	if err != nil {
		return log.Error(err)
	}
	token, err := base64.Decode(tokenString)
	if err != nil {
		return log.Error(err)
	}
	na, err := base64.Decode(nymaddress)
	if err != nil {
		return log.Error(err)
	}
	mo := client.MessageInput{
		SenderMinDelay: minDelay,
		SenderMaxDelay: maxDelay,
		Token:          token,
		NymAddress:     na,
		Message:        message,
		SMTPPort:       587,
		//SmartHost:      "mix.serviceguard.chavpn.net", // TODO: allow to set SmartHost
		CACert: def.CACert,
	}.Create()
	if mo.Error != nil {
		return log.Error(mo.Error)
	}
	envelope := mo.Marshal()
	if _, err := io.WriteString(w, base64.Encode(envelope)); err != nil {
		return log.Error(err)
	}
	return nil
}
コード例 #28
0
ファイル: uid.go プロジェクト: JonathanLogan/mute
// CreateReply creates MessageReply.
func CreateReply(
	UIDMessageEncrypted, HCEntry string,
	HCPos uint64,
	sigKey *cipher.Ed25519Key,
) *MessageReply {
	// Construct Entry from hcEntry, hcPos, UIDMessageEncrypted
	entry := Entry{
		UIDMESSAGEENCRYPTED: UIDMessageEncrypted,
		HASHCHAINENTRY:      HCEntry,
		HASHCHAINPOS:        HCPos,
	}

	// Sign Entry by Key Server's key pkey: serverSig = sign(pkey, Entry)
	serverSig := sigKey.Sign(entry.json())

	// Construct MessageReply from Entry, serverSig
	return &MessageReply{
		ENTRY:           entry,
		SERVERSIGNATURE: base64.Encode(serverSig),
	}
}
コード例 #29
0
ファイル: header.go プロジェクト: JonathanLogan/mute
func newHeaderPacket(
	h *header,
	recipientIdentityPub, senderHeaderPriv *[32]byte,
	rand io.Reader,
) (*headerPacket, error) {
	var hp headerPacket
	jsn, err := json.Marshal(h)
	if err != nil {
		return nil, err
	}
	if _, err := io.ReadFull(rand, hp.Nonce[:]); err != nil {
		return nil, log.Error(err)
	}
	log.Debugf("recvPub=%s\n", base64.Encode(recipientIdentityPub[:]))
	hp.EncryptedHeader = box.Seal(hp.EncryptedHeader, jsn, &hp.Nonce,
		recipientIdentityPub, senderHeaderPriv)
	hp.LengthEncryptedHeader = uint16(len(hp.EncryptedHeader))
	if hp.LengthEncryptedHeader != lengthEncryptedHeader {
		return nil,
			log.Errorf("msg: encrypted header has wrong length (%d != %d)",
				hp.LengthEncryptedHeader, lengthEncryptedHeader)
	}
	return &hp, nil
}
コード例 #30
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
}