Finished main onion layers wrapping

This commit is contained in:
David Vennik
2022-12-21 13:46:55 +00:00
parent b3c85dbd17
commit f648d05428
6 changed files with 117 additions and 51 deletions

View File

@@ -60,7 +60,7 @@ package client
// t.FailNow()
// }
// // Create the onion
// var lastMsg ifc.Message
// var lastMsg ifc.Header
// lastMsg, _, e = testutils.GenerateTestMessage(32)
// original := make([]byte, 32)
// copy(original, lastMsg)
@@ -70,7 +70,7 @@ package client
// // progress through the hops in reverse
// rm := &wire.HeaderKey{
// IP: ci.Hops[len(ci.Hops)-i-1].IP,
// Message: lastMsg,
// Header: lastMsg,
// }
// rmm := rm.Encode()
// ep := message.EP{
@@ -127,7 +127,7 @@ package client
// log.I.Ln("did not find matching address.Receiver")
// t.FailNow()
// }
// var f *message.Message
// var f *message.Header
// if f, e = message.Decode(lastMsg, from,
// match.Key); check(e) {
//
@@ -135,7 +135,7 @@ package client
// t.FailNow()
// }
// var rm *wire.HeaderKey
// var msg wire.Message
// var msg wire.Header
// if msg, e = wire.Deserialize(f.Data); check(e) {
// t.Error(e)
// t.FailNow()
@@ -145,9 +145,9 @@ package client
// t.FailNow()
// }
// // log.I.Ln(rm.IP)
// // log.I.S(rm.Message)
// // log.I.S(rm.Header)
// // log.I.Ln(lastMsg[0], net.IP(lastMsg[1:5]))
// lastMsg = rm.Message
// lastMsg = rm.Header
// }
// if string(original) != string(lastMsg) {
// t.Error("failed to recover original message")

View File

