// ReceiveMessage receives a Client-Mix message func ReceiveMessage(lookupKey KeyFunc, message []byte) (*ReceiveStruct, error) { // var uniqueDat []UniquenessData var rstr ReceiveStruct var lenB uint16 decMessage, err := Decrypt(lookupKey, message) if err != nil { return nil, err } rstr.MixHeader, lenB, err = new(ClientMixHeader).Unmarshal(decMessage) if err != nil { return nil, err } // Test Size msgLen := len(decMessage) - int(lenB) if rstr.MixHeader.MessageType == MessageTypeRelay && (msgLen < RelayMinSize || msgLen > RelayMaxSize) { fmt.Println(msgLen) return nil, ErrSize } if rstr.MixHeader.MessageType == MessageTypeForward && (msgLen < ForwardMinSize || msgLen > ForwardMaxSize) { return nil, ErrSize } // Uniqueness data collection if rstr.MixHeader.MessageType == MessageTypeRelay { rstr.NymAddress, err = nymaddr.ParseAddress(rstr.MixHeader.Address) if err != nil { return nil, err } rstr.NymAddressPrivate, err = rstr.NymAddress.GetMixData(nymaddr.KeyFunc(lookupKey)) if err != nil { return nil, err } // First 256byte of message rstr.UniqueTest = append(rstr.UniqueTest, UniquenessData{ Expire: rstr.NymAddressPrivate.Expire, Hash: mkHash(decMessage[lenB : lenB+256]), // First 256 byte of message }) if rstr.NymAddressPrivate.SingleUse { rstr.UniqueTest = append(rstr.UniqueTest, UniquenessData{ Expire: rstr.NymAddressPrivate.Expire, Hash: rstr.NymAddressPrivate.ReceiverPubKey, }) } } else { rstr.UniqueTest = append(rstr.UniqueTest, UniquenessData{ Expire: timeNow() + ExpireReceive, Hash: mkHash(decMessage[lenB : lenB+256]), // First 256 byte of message }) } rstr.Message = decMessage[lenB:] return &rstr, nil }
// 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 }
// NewRelayMessage creates a new message with type MessageTypeRelay. Uses ClientMixHeader SenderMinDelay,SenderMaxDelay,Token. Sets revokeID func (cl *ClientMixHeader) NewRelayMessage(NymAddress []byte, msg []byte) (message []byte, deliverAddress string, err error) { if cl == nil { cl = new(ClientMixHeader) } address, err := nymaddr.ParseAddress(NymAddress) if err != nil { return nil, "", err } NextHopKey := new([KeySize]byte) copy(NextHopKey[:], address.MixPubKey) cl.MessageType = MessageTypeRelay cl.Address = NymAddress revokeID, _ := genNonce() cl.RevokeID = revokeID[:] header := cl.Marshal() messageC := make([]byte, len(header)+len(msg)) copy(messageC[0:len(header)], header) copy(messageC[len(header):], msg) msgEncrypted, err := Encrypt(NextHopKey, nil, messageC) return msgEncrypted, string(address.MixAddress), err }
func (ce *CtrlEngine) procOutQueue( c *cli.Context, nym string, failDelivery bool, ) error { log.Debug("procOutQueue()") for { oqIdx, msg, nymaddress, minDelay, maxDelay, envelope, err := ce.msgDB.GetOutQueue(nym) if err != nil { return err } if msg == "" { log.Debug("break") break // no more messages in outqueue } if !envelope { log.Debug("envelope") // parse nymaddress na, err := base64.Decode(nymaddress) if err != nil { return log.Error(na) } addr, err := nymaddr.ParseAddress(na) if err != nil { return err } // get token from wallet var pubkey [32]byte copy(pubkey[:], addr.TokenPubKey) token, err := wallet.GetToken(ce.client, "Message", &pubkey) if err != nil { return err } // `muteproto create` env, err := muteprotoCreate(c, msg, minDelay, maxDelay, base64.Encode(token.Token), nymaddress) if err != nil { return log.Error(err) } // update outqueue if err := ce.msgDB.SetOutQueue(oqIdx, env); err != nil { ce.client.UnlockToken(token.Hash) return err } ce.client.DelToken(token.Hash) msg = env } // `muteproto deliver` if failDelivery { return log.Error(ErrDeliveryFailed) } sendTime := times.Now() + int64(minDelay) // earliest resend, err := muteprotoDeliver(c, msg) if err != nil { // If the message delivery failed because the token expired in the // meantime we retract the message from the outqueue (setting it // back to 'ToSend') and start the delivery process for this // message all over again. // Matching the error message string is not optimal, but the best // available solution since the error results from calling another // binary (muteproto). if strings.HasSuffix(err.Error(), client.ErrFinal.Error()) { log.Debug("retract") if err := ce.msgDB.RetractOutQueue(oqIdx); err != nil { return err } continue } return log.Error(err) } if resend { // set resend status log.Debug("resend") if err := ce.msgDB.SetResendOutQueue(oqIdx); err != nil { return err } } else { // remove from outqueue log.Debug("remove") if err := ce.msgDB.RemoveOutQueue(oqIdx, sendTime); err != nil { return err } } } return nil }