Added Confirmation message and removed Acknowledgement
This commit is contained in:
@@ -1,10 +1,6 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
||||
"github.com/Indra-Labs/indra"
|
||||
@@ -13,7 +9,6 @@ import (
|
||||
"github.com/Indra-Labs/indra/pkg/key/prv"
|
||||
"github.com/Indra-Labs/indra/pkg/key/pub"
|
||||
"github.com/Indra-Labs/indra/pkg/node"
|
||||
"github.com/Indra-Labs/indra/pkg/nonce"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
"github.com/cybriq/qu"
|
||||
)
|
||||
@@ -75,43 +70,3 @@ func (c *Client) Cleanup() {
|
||||
func (c *Client) Shutdown() {
|
||||
c.C.Q()
|
||||
}
|
||||
|
||||
const CircuitLen = 5
|
||||
const CircuitExit = 2
|
||||
const ReturnLen = 3
|
||||
|
||||
func (c *Client) GeneratePath(length, exit int) (ci *Circuit, e error) {
|
||||
if len(c.Sessions) < 5 {
|
||||
e = fmt.Errorf("insufficient Sessions to form a circuit, "+
|
||||
"5 required, %d available", len(c.Sessions))
|
||||
return
|
||||
}
|
||||
nodesLen := len(c.Nodes)
|
||||
s := make(node.Nodes, nodesLen)
|
||||
for i := range s {
|
||||
s[i] = c.Nodes[i]
|
||||
}
|
||||
randBytes := make([]byte, 8)
|
||||
// use crypto/rand to seed PRNG to avoid possible timing attacks.
|
||||
var n int
|
||||
if n, e = crand.Read(randBytes); check(e) && n != 8 {
|
||||
return
|
||||
}
|
||||
rand.Seed(int64(binary.LittleEndian.Uint64(randBytes)))
|
||||
rand.Shuffle(nodesLen, func(i, j int) { s[i], s[j] = s[j], s[i] })
|
||||
ci = &Circuit{
|
||||
ID: nonce.NewID(),
|
||||
Hops: s[:length],
|
||||
Exit: exit,
|
||||
}
|
||||
c.Circuits = c.Circuits.Add(ci)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Client) GenerateCircuit() (ci *Circuit, e error) {
|
||||
return c.GeneratePath(CircuitLen, CircuitExit)
|
||||
}
|
||||
|
||||
func (c *Client) GenerateReturn() (ci *Circuit, e error) {
|
||||
return c.GeneratePath(ReturnLen, CircuitExit)
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
// with new credit, and the current state of the encryption.
|
||||
type Session struct {
|
||||
nonce.ID
|
||||
Remaining uint64
|
||||
SendEntry *address.SendEntry
|
||||
ReceiveEntry *address.ReceiveEntry
|
||||
KeyRoller *signer.KeySet
|
||||
Remaining uint64
|
||||
Forward, Return *address.SendEntry
|
||||
ReceiveEntry *address.ReceiveEntry
|
||||
KeyRoller *signer.KeySet
|
||||
}
|
||||
|
||||
type Sessions []*Session
|
||||
@@ -49,13 +49,13 @@ func (s Sessions) Find(t nonce.ID) (se *Session) {
|
||||
//
|
||||
// Purchasing a session the seller returns a token, based on a requested data
|
||||
// allocation,
|
||||
func NewSession(id nonce.ID, rem uint64, se *address.SendEntry,
|
||||
func NewSession(id nonce.ID, rem uint64, fwd, rtn *address.SendEntry,
|
||||
re *address.ReceiveEntry, kr *signer.KeySet) (s *Session) {
|
||||
|
||||
s = &Session{
|
||||
ID: id,
|
||||
Remaining: rem,
|
||||
SendEntry: se,
|
||||
Forward: fwd,
|
||||
ReceiveEntry: re,
|
||||
KeyRoller: kr,
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func (s *Session) SubtractBytes(b uint64) bool {
|
||||
}
|
||||
|
||||
func (s *Session) SetSendEntry(se *address.SendEntry) {
|
||||
s.SendEntry = se
|
||||
s.Forward = se
|
||||
}
|
||||
|
||||
func (s *Session) SetReceiveEntry(re *address.ReceiveEntry) {
|
||||
|
||||
@@ -16,6 +16,9 @@ type OnionSkins []Onion
|
||||
func (o OnionSkins) Message(to *address.Sender, from *prv.Key) OnionSkins {
|
||||
return append(o, &Message{To: to, From: from})
|
||||
}
|
||||
func (o OnionSkins) Confirmation(ciph sha256.Hash, id nonce.ID) OnionSkins {
|
||||
return append(o, &Confirmation{Cipher: ciph, ID: id})
|
||||
}
|
||||
func (o OnionSkins) Forward(ip net.IP) OnionSkins {
|
||||
return append(o, &Forward{IP: ip})
|
||||
}
|
||||
@@ -38,9 +41,6 @@ func (o OnionSkins) Session(fwd, rtn pub.Key) OnionSkins {
|
||||
ForwardKey: fwd.ToBytes(), ReturnKey: rtn.ToBytes(),
|
||||
})
|
||||
}
|
||||
func (o OnionSkins) Acknowledgement(id nonce.ID) OnionSkins {
|
||||
return append(o, &Acknowledgement{ID: id})
|
||||
}
|
||||
func (o OnionSkins) Response(res slice.Bytes) OnionSkins {
|
||||
return append(o, Response(res))
|
||||
}
|
||||
|
||||
@@ -4,9 +4,23 @@ import (
|
||||
"github.com/Indra-Labs/indra/pkg/key/address"
|
||||
"github.com/Indra-Labs/indra/pkg/key/signer"
|
||||
"github.com/Indra-Labs/indra/pkg/node"
|
||||
"github.com/Indra-Labs/indra/pkg/nonce"
|
||||
"github.com/Indra-Labs/indra/pkg/sha256"
|
||||
)
|
||||
|
||||
func Ping(nodes [3]node.Node, set signer.KeySet) Onion {
|
||||
// Ping is a message which checks the liveness of relays by ensuring they are
|
||||
// correctly relaying messages. Pending pings are stored in a table with the
|
||||
// last hop as the key to narrow the number of elements to search through to
|
||||
// find the matching cipher and reveal the contained ID inside it.
|
||||
//
|
||||
// The pending ping records keep the identifiers of the three nodes that were in
|
||||
// a ping onion and when the Confirmation is correctly received these nodes get
|
||||
// an increment of their liveness score. By using this scheme, when nodes are
|
||||
// offline their scores will fall to zero after a time whereas live nodes will
|
||||
// have steadily increasing scores from successful pings.
|
||||
func Ping(ciph sha256.Hash, id nonce.ID, nodes [3]node.Node,
|
||||
set signer.KeySet) Onion {
|
||||
|
||||
return OnionSkins{}.
|
||||
Message(address.FromPubKey(nodes[0].Forward), set.Next()).
|
||||
Forward(nodes[0].IP).
|
||||
@@ -14,5 +28,6 @@ func Ping(nodes [3]node.Node, set signer.KeySet) Onion {
|
||||
Forward(nodes[1].IP).
|
||||
Message(address.FromPubKey(nodes[2].Forward), set.Next()).
|
||||
Forward(nodes[2].IP).
|
||||
Confirmation(ciph, id).
|
||||
Assemble()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"net"
|
||||
|
||||
@@ -25,15 +26,15 @@ var (
|
||||
const MagicLen = 3
|
||||
|
||||
var (
|
||||
ForwardMagic = slice.Bytes("fwd")
|
||||
ExitMagic = slice.Bytes("exi")
|
||||
ReturnMagic = slice.Bytes("rtn")
|
||||
CipherMagic = slice.Bytes("cif")
|
||||
PurchaseMagic = slice.Bytes("prc")
|
||||
SessionMagic = slice.Bytes("ses")
|
||||
AcknowledgementMagic = slice.Bytes("ack")
|
||||
ResponseMagic = slice.Bytes("res")
|
||||
TokenMagic = slice.Bytes("tok")
|
||||
ConfirmationMagic = slice.Bytes("cnf")
|
||||
ForwardMagic = slice.Bytes("fwd")
|
||||
ExitMagic = slice.Bytes("exi")
|
||||
ReturnMagic = slice.Bytes("rtn")
|
||||
CipherMagic = slice.Bytes("cif")
|
||||
PurchaseMagic = slice.Bytes("prc")
|
||||
SessionMagic = slice.Bytes("ses")
|
||||
ResponseMagic = slice.Bytes("res")
|
||||
TokenMagic = slice.Bytes("tok")
|
||||
)
|
||||
|
||||
// Onion is an interface for the layers of messages each encrypted inside a
|
||||
@@ -100,6 +101,42 @@ func (on *Message) Encode(o slice.Bytes, c *slice.Cursor) {
|
||||
copy(o[checkStart:checkEnd], hash[:4])
|
||||
}
|
||||
|
||||
// Confirmation is an encryption layer for messages returned to the client on
|
||||
// the inside of an onion, for Ping and Cipher messages, providing a
|
||||
// confirmation of the transit of the onion through its encoded route.
|
||||
//
|
||||
// It is encrypted because otherwise internal identifiers could be leaked and
|
||||
// potentially reveal something about the entropy of a client/relay.
|
||||
//
|
||||
// In order to speed up recognition, the key of the table of pending Ping and
|
||||
// Cipher messages will include the last hop that will deliver this layer of the
|
||||
// onion - there can be more than one up in the air at a time, but they are
|
||||
// randomly selected, so they will generally be a much smaller subset versus the
|
||||
// current full set of Session s currently open.
|
||||
type Confirmation struct {
|
||||
Cipher sha256.Hash
|
||||
nonce.ID
|
||||
}
|
||||
|
||||
var _ Onion = &Confirmation{}
|
||||
|
||||
func (cf *Confirmation) Inner() Onion { return nil }
|
||||
func (cf *Confirmation) Insert(o Onion) {}
|
||||
func (cf *Confirmation) Len() int {
|
||||
return MagicLen + nonce.IDLen
|
||||
}
|
||||
|
||||
func (cf *Confirmation) Encode(o slice.Bytes, c *slice.Cursor) {
|
||||
copy(o[*c:c.Inc(MagicLen)], ConfirmationMagic)
|
||||
// Generate block cipher from confirmation Cipher.
|
||||
block, _ := aes.NewCipher(cf.Cipher[:])
|
||||
start, end := *c, c.Inc(nonce.IDLen)
|
||||
// Copy in the ID.
|
||||
copy(o[start:end], cf.ID[:])
|
||||
// Encrypt the ID to the cipher.
|
||||
ciph.Encipher(block, nonce.New(), o[start:end])
|
||||
}
|
||||
|
||||
// Forward is just an IP address and a wrapper for another message.
|
||||
type Forward struct {
|
||||
net.IP
|
||||
@@ -278,27 +315,10 @@ func (se *Session) Encode(o slice.Bytes, c *slice.Cursor) {
|
||||
se.Onion.Encode(o, c)
|
||||
}
|
||||
|
||||
// The remaining methods are terminals, all constructed Onion structures
|
||||
// The remaining types are terminals, all constructed Onion structures
|
||||
// should have one of these as the last element otherwise the second last call
|
||||
// to Encode will panic with a nil.
|
||||
|
||||
// Acknowledgement messages just contain a nonce ID, these are used to terminate
|
||||
// ping and Cipher onion messages that confirm relaying was successful.
|
||||
type Acknowledgement struct {
|
||||
nonce.ID
|
||||
}
|
||||
|
||||
var _ Onion = &Acknowledgement{}
|
||||
|
||||
func (ak *Acknowledgement) Inner() Onion { return nil }
|
||||
func (ak *Acknowledgement) Insert(_ Onion) {}
|
||||
func (ak *Acknowledgement) Len() int { return MagicLen + nonce.IDLen }
|
||||
|
||||
func (ak *Acknowledgement) Encode(o slice.Bytes, c *slice.Cursor) {
|
||||
copy(o[*c:c.Inc(MagicLen)], AcknowledgementMagic)
|
||||
copy(o[*c:c.Inc(pub.KeyLen)], ak.ID[:])
|
||||
}
|
||||
|
||||
// Response messages are what are carried back via Return messages from an Exit.
|
||||
type Response slice.Bytes
|
||||
|
||||
@@ -316,7 +336,7 @@ func (rs Response) Encode(o slice.Bytes, c *slice.Cursor) {
|
||||
copy(o[*c:c.Inc(len(rs))], rs)
|
||||
}
|
||||
|
||||
// A Token is a 32 byte value. TODO: not sure we need this?
|
||||
// A Token is a 32 byte value.
|
||||
type Token sha256.Hash
|
||||
|
||||
var _ Onion = Token{}
|
||||
|
||||
@@ -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 = "6f024585b196a19c99cd28a80613c3a5a6b8ada1"
|
||||
ParentGitCommit = "6c414cd9e34291f25632a39ee739435a56ce7fa4"
|
||||
// BuildTime stores the time when the current binary was built.
|
||||
BuildTime = "2022-12-19T22:23:36Z"
|
||||
BuildTime = "2022-12-20T09:52:26Z"
|
||||
// SemVer lists the (latest) git tag on the build.
|
||||
SemVer = "v0.0.191"
|
||||
SemVer = "v0.0.192"
|
||||
// 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 = 191
|
||||
Patch = 192
|
||||
)
|
||||
|
||||
// Version returns a pretty printed version information string.
|
||||
|
||||
Reference in New Issue
Block a user