// 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 }
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 }
// 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 }
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 }
// 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 }
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") } }
// 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) }
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 }
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") } }
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 }
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") } }
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") } }
// 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))) }
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 }
// 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 }
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 }
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 }
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) } }
// 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 }
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") } }
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) } }
// 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 }
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 }
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") } }
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 } }
// 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 }
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 }
// 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), } }
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 }
// 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 }