@@ -134,7 +134,7 @@ func Encode(ep EP) (pkt []byte, e error) {
// After this, if the matching private key to the cloaked address returned is
// found, it is combined with the public key to generate the cipher and the
// entire packet should then be decrypted, and the Decode function will then
// decode a Message.
// decode a Header.
func GetKeys(d []byte) (from *pub.Key, e error) {
pktLen := len(d)
if pktLen < Overhead {

View File

@@ -13,7 +13,7 @@ import (
type OnionSkins []Onion
func (o OnionSkins) Message(to *address.Sender, from *prv.Key) OnionSkins {
func (o OnionSkins) Header(to *address.Sender, from *prv.Key) OnionSkins {
return append(o, &Message{To: to, From: from})
}
func (o OnionSkins) Confirmation(id nonce.ID) OnionSkins {
@@ -33,8 +33,8 @@ func (o OnionSkins) Return(ip net.IP) OnionSkins {
func (o OnionSkins) Cipher(hdr, pld *prv.Key) OnionSkins {
return append(o, &Cipher{Header: hdr, Payload: pld})
}
func (o OnionSkins) Purchase(value uint64, ciphers [3]sha256.Hash) OnionSkins {
return append(o, &Purchase{Value: value, Ciphers: ciphers})
func (o OnionSkins) Purchase(nBytes uint64, ciphers [3]sha256.Hash) OnionSkins {
return append(o, &Purchase{NBytes: nBytes, Ciphers: ciphers})
}
func (o OnionSkins) Session(fwd, rtn *pub.Key) OnionSkins {
return append(o, &Session{

View File

@@ -2,6 +2,7 @@ package wire
import (
"github.com/Indra-Labs/indra/pkg/key/address"
"github.com/Indra-Labs/indra/pkg/key/ecdh"
"github.com/Indra-Labs/indra/pkg/key/prv"
"github.com/Indra-Labs/indra/pkg/key/signer"
"github.com/Indra-Labs/indra/pkg/node"
@@ -24,18 +25,18 @@ func Ping(id nonce.ID, client node.Node, hop [3]node.Node,
set signer.KeySet) Onion {
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].IP).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].IP).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Forward(client.IP).
Message(address.FromPubKey(client.HeaderKey), set.Next()).
Header(address.FromPubKey(client.HeaderKey), set.Next()).
Confirmation(id).
Assemble()
}
// SendReturn provides a pair of private keys that will be used to generate the
// SendKeys provides a pair of private keys that will be used to generate the
// Purchase header bytes and to generate the ciphers provided in the Purchase
// message to encrypt the Session that is returned.
//
@@ -48,51 +49,122 @@ func Ping(id nonce.ID, client node.Node, hop [3]node.Node,
// This message's last layer is a Confirmation, which allows the client to know
// that the key was successfully delivered to the Return relays that will be
// used in the Purchase.
func SendReturn(id nonce.ID, hdr, pld *prv.Key,
func SendKeys(id nonce.ID, hdr, pld *prv.Key,
client node.Node, hop [5]node.Node, set signer.KeySet) Onion {
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].IP).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].IP).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Cipher(hdr, pld).
Forward(hop[3].IP).
Message(address.FromPubKey(hop[3].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[3].HeaderKey), set.Next()).
Forward(hop[4].IP).
Message(address.FromPubKey(hop[4].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[4].HeaderKey), set.Next()).
Forward(client.IP).
Message(address.FromPubKey(client.HeaderKey), set.Next()).
Header(address.FromPubKey(client.HeaderKey), set.Next()).
Confirmation(id).
Assemble()
}
// SendPurchase delivers a request for keys for a relaying session with a given
// router (in this case, hop 2). It is almost identical to an Exit except the
// payload is always just a 64-bit unsigned integer.
//
// The response, which will be two public keys that identify the session and
// form the basis of the cloaked "To" keys, is encrypted with the given layers,
// the ciphers are already given in reverse order, so they are decoded in given
// order to create the correct payload encryption to match the PayloadKey
// combined with the header's given public From key.
//
// The header remains a constant size and each node in the Return trims off
// their section at the top, moves the next layer header to the top and pads the
// remainder with noise, so it always looks like the first hop,
// indistinguishable.
func SendPurchase(nBytes uint64, client node.Node,
hop [5]node.Node, set signer.KeySet) Onion {
var rtns [3]*prv.Key
for i := range rtns {
rtns[i] = set.Next()
}
// The ciphers represent the combination of the same From key and the
// payload keys combined, which the receiver knows means the header uses
// HeaderKey and the message underneath use a different cipher in place
// of the HeaderKey, the PayloadKey it corresponds to.
ciphers := [3]sha256.Hash{
ecdh.Compute(rtns[2], client.PayloadKey),
ecdh.Compute(rtns[1], hop[4].PayloadKey),
ecdh.Compute(rtns[0], hop[3].PayloadKey),
}
return OnionSkins{}.
Header(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].IP).
Header(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].IP).
Header(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Purchase(nBytes, ciphers).
Return(hop[3].IP).
Header(address.FromPubKey(hop[3].HeaderKey), rtns[0]).
Return(hop[4].IP).
Header(address.FromPubKey(hop[4].HeaderKey), rtns[1]).
Return(client.IP).
Header(address.FromPubKey(client.HeaderKey), rtns[2]).
Assemble()
}
// SendExit constructs a message containing an arbitrary payload to a node (3rd
// hop) with a set of 3 ciphers derived from the hidden PayloadKey of the return
// hops that are layered progressively after the Exit message.
//
// The Exit node forwards the packet it receives to the local port specified in
// the Exit message, and then uses the ciphers to encrypt the return with the
// the Exit message, and then uses the ciphers to encrypt the reply with the
// three ciphers provided, which don't enable it to decrypt the header, only to
// encrypt the payload.
//
// TODO: we can create the ciphers based on hop 3, 4 and client Nodes.
func SendExit(payload slice.Bytes, port uint16, ciphers [3]sha256.Hash,
client node.Node, hop [5]node.Node, set signer.KeySet) Onion {
// The response is encrypted with the given layers, the ciphers are already
// given in reverse order, so they are decoded in given order to create the
// correct payload encryption to match the PayloadKey combined with the header's
// given public From key.
//
// The header remains a constant size and each node in the Return trims off
// their section at the top, moves the next layer header to the top and pads the
// remainder with noise, so it always looks like the first hop,
// indistinguishable.
func SendExit(payload slice.Bytes, port uint16, client node.Node,
hop [5]node.Node, set signer.KeySet) Onion {
var rtns [3]*prv.Key
for i := range rtns {
rtns[i] = set.Next()
}
// The ciphers represent the combination of the same From key and the
// payload keys combined, which the receiver knows means the header uses
// HeaderKey and the message underneath use a different cipher in place
// of the HeaderKey, the PayloadKey it corresponds to.
ciphers := [3]sha256.Hash{
ecdh.Compute(rtns[2], client.PayloadKey),
ecdh.Compute(rtns[1], hop[4].PayloadKey),
ecdh.Compute(rtns[0], hop[3].PayloadKey),
}
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].IP).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].IP).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Header(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Exit(port, ciphers, payload).
Return(hop[3].IP).
Message(address.FromPubKey(hop[3].PayloadKey), set.Next()).
Header(address.FromPubKey(hop[3].HeaderKey), rtns[0]).
Return(hop[4].IP).
Message(address.FromPubKey(hop[4].PayloadKey), set.Next()).
Header(address.FromPubKey(hop[4].HeaderKey), rtns[1]).
Return(client.IP).
Message(address.FromPubKey(client.PayloadKey), set.Next()).
Header(address.FromPubKey(client.HeaderKey), rtns[2]).
Assemble()
}

View File

@@ -82,8 +82,12 @@ func (on *Message) Encode(o slice.Bytes, c *slice.Cursor) {
// Derive the cloaked key and copy it in.
to := on.To.GetCloak()
copy(o[*c:c.Inc(address.Len)], to[:])
// Derive the public key from the From key and copy in.
pubKey := pub.Derive(on.From).ToBytes()
copy(o[*c:c.Inc(pub.KeyLen)], pubKey[:])
// Call the tree of onions to perform their encoding.
on.Onion.Encode(o, c)
// Then we can encrypt the message segment
var e error
var blk cipher.Block
@@ -92,8 +96,8 @@ func (on *Message) Encode(o slice.Bytes, c *slice.Cursor) {
}
ciph.Encipher(blk, n, o[checkEnd:])
// Get the hash of the message and truncate it to the checksum at the
// start of the message. Every layer of the onion has a Message and an
// onion inside it, the Message takes care of the encryption. This saves
// start of the message. Every layer of the onion has a Header and an
// onion inside it, the Header takes care of the encryption. This saves
// on complications as every layer is header first, message after, with
// wrapped messages inside each message afterwards.
hash := sha256.Single(o[checkEnd:])
@@ -253,15 +257,10 @@ func (ci *Cipher) Encode(o slice.Bytes, c *slice.Cursor) {
// message which contains the pair of keys associated with the Session that is
// purchased.
type Purchase struct {
Value uint64
NBytes uint64
// Ciphers is a set of 3 symmetric ciphers that are to be used in their
// given order over the reply message from the service.
Ciphers [3]sha256.Hash
// Return is the pre-formed header which uses different private keys to
// the ones used to create the Ciphers above, meaning the seller can
// encrypt the payload to be correctly decrypted by the Return hops, but
// cannot decrypt the header, which would reveal the return path.
Return slice.Bytes
Onion
}
@@ -270,18 +269,13 @@ var _ Onion = &Purchase{}
func (pr *Purchase) Inner() Onion { return pr.Onion }
func (pr *Purchase) Insert(o Onion) { pr.Onion = o }
func (pr *Purchase) Len() int {
return MagicLen + slice.Uint64Len + len(pr.Return) + pr.Onion.Len()
return MagicLen + slice.Uint64Len + pr.Onion.Len()
}
func (pr *Purchase) Encode(o slice.Bytes, c *slice.Cursor) {
copy(o[*c:c.Inc(MagicLen)], PurchaseMagic)
value := slice.NewUint64()
slice.EncodeUint64(value, pr.Value)
copy(o[*c:c.Inc(slice.Uint64Len)], value)
copy(o[*c:c.Inc(sha256.Len)], pr.Ciphers[0][:])
copy(o[*c:c.Inc(sha256.Len)], pr.Ciphers[1][:])
copy(o[*c:c.Inc(sha256.Len)], pr.Ciphers[1][:])
copy(o[*c:c.Inc(len(pr.Return))], pr.Return)
slice.EncodeUint64(value, pr.NBytes)
pr.Onion.Encode(o, c)
}

View File

@@ -13,11 +13,11 @@ var (
// GitRef is the gitref, as in refs/heads/branchname.
GitRef = "refs/heads/main"
// ParentGitCommit is the commit hash of the parent HEAD.
ParentGitCommit = "6ae27fc4353fe8399f83acfe7639f9168643023a"
ParentGitCommit = "b0d389cfdaf3d1c2db41401fe1d9f6169366493b"
// BuildTime stores the time when the current binary was built.
BuildTime = "2022-12-20T16:42:32Z"
BuildTime = "2022-12-21T13:46:55Z"
// SemVer lists the (latest) git tag on the build.
SemVer = "v0.0.196"
SemVer = "v0.0.197"
// PathBase is the path base returned from runtime caller.
PathBase = "/home/loki/src/github.com/Indra-Labs/indra/"
// Major is the major number from the tag.
@@ -25,7 +25,7 @@ var (
// Minor is the minor number from the tag.
Minor = 0
// Patch is the patch version number from the tag.
Patch = 196
Patch = 197
)
// Version returns a pretty printed version information string.