@@ -707,7 +707,7 @@ func (r *Router) ProcessOnionPacket(onionPkt *OnionPacket,
707707 // Continue to optimistically process this packet, deferring replay
708708 // protection until the end to reduce the penalty of multiple IO
709709 // operations.
710- packet , err := processOnionPacket (onionPkt , & sharedSecret , assocData )
710+ packet , err := processOnionPacket (onionPkt , & sharedSecret , assocData , r )
711711 if err != nil {
712712 return nil , err
713713 }
@@ -734,14 +734,16 @@ func (r *Router) ReconstructOnionPacket(onionPkt *OnionPacket,
734734 return nil , err
735735 }
736736
737- return processOnionPacket (onionPkt , & sharedSecret , assocData )
737+ return processOnionPacket (onionPkt , & sharedSecret , assocData , r )
738738}
739739
740- // processOnionPacket performs the primary key derivation and handling of onion
741- // packets. The processed packets returned from this method should only be used
742- // if the packet was not flagged as a replayed packet.
743- func processOnionPacket (onionPkt * OnionPacket ,
744- sharedSecret * Hash256 , assocData []byte ) (* ProcessedPacket , error ) {
740+ // unwrapPacket wraps a layer of the passed onion packet using the specified
741+ // shared secret and associated data. The associated data will be used to check
742+ // the HMAC at each hop to ensure the same data is passed along with the onion
743+ // packet. This function returns the next inner onion packet layer, along with
744+ // the hop data extracted from the outer onion packet.
745+ func unwrapPacket (onionPkt * OnionPacket , sharedSecret * Hash256 ,
746+ assocData []byte ) (* OnionPacket , * HopData , error ) {
745747
746748 dhKey := onionPkt .EphemeralKey
747749 routeInfo := onionPkt .RoutingInfo
@@ -753,7 +755,7 @@ func processOnionPacket(onionPkt *OnionPacket,
753755 message := append (routeInfo [:], assocData ... )
754756 calculatedMac := calcMac (generateKey ("mu" , sharedSecret ), message )
755757 if ! hmac .Equal (headerMac [:], calculatedMac [:]) {
756- return nil , ErrInvalidOnionHMAC
758+ return nil , nil , ErrInvalidOnionHMAC
757759 }
758760
759761 // Attach the padding zeroes in order to properly strip an encryption
@@ -779,32 +781,69 @@ func processOnionPacket(onionPkt *OnionPacket,
779781 // instructions.
780782 var hopData HopData
781783 if err := hopData .Decode (bytes .NewReader (hopInfo [:])); err != nil {
782- return nil , err
784+ return nil , nil , err
783785 }
784786
785787 // With the necessary items extracted, we'll copy of the onion packet
786788 // for the next node, snipping off our per-hop data.
787789 var nextMixHeader [routingInfoSize ]byte
788- nextFwdMsg := & OnionPacket {
789790 copy (nextMixHeader [:], hopInfo [HopDataSize :])
791+ innerPkt := & OnionPacket {
790792 Version : onionPkt .Version ,
791793 EphemeralKey : nextDHKey ,
792794 RoutingInfo : nextMixHeader ,
793795 HeaderMAC : hopData .HMAC ,
794796 }
795797
798+ return innerPkt , & hopData , nil
799+ }
800+
801+ // sharedSecretGenerator is an interface that abstracts away exactly *how* the
802+ // shared secret for each hop is generated.
803+ //
804+ // TODO(roasbef): rename?
805+ type sharedSecretGenerator interface {
806+ // generateSharedSecret given a public key, generates a shared secret
807+ // using private data of the underlying sharedSecretGenerator.
808+ generateSharedSecret (dhKey * btcec.PublicKey ) (Hash256 , error )
809+ }
810+
811+ // processOnionPacket performs the primary key derivation and handling of onion
812+ // packets. The processed packets returned from this method should only be used
813+ // if the packet was not flagged as a replayed packet.
814+ func processOnionPacket (onionPkt * OnionPacket , sharedSecret * Hash256 ,
815+ assocData []byte ,
816+ sharedSecretGen sharedSecretGenerator ) (* ProcessedPacket , error ) {
817+
818+ // First, we'll unwrap an initial layer of the onion packet. Typically,
819+ // we'll only have a single layer to unwrap, However, if the sender has
820+ // additional data for us within the Extra Onion Blobs (EOBs), then we
821+ // may have to unwrap additional layers. By default, the inner most
822+ // mix header is the one that we'll want to pass onto the next hop so
823+ // they can properly check the HMAC and unwrap a layer for their
824+ // handoff hop.
825+ innerPkt , outerHopData , err := unwrapPacket (
826+ onionPkt , sharedSecret , assocData ,
827+ )
828+ if err != nil {
829+ return nil , err
830+ }
831+
796832 // By default we'll assume that there are additional hops in the route.
797833 // However if the uncovered 'nextMac' is all zeroes, then this
798834 // indicates that we're the final hop in the route.
799835 var action ProcessCode = MoreHops
800- if bytes .Compare (zeroHMAC [:], hopData .HMAC [:]) == 0 {
836+ if bytes .Compare (zeroHMAC [:], outerHopData .HMAC [:]) == 0 {
801837 action = ExitNode
802838 }
803839
840+ // Finally, we'll return a fully processed packet with the outer most
841+ // hop data (where the primary forwarding instructions lie) and the
842+ // inner most onion packet that we unwrapped.
804843 return & ProcessedPacket {
805844 Action : action ,
806- ForwardingInstructions : hopData ,
807- NextPacket : nextFwdMsg ,
845+ ForwardingInstructions : * outerHopData ,
846+ NextPacket : innerPkt ,
808847 }, nil
809848}
810849
0 commit comments