Files
indra/pkg/wire/layer/layer.go

101 lines
3.3 KiB
Go

package layer
import (
"crypto/cipher"
"fmt"
"github.com/indra-labs/indra"
"github.com/indra-labs/indra/pkg/crypto/ciph"
"github.com/indra-labs/indra/pkg/crypto/key/cloak"
"github.com/indra-labs/indra/pkg/crypto/key/prv"
"github.com/indra-labs/indra/pkg/crypto/key/pub"
"github.com/indra-labs/indra/pkg/crypto/nonce"
log2 "github.com/indra-labs/indra/pkg/proc/log"
"github.com/indra-labs/indra/pkg/types"
"github.com/indra-labs/indra/pkg/util/slice"
"github.com/indra-labs/indra/pkg/wire/magicbytes"
)
const (
MagicString = "os"
Len = magicbytes.Len + nonce.IVLen + cloak.Len + pub.KeyLen
)
var (
log = log2.GetLogger(indra.PathBase)
check = log.E.Chk
Magic = slice.Bytes(MagicString)
_ types.Onion = &OnionSkin{}
)
// OnionSkin message is the generic top level wrapper for an OnionSkin. All
// following messages are wrapped inside this. This type provides the encryption
// for each layer, and a header which a relay uses to determine what cipher to
// use. Everything in a message after this message is encrypted as specified.
type OnionSkin struct {
To *pub.Key
From *prv.Key
// The remainder here are for Decode.
Nonce nonce.IV
Cloak cloak.PubKey
ToPriv *prv.Key
FromPub *pub.Key
// The following field is only populated in the outermost layer, and
// passed in the `b slice.Bytes` parameter in both encode and decode,
// this is created after first getting the Len of everything and
// pre-allocating.
slice.Bytes
types.Onion
}
func (x *OnionSkin) String() string {
return fmt.Sprintf("\n\tnonce: %x\n\tto: %x,\n\tfrom: %x,\n",
x.Nonce, x.To.ToBytes(), x.From.ToBytes())
}
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 Len + x.Onion.Len()
}
func (x *OnionSkin) Encode(b slice.Bytes, c *slice.Cursor) {
copy(b[*c:c.Inc(magicbytes.Len)], Magic)
copy(b[*c:c.Inc(nonce.IVLen)], x.Nonce[:])
// Derive the cloaked key and copy it in.
to := cloak.GetCloak(x.To)
copy(b[*c:c.Inc(cloak.Len)], to[:])
// Derive the public key from the From key and copy in.
pubKey := pub.Derive(x.From).ToBytes()
copy(b[*c:c.Inc(pub.KeyLen)], pubKey[:])
start := *c
// Call the tree of onions to perform their encoding.
x.Onion.Encode(b, c)
// Then we can encrypt the message segment
var e error
var blk cipher.Block
log.T.Ln("encrypting layer")
if blk = ciph.GetBlock(x.From, x.To); check(e) {
panic(e)
}
ciph.Encipher(blk, x.Nonce, b[start:])
}
func (x *OnionSkin) Decode(b slice.Bytes, c *slice.Cursor) (e error) {
if len(b[*c:]) < Len-magicbytes.Len {
return magicbytes.TooShort(len(b[*c:]), Len-magicbytes.Len, "message")
}
copy(x.Nonce[:], b[*c:c.Inc(nonce.IVLen)])
copy(x.Cloak[:], b[*c:c.Inc(cloak.Len)])
if x.FromPub, e = pub.FromBytes(b[*c:c.Inc(pub.KeyLen)]); check(e) {
return
}
// A further step is required which decrypts the remainder of the bytes
// after finding the private key corresponding to the Cloak.
return
}
// 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, b slice.Bytes, c *slice.Cursor) {
ciph.Encipher(ciph.GetBlock(prk, x.FromPub), x.Nonce, b[*c:])
}