Finished main onion layers wrapping
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user