All layer types tested and inner layer encryption unwrapped

This commit is contained in:
David Vennik
2022-12-27 12:17:28 +00:00
parent b0b303fb6f
commit b81844a7a1
10 changed files with 105 additions and 91 deletions

View File

@@ -60,7 +60,7 @@ package client
// t.FailNow()
// }
// // Create the onion
// var lastMsg ifc.Message
// var lastMsg ifc.OnionSkin
// 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,
// OnionSkin: 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.OnionSkin
// 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.OnionSkin
// 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.OnionSkin)
// // log.I.Ln(lastMsg[0], net.IP(lastMsg[1:5]))
// lastMsg = rm.Message
// lastMsg = rm.OnionSkin
// }
// 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 OnionSkin.
func GetKeys(d []byte) (from *pub.Key, e error) {
pktLen := len(d)
if pktLen < Overhead {

View File

@@ -5,7 +5,7 @@ import (
)
// Onion is an interface for the layers of messages each encrypted inside a
// Message, which provides the cipher for the inner layers inside it.
// OnionSkin, which provides the cipher for the inner layers inside it.
type Onion interface {
Encode(b slice.Bytes, c *slice.Cursor)
Decode(b slice.Bytes, c *slice.Cursor) (e error)

View File

@@ -9,8 +9,8 @@ import (
"github.com/Indra-Labs/indra/pkg/wire/delay"
"github.com/Indra-Labs/indra/pkg/wire/exit"
"github.com/Indra-Labs/indra/pkg/wire/forward"
"github.com/Indra-Labs/indra/pkg/wire/layer"
"github.com/Indra-Labs/indra/pkg/wire/magicbytes"
"github.com/Indra-Labs/indra/pkg/wire/message"
"github.com/Indra-Labs/indra/pkg/wire/purchase"
"github.com/Indra-Labs/indra/pkg/wire/reply"
"github.com/Indra-Labs/indra/pkg/wire/response"
@@ -41,6 +41,7 @@ func PeelOnion(b slice.Bytes, c *slice.Cursor) (on types.Onion, e error) {
}
on = o
case confirmation.MagicString:
log.I.S("confirmation")
o := &confirmation.OnionSkin{}
if e = o.Decode(b, c); check(e) {
return
@@ -64,8 +65,8 @@ func PeelOnion(b slice.Bytes, c *slice.Cursor) (on types.Onion, e error) {
return
}
on = o
case message.MagicString:
var o message.OnionSkin
case layer.MagicString:
var o layer.OnionSkin
if e = o.Decode(b, c); check(e) {
return
}

View File

@@ -8,6 +8,7 @@ import (
"testing"
"time"
"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"
@@ -20,6 +21,7 @@ import (
"github.com/Indra-Labs/indra/pkg/wire/delay"
"github.com/Indra-Labs/indra/pkg/wire/exit"
"github.com/Indra-Labs/indra/pkg/wire/forward"
"github.com/Indra-Labs/indra/pkg/wire/layer"
"github.com/Indra-Labs/indra/pkg/wire/purchase"
"github.com/Indra-Labs/indra/pkg/wire/reply"
"github.com/Indra-Labs/indra/pkg/wire/response"
@@ -195,8 +197,48 @@ func TestOnionSkins_Forward(t *testing.T) {
}
}
func TestOnionSkins_Message(t *testing.T) {
func TestOnionSkins_Layer(t *testing.T) {
log2.CodeLoc = true
var e error
n := nonce.NewID()
log.I.S("confirmation nonce", n)
prv1, prv2 := GetTwoPrvKeys(t)
pub1 := pub.Derive(prv1)
// log.I.S(pub1.ToBytes(), prv1.ToBytes())
on := OnionSkins{}.
OnionSkin(address.FromPubKey(pub1), prv2).
Confirmation(n).
Assemble()
onb := EncodeOnion(on)
// log.I.S(onb.ToBytes())
c := slice.NewCursor()
var onos, onc types.Onion
if onos, e = PeelOnion(onb, c); check(e) {
t.Error(e)
t.FailNow()
}
os := &layer.OnionSkin{}
var ok bool
if os, ok = onos.(*layer.OnionSkin); !ok {
t.Error("did not unwrap expected type")
t.FailNow()
}
// log.I.S(os.FromPub.ToBytes(), os.Cloak, os.Nonce)
log.I.S(onb[*c:].ToBytes())
os.Decrypt(prv1, onb, c)
log.I.S(onb[*c:].ToBytes())
// unwrap the confirmation
if onc, e = PeelOnion(onb, c); check(e) {
t.Error(e)
t.FailNow()
}
log.I.S(reflect.TypeOf(onc))
oc := &confirmation.OnionSkin{}
if oc, ok = onc.(*confirmation.OnionSkin); !ok {
t.Error("did not unwrap expected type")
t.FailNow()
}
log.I.S(oc)
}
func TestOnionSkins_Purchase(t *testing.T) {

View File

@@ -19,8 +19,8 @@ var (
_ types.Onion = &OnionSkin{}
)
// OnionSkin exit messages are the layer of a message after two Forward packets that
// provides an exit address and
// OnionSkin exit messages are the layer of a message after two Forward packets
// that provides an exit address and
type OnionSkin 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

View File

@@ -1,8 +1,7 @@
package message
package layer
import (
"crypto/cipher"
"fmt"
"github.com/Indra-Labs/indra"
"github.com/Indra-Labs/indra/pkg/ciph"
@@ -10,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/nonce"
"github.com/Indra-Labs/indra/pkg/sha256"
"github.com/Indra-Labs/indra/pkg/slice"
"github.com/Indra-Labs/indra/pkg/types"
"github.com/Indra-Labs/indra/pkg/wire/magicbytes"
@@ -20,7 +18,7 @@ import (
var (
log = log2.GetLogger(indra.PathBase)
check = log.E.Chk
MagicString = "mg"
MagicString = "os"
Magic = slice.Bytes(MagicString)
_ types.Onion = &OnionSkin{}
)
@@ -54,29 +52,20 @@ func (x *OnionSkin) Len() int {
}
func (x *OnionSkin) Encode(b slice.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 b == nil {
b = x.Bytes
}
// Magic after the check, so it is part of the checksum.
copy(b[*c:c.Inc(magicbytes.Len)], Magic)
// Generate a new nonce and copy it in.
n := nonce.New()
copy(b[c.Inc(4):c.Inc(nonce.IVLen)], n[:])
// log.I.S("encryption nonce", n)
copy(b[*c:c.Inc(nonce.IVLen)], n[:])
// Derive the cloaked key and copy it in.
// log.I.S("public key", x.To.ToBytes())
to := x.To.GetCloak()
// log.I.S("cloaked public key", to)
copy(b[*c:c.Inc(address.Len)], to[:])
// Derive the public key from the From key and copy in.
pubKey := pub.Derive(x.From).ToBytes()
// log.I.S("public key of private key used for encryption", pubKey)
copy(b[*c:c.Inc(pub.KeyLen)], pubKey[:])
// Encode the remaining data size of the message below. This will also
// be the entire remaining part of the message buffer.
mLen := len(b[*c:]) - slice.Uint32Len
length := slice.NewUint32()
slice.EncodeUint32(length, mLen)
copy(b[*c:c.Inc(mLen)], b[*c:])
start := *c
// Call the tree of onions to perform their encoding.
x.Onion.Encode(b, c)
@@ -86,40 +75,20 @@ func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
if blk = ciph.GetBlock(x.From, x.To.Key); check(e) {
panic(e)
}
ciph.Encipher(blk, n, b[start+MinLen:])
ciph.Encipher(blk, n, b[start:])
}
// Decode decodes a received message. Note that it only gets the relevant data
// from the header, a subsequent process must be performed to find the prv.Key
// corresponding to the Cloak and the pub.Key together forming the cipher secret
// needed to decrypt the remainder of the bytes.
// Decode decodes a received OnionSkin. The entire remainder of the message is
// encrypted by this layer.
func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
if len(b[*c:]) < MinLen {
return magicbytes.TooShort(len(b[*c:]), MinLen, "message")
if len(b[*c:]) < MinLen-magicbytes.Len {
return magicbytes.TooShort(len(b[*c:]), MinLen-magicbytes.Len, "message")
}
chek := b[*c:c.Inc(4)]
start := int(*c)
var n nonce.IV
copy(n[:], b[c.Inc(magicbytes.Len):c.Inc(nonce.IVLen)])
copy(x.Nonce[:], n[:])
copy(x.Nonce[:], b[*c:c.Inc(nonce.IVLen)])
copy(x.Cloak[:], b[*c:c.Inc(address.Len)])
if x.FromPub, e = pub.FromBytes(b[*c:c.Inc(pub.KeyLen)]); check(e) {
return
}
length := slice.DecodeUint32(b[*c:c.Inc(slice.Uint32Len)])
if length < len(b[*c:]) {
e = fmt.Errorf("not enough remaining bytes as specified in"+
" length field, got: %d expected %d",
length, len(b[*c:]))
}
hash := sha256.Single(b[start : start+length])
if string(hash[:4]) != string(chek) {
return fmt.Errorf("message decode fail checksum")
}
// Snip out bytes for this layer from the remainder, until the length
// indicated by the length prefix. Cursor will now be at the beginning
// of the next layer's messages.
x.Bytes = b[*c:c.Inc(length)]
// A further step is required which decrypts the remainder of the bytes
// after finding the private key corresponding to the Cloak.
return
@@ -128,6 +97,6 @@ func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
// Decrypt requires the prv.Key to be located from the Cloak, using the
// FromPub key to derive the shared secret, and then decrypts the rest of the
// message.
func (x *OnionSkin) Decrypt(prk *prv.Key) {
ciph.Encipher(ciph.GetBlock(prk, x.FromPub), x.Nonce, x.Bytes)
func (x *OnionSkin) Decrypt(prk *prv.Key, b slice.Bytes, c *slice.Cursor) {
ciph.Encipher(ciph.GetBlock(prk, x.FromPub), x.Nonce, b[*c:])
}

View File

@@ -17,7 +17,7 @@ import (
"github.com/Indra-Labs/indra/pkg/wire/delay"
"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/layer"
"github.com/Indra-Labs/indra/pkg/wire/noop"
"github.com/Indra-Labs/indra/pkg/wire/purchase"
"github.com/Indra-Labs/indra/pkg/wire/reply"
@@ -63,11 +63,13 @@ func (o OnionSkins) Exit(port uint16, prvs [3]*prv.Key, pubs [3]*pub.Key,
Onion: os,
})
}
func (o OnionSkins) Forward(addr *netip.AddrPort) OnionSkins {
return append(o, &forward.OnionSkin{AddrPort: addr, Onion: &noop.OnionSkin{}})
}
func (o OnionSkins) Message(to *address.Sender, from *prv.Key) OnionSkins {
return append(o, &message.OnionSkin{
func (o OnionSkins) OnionSkin(to *address.Sender, from *prv.Key) OnionSkins {
return append(o, &layer.OnionSkin{
To: to,
From: from,
Onion: os,

View File

@@ -25,13 +25,13 @@ func Ping(id nonce.ID, client node.Node, hop [3]node.Node,
set signer.KeySet) types.Onion {
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].AddrPort).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].AddrPort).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Forward(client.AddrPort).
Message(address.FromPubKey(client.HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(client.HeaderKey), set.Next()).
Confirmation(id).
Assemble()
}
@@ -40,7 +40,7 @@ func Ping(id nonce.ID, client node.Node, hop [3]node.Node,
// Purchase header bytes and to generate the ciphers provided in the Purchase
// message to encrypt the Session that is returned.
//
// The Message key, its cloaked public key counterpart used in the To field of
// The OnionSkin key, its cloaked public key counterpart used in the To field of
// the Purchase message preformed header bytes, but the Ciphers provided in the
// Purchase message, for encrypting the Session to be returned, uses the Payload
// key, along with the public key found in the encrypted layer of the header for
@@ -53,18 +53,18 @@ func SendKeys(id nonce.ID, hdr, pld *pub.Key,
client node.Node, hop [5]node.Node, set signer.KeySet) types.Onion {
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].AddrPort).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].AddrPort).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Cipher(hdr, pld).
Forward(hop[3].AddrPort).
Message(address.FromPubKey(hop[3].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[3].HeaderKey), set.Next()).
Forward(hop[4].AddrPort).
Message(address.FromPubKey(hop[4].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[4].HeaderKey), set.Next()).
Forward(client.AddrPort).
Message(address.FromPubKey(client.HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(client.HeaderKey), set.Next()).
Confirmation(id).
Assemble()
}
@@ -99,18 +99,18 @@ func SendPurchase(nBytes uint64, client node.Node,
pubs[1] = hop[4].PayloadKey
pubs[2] = hop[3].PayloadKey
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].AddrPort).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].AddrPort).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Purchase(nBytes, prvs, pubs).
Reply(hop[3].AddrPort).
Message(address.FromPubKey(hop[3].HeaderKey), replies[0]).
OnionSkin(address.FromPubKey(hop[3].HeaderKey), replies[0]).
Reply(hop[4].AddrPort).
Message(address.FromPubKey(hop[4].HeaderKey), replies[1]).
OnionSkin(address.FromPubKey(hop[4].HeaderKey), replies[1]).
Reply(client.AddrPort).
Message(address.FromPubKey(client.HeaderKey), replies[2]).
OnionSkin(address.FromPubKey(client.HeaderKey), replies[2]).
Assemble()
}
@@ -149,17 +149,17 @@ func SendExit(payload slice.Bytes, port uint16, client node.Node,
pubs[1] = hop[4].PayloadKey
pubs[2] = hop[3].PayloadKey
return OnionSkins{}.
Message(address.FromPubKey(hop[0].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[0].HeaderKey), set.Next()).
Forward(hop[1].AddrPort).
Message(address.FromPubKey(hop[1].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[1].HeaderKey), set.Next()).
Forward(hop[2].AddrPort).
Message(address.FromPubKey(hop[2].HeaderKey), set.Next()).
OnionSkin(address.FromPubKey(hop[2].HeaderKey), set.Next()).
Exit(port, prvs, pubs, payload).
Reply(hop[3].AddrPort).
Message(address.FromPubKey(hop[3].HeaderKey), replies[0]).
OnionSkin(address.FromPubKey(hop[3].HeaderKey), replies[0]).
Reply(hop[4].AddrPort).
Message(address.FromPubKey(hop[4].HeaderKey), replies[1]).
OnionSkin(address.FromPubKey(hop[4].HeaderKey), replies[1]).
Reply(client.AddrPort).
Message(address.FromPubKey(client.HeaderKey), replies[2]).
OnionSkin(address.FromPubKey(client.HeaderKey), replies[2]).
Assemble()
}

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 = "ff65fa2f04bdd776dff598f63343b2e1dcc07679"
ParentGitCommit = "0fba69ad52595df91c8269247c78567dcea9985b"
// BuildTime stores the time when the current binary was built.
BuildTime = "2022-12-24T17:07:04Z"
BuildTime = "2022-12-27T12:17:28Z"
// SemVer lists the (latest) git tag on the build.
SemVer = "v0.0.236"
SemVer = "v0.0.237"
// 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 = 236
Patch = 237
)
// Version returns a pretty printed version information string.