Drafted all onion message layer types
and including automation for constructing and encrypting onion layers
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/Indra-Labs/indra"
|
||||
"github.com/Indra-Labs/indra/pkg/slice"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
)
|
||||
|
||||
@@ -14,18 +15,17 @@ var (
|
||||
)
|
||||
|
||||
type Transport interface {
|
||||
Send(b Message)
|
||||
Receive() <-chan Message
|
||||
Send(b Bytes)
|
||||
Receive() <-chan Bytes
|
||||
}
|
||||
|
||||
type Message []byte
|
||||
type Bytes []byte
|
||||
|
||||
func ToMessage(b []byte) (msg Message) { return b }
|
||||
func (m Message) ToBytes() []byte { return m }
|
||||
func (m Message) Copy() (o Message) {
|
||||
o = make(Message, len(m))
|
||||
copy(o, m)
|
||||
return
|
||||
func ToBytes(b []byte) (msg Bytes) { return b }
|
||||
func (m Bytes) ToBytes() []byte { return m }
|
||||
func (m Bytes) Len() int { return len(m) }
|
||||
func (m Bytes) Copy(start, end *slice.Cursor, bytes Bytes) {
|
||||
copy(m[*start:*end], bytes[:*end-*start])
|
||||
}
|
||||
|
||||
type U64Slice []uint64
|
||||
@@ -42,7 +42,7 @@ func (u U64Slice) Copy() (o U64Slice) {
|
||||
// intended to be used with short byte slices like cipher nonces and hashes, so
|
||||
// it usually won't trigger allocations off stack and very often won't trigger
|
||||
// a copy on stack, saving a lot of time in a short, oft repeated operations.
|
||||
func (m Message) ToU64Slice() (u U64Slice) {
|
||||
func (m Bytes) ToU64Slice() (u U64Slice) {
|
||||
mLen := uint64(len(m))
|
||||
uLen := int(mLen / 8)
|
||||
mMod := mLen % 8
|
||||
@@ -84,10 +84,10 @@ func (u U64Slice) XOR(v U64Slice) {
|
||||
}
|
||||
}
|
||||
|
||||
func (u U64Slice) ToMessage() (m Message) {
|
||||
func (u U64Slice) ToMessage() (m Bytes) {
|
||||
// length is encoded into the last element
|
||||
mLen := int(u[len(u)-1])
|
||||
m = make(Message, 0, 0)
|
||||
m = make(Bytes, 0, 0)
|
||||
// With the slice now long enough to be safely converted to []uint64
|
||||
// plus an extra uint64 to store the original length we can coerce the
|
||||
// type using unsafe.
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
func TestMessage_ToU64Slice(t *testing.T) {
|
||||
var e error
|
||||
var msg1 Message
|
||||
var msg1 Bytes
|
||||
if msg1, _, e = testutils.GenerateTestMessage(33); check(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
@@ -25,21 +25,21 @@ func TestMessage_ToU64Slice(t *testing.T) {
|
||||
|
||||
func TestU64Slice_XOR(t *testing.T) {
|
||||
var e error
|
||||
var msg1 Message
|
||||
var msg1 Bytes
|
||||
if msg1, _, e = testutils.GenerateTestMessage(33); check(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
}
|
||||
hash1 := sha256.Single(msg1)
|
||||
uMsg1 := msg1.ToU64Slice()
|
||||
var msg2 Message
|
||||
var msg2 Bytes
|
||||
if msg2, _, e = testutils.GenerateTestMessage(33); check(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
}
|
||||
// log.I.S(msg2)
|
||||
uMsg2 := msg2.ToU64Slice()
|
||||
var msg3 Message
|
||||
var msg3 Bytes
|
||||
if msg3, _, e = testutils.GenerateTestMessage(33); check(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
@@ -56,3 +56,15 @@ func TestU64Slice_XOR(t *testing.T) {
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytes_Copy(t *testing.T) {
|
||||
var e error
|
||||
var msg Bytes
|
||||
if msg, _, e = testutils.GenerateTestMessage(33); check(e) {
|
||||
t.Error(e)
|
||||
t.FailNow()
|
||||
}
|
||||
buf := make(Bytes, 65)
|
||||
buf.Copy(10, 20, msg)
|
||||
log.I.S(msg, buf)
|
||||
}
|
||||
|
||||
@@ -70,11 +70,12 @@ func FromBytes(pkb pub.Bytes) (s *Sender, e error) {
|
||||
// generates the 5 bytes at the end of the Cloaked code. In this way the
|
||||
// source public key it relates to is hidden to any who don't have this public
|
||||
// key, which only the parties know.
|
||||
func (s Sender) GetCloak() (c Cloaked, e error) {
|
||||
func (s Sender) GetCloak() (c Cloaked) {
|
||||
var blinder Blinder
|
||||
var n int
|
||||
var e error
|
||||
if n, e = rand.Read(blinder[:]); check(e) && n != BlindLen {
|
||||
return
|
||||
panic("no entropy")
|
||||
}
|
||||
c = Cloak(blinder, s.Key.ToBytes())
|
||||
return
|
||||
@@ -83,7 +84,7 @@ func (s Sender) GetCloak() (c Cloaked, e error) {
|
||||
func Cloak(b Blinder, key pub.Bytes) (c Cloaked) {
|
||||
h := sha256.Single(append(b[:], key[:]...))
|
||||
copy(c[:BlindLen], b[:BlindLen])
|
||||
copy(c[HashLen:], h[:HashLen])
|
||||
copy(c[BlindLen:BlindLen+HashLen], h[:HashLen])
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ func TestAddress(t *testing.T) {
|
||||
r := NewReceiver(sendPriv)
|
||||
s := FromPubKey(r.Pub)
|
||||
var cloaked Cloaked
|
||||
cloaked, e = s.GetCloak()
|
||||
cloaked = s.GetCloak()
|
||||
if !r.Match(cloaked) {
|
||||
t.Error("failed to recognise cloaked address")
|
||||
}
|
||||
|
||||
@@ -38,17 +38,6 @@ type Message struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// GetOverhead returns the packet frame overhead given the settings found in the
|
||||
// packet.
|
||||
func (p *Message) GetOverhead() int {
|
||||
return Overhead
|
||||
}
|
||||
|
||||
// Overhead is the base overhead on a packet, use GetOverhead to add any extra
|
||||
// as found in a Message.
|
||||
const Overhead = slice.Uint16Len +
|
||||
slice.Uint32Len + 1 + KeyEnd
|
||||
|
||||
type Addresses struct {
|
||||
To *address.Sender
|
||||
From *prv.Key
|
||||
@@ -77,7 +66,7 @@ func Encode(To *address.Sender, From *prv.Key, d []byte) (pkt []byte,
|
||||
}
|
||||
nonc := nonce.New()
|
||||
var to address.Cloaked
|
||||
to, e = To.GetCloak()
|
||||
to = To.GetCloak()
|
||||
Length := slice.NewUint32()
|
||||
slice.EncodeUint32(Length, len(d))
|
||||
// Concatenate the message pieces together into a single byte slice.
|
||||
@@ -105,7 +94,7 @@ func Encode(To *address.Sender, From *prv.Key, d []byte) (pkt []byte,
|
||||
}
|
||||
|
||||
// GetKeys returns the To field of the message in order, checks the packet
|
||||
// checksum and recovers the public key signing it.
|
||||
// checksum and recovers the public key.
|
||||
//
|
||||
// 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
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/Indra-Labs/indra"
|
||||
"github.com/Indra-Labs/indra/pkg/ifc"
|
||||
"github.com/Indra-Labs/indra/pkg/sha256"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
)
|
||||
@@ -55,11 +56,20 @@ func Cat(chunks ...[]byte) (pkt []byte) {
|
||||
return
|
||||
}
|
||||
|
||||
var put64 = binary.LittleEndian.PutUint64
|
||||
var get64 = binary.LittleEndian.Uint64
|
||||
var put32 = binary.LittleEndian.PutUint32
|
||||
var get32 = binary.LittleEndian.Uint32
|
||||
var put16 = binary.LittleEndian.PutUint16
|
||||
var get16 = binary.LittleEndian.Uint16
|
||||
|
||||
// DecodeUint64 returns an int containing the little endian encoded 64-bit value
|
||||
// stored in a 4 byte long slice
|
||||
func DecodeUint64(b []byte) uint64 { return get64(b) }
|
||||
|
||||
// EncodeUint64 puts an int into a uint32 and then into 8 byte long slice.
|
||||
func EncodeUint64(b []byte, n uint64) { put64(b, n) }
|
||||
|
||||
// DecodeUint32 returns an int containing the little endian encoded 32bit value
|
||||
// stored in a 4 byte long slice
|
||||
func DecodeUint32(b []byte) int { return int(get32(b)) }
|
||||
@@ -89,17 +99,15 @@ func DecodeUint16(b []byte) int { return int(get16(b)) }
|
||||
// EncodeUint16 puts an int into a uint32 and then into 2 byte long slice.
|
||||
func EncodeUint16(b []byte, n int) { put16(b, uint16(n)) }
|
||||
|
||||
const Uint64Len = 8
|
||||
const Uint32Len = 4
|
||||
const Uint24Len = 3
|
||||
const Uint16Len = 2
|
||||
|
||||
type Size32 []byte
|
||||
type Size24 []byte
|
||||
type Size16 []byte
|
||||
|
||||
func NewUint32() Size32 { return make(Size32, Uint32Len) }
|
||||
func NewUint24() Size24 { return make(Size24, Uint24Len) }
|
||||
func NewUint16() Size16 { return make(Size16, Uint16Len) }
|
||||
func NewUint64() ifc.Bytes { return make(ifc.Bytes, Uint64Len) }
|
||||
func NewUint32() ifc.Bytes { return make(ifc.Bytes, Uint32Len) }
|
||||
func NewUint24() ifc.Bytes { return make(ifc.Bytes, Uint24Len) }
|
||||
func NewUint16() ifc.Bytes { return make(ifc.Bytes, Uint16Len) }
|
||||
|
||||
func NoisePad(l int) (noise []byte) {
|
||||
var seed sha256.Hash
|
||||
@@ -121,3 +129,10 @@ func NoisePad(l int) (noise []byte) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type Cursor int
|
||||
|
||||
func (c *Cursor) Inc(v int) *Cursor {
|
||||
*c += Cursor(v)
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -4,13 +4,13 @@ import (
|
||||
"github.com/Indra-Labs/indra/pkg/ifc"
|
||||
)
|
||||
|
||||
type Sim chan ifc.Message
|
||||
type Sim chan ifc.Bytes
|
||||
|
||||
func (d Sim) Send(b ifc.Message) {
|
||||
func (d Sim) Send(b ifc.Bytes) {
|
||||
d <- b
|
||||
}
|
||||
|
||||
func (d Sim) Receive() <-chan ifc.Message {
|
||||
func (d Sim) Receive() <-chan ifc.Bytes {
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ import (
|
||||
"github.com/Indra-Labs/indra/pkg/ifc"
|
||||
)
|
||||
|
||||
type Dispatcher chan ifc.Message
|
||||
type Dispatcher chan ifc.Bytes
|
||||
|
||||
func (d Dispatcher) Send(b ifc.Message) {
|
||||
func (d Dispatcher) Send(b ifc.Bytes) {
|
||||
d <- b
|
||||
}
|
||||
|
||||
func (d Dispatcher) Receive() <-chan ifc.Message {
|
||||
func (d Dispatcher) Receive() <-chan ifc.Bytes {
|
||||
return d
|
||||
}
|
||||
|
||||
|
||||
305
pkg/wire/onionskins.go
Normal file
305
pkg/wire/onionskins.go
Normal file
@@ -0,0 +1,305 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"net"
|
||||
|
||||
"github.com/Indra-Labs/indra"
|
||||
"github.com/Indra-Labs/indra/pkg/ciph"
|
||||
"github.com/Indra-Labs/indra/pkg/ifc"
|
||||
"github.com/Indra-Labs/indra/pkg/key/address"
|
||||
"github.com/Indra-Labs/indra/pkg/key/prv"
|
||||
"github.com/Indra-Labs/indra/pkg/key/pub"
|
||||
"github.com/Indra-Labs/indra/pkg/nonce"
|
||||
"github.com/Indra-Labs/indra/pkg/sha256"
|
||||
"github.com/Indra-Labs/indra/pkg/slice"
|
||||
log2 "github.com/cybriq/proc/pkg/log"
|
||||
)
|
||||
|
||||
var (
|
||||
log = log2.GetLogger(indra.PathBase)
|
||||
check = log.E.Chk
|
||||
)
|
||||
|
||||
// MagicLen is 3 to make it nearly impossible that the wrong cipher will yield a
|
||||
// valid Magic string as listed below.
|
||||
const MagicLen = 3
|
||||
|
||||
type Onion interface {
|
||||
Encode(o ifc.Bytes, c *slice.Cursor)
|
||||
Len() int
|
||||
}
|
||||
|
||||
var (
|
||||
ForwardMagic = ifc.Bytes("fwd")
|
||||
ExitMagic = ifc.Bytes("exi")
|
||||
ReturnMagic = ifc.Bytes("rtn")
|
||||
CipherMagic = ifc.Bytes("cif")
|
||||
PurchaseMagic = ifc.Bytes("prc")
|
||||
SessionMagic = ifc.Bytes("ses")
|
||||
AcknowledgementMagic = ifc.Bytes("ack")
|
||||
ResponseMagic = ifc.Bytes("res")
|
||||
TokenMagic = ifc.Bytes("tok")
|
||||
)
|
||||
|
||||
// Message is the generic top level wrapper for an Onion. All following messages
|
||||
// are wrapped inside this.
|
||||
type Message struct {
|
||||
To *address.Sender
|
||||
From *prv.Key
|
||||
// The following field is only populated in the outermost layer.
|
||||
ifc.Bytes
|
||||
Onion
|
||||
}
|
||||
|
||||
// NewOnion creates a new Onion. It accepts a recursively structured message
|
||||
// layering definition which all parts know their length, and it stores a buffer.
|
||||
//
|
||||
// Note that this is only required at the top level, following messages inside
|
||||
// the passed message do not need initialisation as there is only one buffer
|
||||
// needed for the entire message, though each layer is started by a Message.
|
||||
//
|
||||
// Example usage:
|
||||
/*
|
||||
|
||||
o := NewOnion(&Message{
|
||||
To: to,
|
||||
From: from,
|
||||
Onion: &Message{
|
||||
To: to,
|
||||
From: from,
|
||||
Onion: &Forward{
|
||||
IP: 10.0.0.1,
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
// Of course normally onions would not be decoratively structured like this,
|
||||
// except Cipher and "ping" messages which have a fixed layer structure.
|
||||
//
|
||||
// Note that the cursor is created here as it can't be easily embedded through
|
||||
// layers of messages wrapped in each other, so this function must be called,
|
||||
// and then Encode method can be called separately with nil for the bytes and
|
||||
// this returned cursor variable. The Bytes don't need to be passed in as the
|
||||
// top level created by this constructor generates one after interrogating all
|
||||
// the layers for their length values.
|
||||
func NewOnion(msg *Message) (o Onion, c *slice.Cursor) {
|
||||
c = new(slice.Cursor)
|
||||
msg.Bytes = make(ifc.Bytes, msg.Len())
|
||||
return msg, c
|
||||
}
|
||||
|
||||
const OnionHeaderLen = 4 + nonce.IVLen + address.Len + pub.KeyLen
|
||||
|
||||
func (on *Message) Len() int { return MagicLen + OnionHeaderLen + on.Onion.Len() }
|
||||
|
||||
func (on *Message) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
// The first level message contains the Bytes, but the inner layers do
|
||||
// not. The inner layers will be passed this buffer, but the first needs
|
||||
// to have it copied from its original location.
|
||||
if o == nil {
|
||||
o = on.Bytes
|
||||
}
|
||||
// We write the checksum last so save the cursor position here.
|
||||
checkStart := *c
|
||||
checkEnd := checkStart + 4
|
||||
// Generate a new nonce and copy it in.
|
||||
n := nonce.New()
|
||||
o.Copy(c.Inc(4), c.Inc(nonce.IVLen), n[:])
|
||||
// Derive the cloaked key and copy it in.
|
||||
to := on.To.GetCloak()
|
||||
o.Copy(c, c.Inc(address.Len), to[:])
|
||||
// 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
|
||||
if blk = ciph.GetBlock(on.From, on.To.Key); check(e) {
|
||||
panic(e)
|
||||
}
|
||||
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
|
||||
// on complications as every layer is header first, message after, with
|
||||
// wrapped messages inside each message afterwards.
|
||||
hash := sha256.Single(o[checkEnd:])
|
||||
copy(o[checkStart:checkEnd], hash[:4])
|
||||
}
|
||||
|
||||
// Forward is just an IP address and a wrapper for another message.
|
||||
type Forward struct {
|
||||
net.IP
|
||||
Onion
|
||||
}
|
||||
|
||||
func (fw *Forward) Len() int { return MagicLen + len(fw.IP) + 1 + fw.Onion.Len() }
|
||||
|
||||
func (fw *Forward) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), ForwardMagic)
|
||||
o[*c] = byte(len(fw.IP))
|
||||
o.Copy(c.Inc(1), c.Inc(len(fw.IP)), ifc.Bytes(fw.IP))
|
||||
fw.Onion.Encode(o, c)
|
||||
}
|
||||
|
||||
// Exit messages are the layer of a message after two Forward packets that
|
||||
// provides an exit address and
|
||||
type Exit struct {
|
||||
// Port identifies the type of service as well as being the port used by
|
||||
// the service to be relayed to. Notice there is no IP address, this is
|
||||
// because Indranet only forwards to exits of decentralised services
|
||||
// also running on the same machine. This service could be a proxy, of
|
||||
// course, if configured this way. This could be done by tunneling from
|
||||
// a local Socks5 proxy into Indranet and the exit node also having
|
||||
// this.
|
||||
Port uint16
|
||||
// Cipher is a set of 3 symmetric ciphers that are to be used in their
|
||||
// given order over the reply message from the service.
|
||||
Cipher [3]sha256.Hash
|
||||
// Bytes are the message to be passed to the exit service.
|
||||
ifc.Bytes
|
||||
// Return is the encoded message with the three hops using the Return
|
||||
// keys for the relevant relays, encrypted progressively. Note that this
|
||||
// message uses a different Cipher than the one above
|
||||
Return
|
||||
}
|
||||
|
||||
func (ex *Exit) Len() int {
|
||||
return MagicLen + slice.Uint16Len + 3*sha256.Len + ex.Bytes.Len() +
|
||||
ex.Return.Len()
|
||||
}
|
||||
|
||||
func (ex *Exit) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), ExitMagic)
|
||||
port := slice.NewUint16()
|
||||
slice.EncodeUint16(port, int(ex.Port))
|
||||
o.Copy(c, c.Inc(slice.Uint16Len), port)
|
||||
o.Copy(c, c.Inc(sha256.Len), ex.Cipher[0][:])
|
||||
o.Copy(c, c.Inc(sha256.Len), ex.Cipher[1][:])
|
||||
o.Copy(c, c.Inc(sha256.Len), ex.Cipher[1][:])
|
||||
bytesLen := slice.NewUint32()
|
||||
slice.EncodeUint32(bytesLen, len(ex.Bytes))
|
||||
o.Copy(c, c.Inc(slice.Uint32Len), bytesLen)
|
||||
o.Copy(c, c.Inc(len(ex.Bytes)), ex.Bytes)
|
||||
ex.Return.Encode(o, c)
|
||||
|
||||
}
|
||||
|
||||
// Return messages are distinct from Forward messages in that the header
|
||||
// encryption uses a different secret than the payload. The magic bytes signal
|
||||
// this to the relay that receives this, which then looks up the Return key
|
||||
// matching the To address in the message header.
|
||||
type Return struct {
|
||||
// IP is the address of the next relay in the return leg of a circuit.
|
||||
net.IP
|
||||
Onion
|
||||
}
|
||||
|
||||
func (rt *Return) Len() int { return MagicLen + len(rt.IP) + 1 + rt.Onion.Len() }
|
||||
|
||||
func (rt *Return) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), ReturnMagic)
|
||||
o[*c] = byte(len(rt.IP))
|
||||
o.Copy(c.Inc(1), c.Inc(len(rt.IP)), ifc.Bytes(rt.IP))
|
||||
rt.Onion.Encode(o, c)
|
||||
}
|
||||
|
||||
// Cipher delivers a public key to be used in association with a Return
|
||||
// specifically in the situation of a node bootstrapping that doesn't have
|
||||
// sessions yet. The ID allows the client to associate the Cipher to the
|
||||
// Purchase.
|
||||
type Cipher struct {
|
||||
nonce.ID
|
||||
Key pub.Bytes
|
||||
Forward
|
||||
}
|
||||
|
||||
func (ci *Cipher) Len() int { return MagicLen + pub.KeyLen + ci.Forward.Len() }
|
||||
|
||||
func (ci *Cipher) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(nonce.IDLen), ci.ID[:])
|
||||
o.Copy(c, c.Inc(MagicLen), CipherMagic)
|
||||
o.Copy(c.Inc(1), c.Inc(sha256.Len), ci.Key[:])
|
||||
ci.Forward.Encode(o, c)
|
||||
}
|
||||
|
||||
// Purchase is a message that is sent after first forwarding a Lighting payment
|
||||
// of an amount corresponding to the number of bytes requested based on the
|
||||
// price advertised for Exit traffic by a relay. The Receipt is the confirmation
|
||||
// after requesting an Invoice for the amount and then paying it.
|
||||
//
|
||||
// This message contains a Return message, which enables payments to proxy
|
||||
// forwards through two hops to the router that will issue the Session, plus two
|
||||
// more Return layers for carrying the Session back to the client.
|
||||
//
|
||||
// Purchases have an ID created by the client.
|
||||
type Purchase struct {
|
||||
Value uint64
|
||||
Return
|
||||
}
|
||||
|
||||
func (pr *Purchase) Len() int {
|
||||
return MagicLen + slice.Uint64Len + pr.Return.Len()
|
||||
}
|
||||
|
||||
func (pr *Purchase) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), PurchaseMagic)
|
||||
value := slice.NewUint64()
|
||||
slice.EncodeUint64(value, pr.Value)
|
||||
o.Copy(c, c.Inc(slice.Uint64Len), value)
|
||||
pr.Return.Encode(o, c)
|
||||
}
|
||||
|
||||
// Session is a message containing two public keys which identify to a relay the
|
||||
// session to account bytes on, this is wrapped in two Return message layers by
|
||||
// the seller. Forward keys are used for encryption in Forward and Exit
|
||||
// messages, and Return keys are separate and are only known to the client and
|
||||
// relay that issues a Session, ensuring that the Exit cannot see the inner
|
||||
// layers of the Return messages.
|
||||
type Session struct {
|
||||
ForwardKey pub.Bytes
|
||||
ReturnKey pub.Bytes
|
||||
Return
|
||||
}
|
||||
|
||||
func (se *Session) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), SessionMagic)
|
||||
o.Copy(c, c.Inc(pub.KeyLen), se.ForwardKey[:])
|
||||
o.Copy(c, c.Inc(pub.KeyLen), se.ReturnKey[:])
|
||||
se.Return.Encode(o, c)
|
||||
}
|
||||
|
||||
// Acknowledgement messages just contain a nonce ID, these are used to terminate
|
||||
// ping and Cipher onion messages which confirms relaying was successful.
|
||||
type Acknowledgement struct {
|
||||
nonce.ID
|
||||
}
|
||||
|
||||
func (ak *Acknowledgement) Len() int { return MagicLen + nonce.IDLen }
|
||||
|
||||
func (ak *Acknowledgement) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), AcknowledgementMagic)
|
||||
o.Copy(c, c.Inc(pub.KeyLen), ak.ID[:])
|
||||
}
|
||||
|
||||
type Response ifc.Bytes
|
||||
|
||||
func (rs Response) Len() int { return MagicLen + len(rs) + 4 }
|
||||
|
||||
func (rs Response) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), ResponseMagic)
|
||||
bytesLen := slice.NewUint32()
|
||||
slice.EncodeUint32(bytesLen, len(rs))
|
||||
o.Copy(c, c.Inc(slice.Uint32Len), bytesLen)
|
||||
o.Copy(c, c.Inc(len(rs)), ifc.Bytes(rs))
|
||||
}
|
||||
|
||||
type Token sha256.Hash
|
||||
|
||||
func (tk Token) Len() int { return MagicLen + sha256.Len }
|
||||
|
||||
func (tk Token) Encode(o ifc.Bytes, c *slice.Cursor) {
|
||||
o.Copy(c, c.Inc(MagicLen), TokenMagic)
|
||||
o.Copy(c, c.Inc(sha256.Len), tk[:])
|
||||
}
|
||||
183
pkg/wire/wire.go
183
pkg/wire/wire.go
@@ -1,183 +0,0 @@
|
||||
package wire
|
||||
|
||||
import (
|
||||
"net"
|
||||
|
||||
"github.com/Indra-Labs/indra/pkg/ifc"
|
||||
"github.com/Indra-Labs/indra/pkg/key/pub"
|
||||
"github.com/Indra-Labs/indra/pkg/message"
|
||||
"github.com/Indra-Labs/indra/pkg/nonce"
|
||||
)
|
||||
|
||||
// MagicLen is 3 to make it nearly impossible that the wrong cipher will yield a
|
||||
// valid Magic string as listed below.
|
||||
const MagicLen = 3
|
||||
|
||||
type MessageMagic string
|
||||
|
||||
type Message interface {
|
||||
Encode() (o ifc.Message)
|
||||
}
|
||||
|
||||
var (
|
||||
ForwardMagic = MessageMagic("fwd")
|
||||
ExitMagic = MessageMagic("exi")
|
||||
ReturnMagic = MessageMagic("rtn")
|
||||
CipherMagic = MessageMagic("cif")
|
||||
PurchaseMagic = MessageMagic("prc")
|
||||
SessionMagic = MessageMagic("ses")
|
||||
)
|
||||
|
||||
// Forward is just an IP address and a wrapper for another message.
|
||||
type Forward struct {
|
||||
*message.Addresses
|
||||
net.IP
|
||||
Message
|
||||
}
|
||||
|
||||
func (fw *Forward) Encode() (o ifc.Message) {
|
||||
ipLen := len(fw.IP)
|
||||
msg := fw.Message.Encode()
|
||||
msg, _ = message.Encode(fw.To, fw.From, msg)
|
||||
fwd := make([]byte, ipLen+1)
|
||||
fwd[0] = byte(ipLen)
|
||||
copy(fwd[1:], fw.IP)
|
||||
o = append(append(ifc.Message(ForwardMagic), fwd...), msg...)
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
func DecodeForward(msg ifc.Message) (rm *Forward, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Exit messages are the layer of a message after two Forward packets that
|
||||
// provides an exit address and
|
||||
type Exit struct {
|
||||
*message.Addresses
|
||||
// Port identifies the type of service as well as being the port used
|
||||
// by the service to be relayed to. Notice there is no IP address, this
|
||||
// is because Indranet only forwards to exits of decentralised services
|
||||
// also running on the same machine. This service could be a proxy, of
|
||||
// course, if configured this way.
|
||||
Port uint16
|
||||
// Cipher is a set of 3 symmetric ciphers that are to be used in their
|
||||
// given order over the reply message from the service.
|
||||
Cipher [3][32]byte
|
||||
// Return is the encoded message with the three hops using the Return
|
||||
// keys for the relevant relays, encrypted progressively. Note that this
|
||||
// message uses a different Cipher than the one above
|
||||
Return ifc.Message
|
||||
Message
|
||||
}
|
||||
|
||||
func (ex *Exit) Encode() (o ifc.Message) {
|
||||
msg := ex.Message.Encode()
|
||||
msg, _ = message.Encode(ex.To, ex.From, msg)
|
||||
return
|
||||
}
|
||||
|
||||
func DecodeExit(msg ifc.Message) (rm *Exit, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Return messages are distinct from Forward messages in that the header
|
||||
// encryption uses a different secret than the payload. Relays identify this by
|
||||
// encrypting the first 16 bytes of the header and if one of the magic bytes is
|
||||
// not found
|
||||
type Return struct {
|
||||
*message.Addresses
|
||||
nonce.ID
|
||||
// IP is the address of the next relay in the return leg of a circuit.
|
||||
net.IP
|
||||
Message
|
||||
}
|
||||
|
||||
func (rt *Return) Encode() (o ifc.Message) {
|
||||
msg := rt.Message.Encode()
|
||||
msg, _ = message.Encode(rt.To, rt.From, msg)
|
||||
return
|
||||
}
|
||||
|
||||
func DecodeReturn(msg ifc.Message) (rm *Return, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Cipher delivers a public key to be used in association with a Return with the
|
||||
// matching ID. This is wrapped in two Forward messages and contains two layers
|
||||
// of Forward messages, ensuring that the node cannot discover where this comes
|
||||
// from but allows a Return public key to be provided for a Purchase.
|
||||
type Cipher struct {
|
||||
*message.Addresses
|
||||
nonce.ID
|
||||
Key pub.Bytes
|
||||
Forward
|
||||
}
|
||||
|
||||
func (ci *Cipher) Encode() (o ifc.Message) {
|
||||
msg := ci.Forward.Encode()
|
||||
msg, _ = message.Encode(ci.To, ci.From, msg)
|
||||
return
|
||||
}
|
||||
|
||||
func DecodeCipher(msg ifc.Message) (rm *Cipher, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Purchase is a message that is sent after first forwarding a Lighting payment
|
||||
// of an amount corresponding to the number of bytes requested based on the
|
||||
// price advertised for Exit traffic by a relay. The Receipt is the confirmation
|
||||
// after requesting an Invoice for the amount and then paying it.
|
||||
//
|
||||
// This message contains a Return message, which enables payments to proxy
|
||||
// forwards through two hops to the router that will issue the Session, plus two
|
||||
// more Return layers for carrying the Session back to the client.
|
||||
type Purchase struct {
|
||||
*message.Addresses
|
||||
Bytes int
|
||||
Receipt ifc.Message
|
||||
Return
|
||||
}
|
||||
|
||||
func (pr *Purchase) Encode() (o ifc.Message) {
|
||||
msg := pr.Return.Encode()
|
||||
msg, _ = message.Encode(pr.To, pr.From, msg)
|
||||
return
|
||||
}
|
||||
|
||||
func DecodePurchase(msg ifc.Message) (rm *Purchase, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Session is a message containing two public keys which identify to a relay the
|
||||
// session to account bytes on, this is wrapped in two Return message layers by
|
||||
// the seller. Forward keys are used for encryption in Forward and Exit
|
||||
// messages, and Return keys are separate and are only known to the client and
|
||||
// relay that issues a Session, ensuring that the Exit cannot see the inner
|
||||
// layers of the Return messages.
|
||||
type Session struct {
|
||||
*message.Addresses
|
||||
ForwardKey pub.Bytes
|
||||
ReturnKey pub.Bytes
|
||||
Return
|
||||
}
|
||||
|
||||
func (se *Session) Encode() (o ifc.Message) {
|
||||
msg := se.Return.Encode()
|
||||
msg, _ = message.Encode(se.To, se.From, msg)
|
||||
return
|
||||
}
|
||||
|
||||
func DecodeSession(msg ifc.Message) (rm *Session, e error) {
|
||||
return
|
||||
}
|
||||
|
||||
type Raw struct {
|
||||
*message.Addresses
|
||||
Bytes []byte
|
||||
}
|
||||
|
||||
func (r Raw) Encode() (o ifc.Message) {
|
||||
o, _ = message.Encode(r.To, r.From, r.Bytes)
|
||||
return
|
||||
}
|
||||
@@ -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 = "a40766089d9ead6c8b7ed52a500aa5f91c72b882"
|
||||
ParentGitCommit = "af876fa30c7b1c97ffe9c3e13e213bbdc7275460"
|
||||
// BuildTime stores the time when the current binary was built.
|
||||
BuildTime = "2022-12-11T22:55:17+01:00"
|
||||
BuildTime = "2022-12-13T09:23:51+01:00"
|
||||
// SemVer lists the (latest) git tag on the build.
|
||||
SemVer = "v0.0.182"
|
||||
SemVer = "v0.0.183"
|
||||
// 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 = 182
|
||||
Patch = 183
|
||||
)
|
||||
|
||||
// Version returns a pretty printed version information string.
|
||||
|
||||
Reference in New Issue
Block a user