Skip to content

Commit e280f21

Browse files
committed
sphinx: refactor processOnionPacket to use an inner unwrapPacket function
In this commit, we refactor the processOnionPacket as prep for the future EOB parsing. Once EOB's are implemented, the main processOnionPacket may actually unwrap multiple inner packets that are encrypted to the same node identity key.
1 parent 4a64e47 commit e280f21

File tree

1 file changed

+52
-13
lines changed

1 file changed

+52
-13
lines changed

sphinx.go

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)