Now cipher, confirmation and exit encode/decode

This commit is contained in:
David Vennik
2022-12-24 12:28:37 +00:00
parent 0e9d3c31ed
commit c263f75115
8 changed files with 165 additions and 46 deletions

View File

@@ -133,6 +133,11 @@ func NoisePad(l int) (noise []byte) {
type Cursor int
func NewCursor() (c *Cursor) {
var cc Cursor
return &cc
}
func (c *Cursor) Inc(v int) Cursor {
*c += Cursor(v)
return *c

View File

@@ -1,15 +1,19 @@
package wire
import (
"math/rand"
"testing"
"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"
"github.com/Indra-Labs/indra/pkg/testutils"
"github.com/Indra-Labs/indra/pkg/types"
"github.com/Indra-Labs/indra/pkg/wire/cipher"
"github.com/Indra-Labs/indra/pkg/wire/confirmation"
"github.com/Indra-Labs/indra/pkg/wire/exit"
log2 "github.com/cybriq/proc/pkg/log"
)
@@ -18,12 +22,10 @@ func TestOnionSkins_Cipher(t *testing.T) {
var e error
hdrP, pldP := GetTwoPrvKeys(t)
hdr, pld := pub.Derive(hdrP), pub.Derive(pldP)
log.I.S(hdr, pld)
n := nonce.NewID()
log.I.S(n)
// n := nonce.NewID()
on := OnionSkins{}.
Cipher(hdr, pld).
Confirmation(n).
// Confirmation(n).
Assemble()
onb := EncodeOnion(on)
var sc slice.Cursor
@@ -32,19 +34,26 @@ func TestOnionSkins_Cipher(t *testing.T) {
if onc, e = PeelOnion(onb, c); check(e) {
t.FailNow()
}
log.I.S(onc.(*cipher.OnionSkin))
var oncn types.Onion
if oncn, e = PeelOnion(onb, c); check(e) {
var ci *cipher.OnionSkin
var ok bool
if ci, ok = onc.(*cipher.OnionSkin); !ok {
t.Error("did not unwrap expected type")
t.FailNow()
}
if !ci.Header.Equals(hdr) {
t.Error("header key did not unwrap correctly")
t.FailNow()
}
if !ci.Payload.Equals(pld) {
t.Error("payload key did not unwrap correctly")
t.FailNow()
}
log.I.S(oncn.(*confirmation.OnionSkin))
}
func TestOnionSkins_Confirmation(t *testing.T) {
log2.CodeLoc = true
var e error
n := nonce.NewID()
log.I.S(n)
on := OnionSkins{}.
Confirmation(n).
Assemble()
@@ -55,11 +64,60 @@ func TestOnionSkins_Confirmation(t *testing.T) {
if oncn, e = PeelOnion(onb, c); check(e) {
t.FailNow()
}
log.I.S(oncn.(*confirmation.OnionSkin))
var cf *confirmation.OnionSkin
var ok bool
if cf, ok = oncn.(*confirmation.OnionSkin); !ok {
t.Error("did not unwrap expected type")
t.FailNow()
}
if cf.ID != n {
t.Error("confirmation ID did not unwrap correctly")
t.FailNow()
}
}
func TestOnionSkins_Exit(t *testing.T) {
log2.CodeLoc = true
var e error
var msg slice.Bytes
prvs, pubs := GetCipherSet(t)
ciphers := GenCiphers(prvs, pubs)
var hash sha256.Hash
if msg, hash, e = testutils.GenerateTestMessage(512); check(e) {
t.Error(e)
t.FailNow()
}
p := uint16(rand.Uint32())
on := OnionSkins{}.
Exit(p, prvs, pubs, msg).
Assemble()
onb := EncodeOnion(on)
c := slice.NewCursor()
var onex types.Onion
if onex, e = PeelOnion(onb, c); check(e) {
t.FailNow()
}
var ex *exit.OnionSkin
var ok bool
if ex, ok = onex.(*exit.OnionSkin); !ok {
t.Error("did not unwrap expected type")
t.FailNow()
}
if ex.Port != p {
t.Error("exit port did not unwrap correctly")
t.FailNow()
}
for i := range ex.Ciphers {
if ex.Ciphers[i] != ciphers[i] {
t.Errorf("cipher %d did not unwrap correctly", i)
t.FailNow()
}
}
plH := sha256.Single(ex.Bytes)
if plH != hash {
t.Errorf("exit message did not unwrap correctly")
t.FailNow()
}
}
func TestOnionSkins_Forward(t *testing.T) {
@@ -100,3 +158,12 @@ func GetTwoPrvKeys(t *testing.T) (prv1, prv2 *prv.Key) {
}
return
}
func GetCipherSet(t *testing.T) (prvs [3]*prv.Key, pubs [3]*pub.Key) {
for i := range prvs {
prv1, prv2 := GetTwoPrvKeys(t)
prvs[i] = prv1
pubs[i] = pub.Derive(prv2)
}
return
}

View File

@@ -10,12 +10,13 @@ import (
)
var (
log = log2.GetLogger(indra.PathBase)
check = log.E.Chk
MagicString = "ex"
Magic = slice.Bytes(MagicString)
MinLen = magicbytes.Len + slice.Uint16Len + 3*sha256.Len
_ types.Onion = &OnionSkin{}
log = log2.GetLogger(indra.PathBase)
check = log.E.Chk
MagicString = "ex"
Magic = slice.Bytes(MagicString)
MinLen = magicbytes.Len + slice.Uint16Len +
3*sha256.Len + slice.Uint32Len
_ types.Onion = &OnionSkin{}
)
// OnionSkin exit messages are the layer of a message after two Forward packets that
@@ -40,8 +41,7 @@ type OnionSkin struct {
func (x *OnionSkin) Inner() types.Onion { return x.Onion }
func (x *OnionSkin) Insert(o types.Onion) { x.Onion = o }
func (x *OnionSkin) Len() int {
return MinLen + x.Bytes.Len() +
x.Onion.Len()
return MinLen + x.Bytes.Len() + x.Onion.Len()
}
func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
@@ -51,7 +51,7 @@ func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
copy(b[*c:c.Inc(slice.Uint16Len)], port)
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[0][:])
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[1][:])
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[1][:])
copy(b[*c:c.Inc(sha256.Len)], x.Ciphers[2][:])
bytesLen := slice.NewUint32()
slice.EncodeUint32(bytesLen, len(x.Bytes))
copy(b[*c:c.Inc(slice.Uint32Len)], bytesLen)
@@ -60,10 +60,10 @@ func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
}
func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
if len(b[*c:]) < MinLen {
if len(b[*c:]) < MinLen-magicbytes.Len {
return magicbytes.TooShort(len(b[*c:]), MinLen, string(Magic))
}
x.Port = uint16(slice.DecodeUint16(b[*c:slice.Uint16Len]))
x.Port = uint16(slice.DecodeUint16(b[*c:c.Inc(slice.Uint16Len)]))
for i := range x.Ciphers {
bytes := b[*c:c.Inc(sha256.Len)]
copy(x.Ciphers[i][:], bytes)

View File

@@ -4,6 +4,7 @@ import (
"net"
"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/pub"
"github.com/Indra-Labs/indra/pkg/nonce"
@@ -15,6 +16,7 @@ import (
"github.com/Indra-Labs/indra/pkg/wire/exit"
"github.com/Indra-Labs/indra/pkg/wire/forward"
"github.com/Indra-Labs/indra/pkg/wire/message"
"github.com/Indra-Labs/indra/pkg/wire/noop"
"github.com/Indra-Labs/indra/pkg/wire/purchase"
"github.com/Indra-Labs/indra/pkg/wire/reply"
"github.com/Indra-Labs/indra/pkg/wire/response"
@@ -22,37 +24,64 @@ import (
"github.com/Indra-Labs/indra/pkg/wire/token"
)
func GenCiphers(prvs [3]*prv.Key, pubs [3]*pub.Key) (ciphers [3]sha256.Hash) {
for i := range prvs {
ciphers[i] = ecdh.Compute(prvs[i], pubs[i])
}
return
}
type OnionSkins []types.Onion
func (o OnionSkins) Cipher(hdr, pld *pub.Key) OnionSkins {
return append(o, &cipher.OnionSkin{Header: hdr, Payload: pld})
return append(o, &cipher.OnionSkin{
Header: hdr,
Payload: pld,
Onion: &noop.OnionSkin{},
})
}
func (o OnionSkins) Confirmation(id nonce.ID) OnionSkins {
return append(o, &confirmation.OnionSkin{ID: id})
}
func (o OnionSkins) Exit(port uint16, ciphers [3]sha256.Hash,
func (o OnionSkins) Exit(port uint16, prvs [3]*prv.Key, pubs [3]*pub.Key,
payload slice.Bytes) OnionSkins {
return append(o, &exit.OnionSkin{Port: port, Ciphers: ciphers, Bytes: payload})
return append(o, &exit.OnionSkin{
Port: port,
Ciphers: GenCiphers(prvs, pubs),
Bytes: payload,
Onion: &noop.OnionSkin{},
})
}
func (o OnionSkins) Forward(ip net.IP) OnionSkins {
return append(o, &forward.OnionSkin{IP: ip})
return append(o, &forward.OnionSkin{IP: ip, Onion: &noop.OnionSkin{}})
}
func (o OnionSkins) Message(to *address.Sender, from *prv.Key) OnionSkins {
return append(o, &message.OnionSkin{To: to, From: from})
return append(o, &message.OnionSkin{
To: to,
From: from,
Onion: &noop.OnionSkin{},
})
}
func (o OnionSkins) Purchase(nBytes uint64, ciphers [3]sha256.Hash) OnionSkins {
return append(o, &purchase.OnionSkin{NBytes: nBytes, Ciphers: ciphers})
return append(o, &purchase.OnionSkin{
NBytes: nBytes,
Ciphers: ciphers,
Onion: &noop.OnionSkin{},
})
}
func (o OnionSkins) Reply(ip net.IP) OnionSkins {
return append(o, &reply.OnionSkin{IP: ip})
return append(o, &reply.OnionSkin{IP: ip, Onion: &noop.OnionSkin{}})
}
func (o OnionSkins) Response(res slice.Bytes) OnionSkins {
return append(o, response.OnionSkin(res))
}
func (o OnionSkins) Session(fwd, rtn *pub.Key) OnionSkins {
return append(o, &session.OnionSkin{
HeaderKey: fwd, PayloadKey: rtn,
HeaderKey: fwd,
PayloadKey: rtn,
Onion: &noop.OnionSkin{},
})
}
func (o OnionSkins) Token(tok sha256.Hash) OnionSkins {

20
pkg/wire/noop/noop.go Normal file
View File

@@ -0,0 +1,20 @@
package noop
import (
"github.com/Indra-Labs/indra/pkg/slice"
"github.com/Indra-Labs/indra/pkg/types"
)
type OnionSkin struct {
}
func (x *OnionSkin) Inner() types.Onion { return nil }
func (x *OnionSkin) Insert(o types.Onion) {}
func (x *OnionSkin) Len() int { return 0 }
func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
}
func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
return
}

View File

@@ -145,23 +145,21 @@ func SendExit(payload slice.Bytes, port uint16, client node.Node,
replies[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(replies[2], client.PayloadKey),
ecdh.Compute(replies[1], hop[4].PayloadKey),
ecdh.Compute(replies[0], hop[3].PayloadKey),
}
var prvs [3]*prv.Key
var pubs [3]*pub.Key
prvs[0] = replies[2]
prvs[1] = replies[1]
prvs[2] = replies[0]
pubs[0] = client.PayloadKey
pubs[1] = hop[4].PayloadKey
pubs[2] = hop[3].PayloadKey
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].IP).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].IP).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Exit(port, ciphers, payload).
Exit(port, prvs, pubs, payload).
Reply(hop[3].IP).
Message(address.FromPubKey(hop[3].HeaderKey), replies[0]).
Reply(hop[4].IP).

View File

@@ -46,7 +46,7 @@ func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
}
func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
if len(b[*c:]) < MinLen {
if len(b[*c:]) < MinLen-magicbytes.Len {
return magicbytes.TooShort(len(b[*c:]), MinLen, string(Magic))
}
x.NBytes = slice.DecodeUint64(

View File

@@ -10,11 +10,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 = "5ae9415225a073e9535ff3c005243e8c59ba8e89"
ParentGitCommit = "4a1ab0f39c1c71fa5f9e0045ec701f671643ec6e"
// BuildTime stores the time when the current binary was built.
BuildTime = "2022-12-24T11:17:07Z"
BuildTime = "2022-12-24T12:28:37Z"
// SemVer lists the (latest) git tag on the build.
SemVer = "v0.0.227"
SemVer = "v0.0.228"
// 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.
@@ -22,7 +22,7 @@ var (
// Minor is the minor number from the tag.
Minor = 0
// Patch is the patch version number from the tag.
Patch = 227
Patch = 228
)
// Version returns a pretty printed version information string.