Merge branch '15'

This commit is contained in:
l0k18
2023-08-10 18:49:20 +01:00
7 changed files with 89 additions and 34 deletions

View File

@@ -1,6 +1,6 @@
// Package crypt is an onion message layer which specifies that subsequent content will be encrypted.
//
// The cloaked receiver key, and the ephemeral per-message/per-packet "from" keys are intended to be single use only (generated via scalar multiplication with pairs of secrets).
// The cloaked receiver key, and the ephemeral per-message/per-packet "from" keys are intended to be single use only (generated via scalar sum with pairs of randomly generated secrets).
//
// todo: note reference of this algorithm.
package crypt
@@ -30,7 +30,7 @@ var (
)
const (
CryptMagic = "cryp"
Magic = "cryp"
)
// Crypt is an encrypted message, and forms the "skins" of the onions.
@@ -75,6 +75,7 @@ func (x *Crypt) Account(res *sess.Data, sm *sess.Manager, s *sessions.Data,
return
}
res.Sessions = append(res.Sessions, sd)
// The last hop needs no accounting as it's us!
if last {
res.Ret = sd.Header.Bytes
@@ -86,19 +87,24 @@ func (x *Crypt) Account(res *sess.Data, sm *sess.Manager, s *sessions.Data,
// Decode a splice.Splice's next bytes into a Crypt.
func (x *Crypt) Decode(s *splice.Splice) (e error) {
if e = magic.TooShort(s.Remaining(), consts.CryptLen-magic.Len,
CryptMagic); fails(e) {
Magic); fails(e) {
return
}
s.ReadIV(&x.IV).ReadCloak(&x.Cloak).ReadPubkey(&x.FromPub)
s.
ReadIV(&x.IV).
ReadCloak(&x.Cloak).
ReadPubkey(&x.FromPub)
return
}
// Decrypt requires the prv.Pub 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 *Crypt) Decrypt(prk *crypto.Prv, s *splice.Splice) {
ciph.Encipher(ciph.GetBlock(prk, x.FromPub, "decrypt crypt header"),
x.IV, s.GetRest())
c := ciph.GetBlock(prk, x.FromPub)
ciph.Encipher(c, x.IV, s.GetRest())
}
// Encode a Crypt into a splice.Splice's next bytes.
@@ -106,24 +112,31 @@ func (x *Crypt) Decrypt(prk *crypto.Prv, s *splice.Splice) {
// The crypt renders the inner contents first and once complete returns and
// encrypts everything after the Crypt header.
func (x *Crypt) Encode(s *splice.Splice) (e error) {
log.T.F("encoding %s %s %x %x", reflect.TypeOf(x),
x.ToHeaderPub, x.From.ToBytes(), x.IV,
)
if x.ToHeaderPub == nil || x.From == nil {
s.Advance(consts.CryptLen, "crypt")
return
}
s.Magic(CryptMagic).
IV(x.IV).Cloak(x.ToHeaderPub).Pubkey(crypto.DerivePub(x.From))
s.Magic(Magic).
IV(x.IV).
Cloak(x.ToHeaderPub).
Pubkey(crypto.DerivePub(x.From))
// Then we can encrypt the message segment
var blk cipher.Block
if blk = ciph.GetBlock(x.From, x.ToHeaderPub,
"crypt header"); fails(e) {
if blk = ciph.GetBlock(x.From, x.ToHeaderPub); fails(e) {
panic(e)
}
start := s.GetCursor()
end := s.Len()
switch {
case x.Depth == 0:
case x.Depth > 0:
@@ -137,9 +150,9 @@ func (x *Crypt) Encode(s *splice.Splice) (e error) {
}
}
ciph.Encipher(blk, x.IV, s.GetRange(start, end))
if end != s.Len() {
if blk = ciph.GetBlock(x.From, x.ToPayloadPub,
"crypt payload"); fails(e) {
if blk = ciph.GetBlock(x.From, x.ToPayloadPub); fails(e) {
return
}
ciph.Encipher(blk, x.IV, s.GetFrom(end))
@@ -184,7 +197,7 @@ func (x *Crypt) Len() int {
}
// Magic bytes that identify this message
func (x *Crypt) Magic() string { return CryptMagic }
func (x *Crypt) Magic() string { return Magic }
// Wrap inserts an onion inside a Crypt.
func (x *Crypt) Wrap(inner ont.Onion) { x.Onion = inner }
@@ -205,4 +218,4 @@ func New(toHdr, toPld *crypto.Pub, from *crypto.Prv, iv nonce.IV,
// Gen is a factory function to generate an Crypt.
func Gen() codec.Codec { return &Crypt{} }
func init() { reg.Register(CryptMagic, Gen) }
func init() { reg.Register(Magic, Gen) }

View File

@@ -125,7 +125,7 @@ func (x *Route) Decode(s *splice.Splice) (e error) {
// Decrypt decrypts the rest of a message after the Route segment if the
// recipient has the hidden service private key.
func (x *Route) Decrypt(prk *crypto.Prv, s *splice.Splice) {
ciph.Encipher(ciph.GetBlock(prk, x.SenderPub, "route decrypt"), x.IV,
ciph.Encipher(ciph.GetBlock(prk, x.SenderPub), x.IV,
s.GetRest())
// And now we can see the reply field for the return trip.
s.ReadID(&x.ID).ReadCiphers(&x.Ciphers).ReadNonces(&x.Nonces)
@@ -149,7 +149,7 @@ func (x *Route) Encode(s *splice.Splice) (e error) {
}
var blk cipher.Block
// Encrypt the message!
if blk = ciph.GetBlock(x.Sender, x.HiddenService, "route"); fails(e) {
if blk = ciph.GetBlock(x.Sender, x.HiddenService); fails(e) {
return
}
ciph.Encipher(blk, x.IV, s.GetFrom(start))
@@ -197,11 +197,14 @@ func (x *Route) Handle(s *splice.Splice, p ont.Onion, ng ont.Ngin) (e error) {
}
rh := []ont.Onion{
reverse.New(addrs[0]),
crypt.New(rt.Sessions[0].Header.Pub, rt.Sessions[0].Payload.Pub, rt.Keys[0], rt.Nonces[0], 3),
crypt.New(rt.Sessions[0].Header.Pub, rt.Sessions[0].Payload.Pub,
rt.Keys[0], rt.Nonces[0], 3),
reverse.New(addrs[1]),
crypt.New(rt.Sessions[1].Header.Pub, rt.Sessions[1].Payload.Pub, rt.Keys[1], rt.Nonces[1], 2),
crypt.New(rt.Sessions[1].Header.Pub, rt.Sessions[1].Payload.Pub,
rt.Keys[1], rt.Nonces[1], 2),
reverse.New(addrs[2]),
crypt.New(rt.Sessions[2].Header.Pub, rt.Sessions[2].Payload.Pub, rt.Keys[2], rt.Nonces[2], 1),
crypt.New(rt.Sessions[2].Header.Pub, rt.Sessions[2].Payload.Pub,
rt.Keys[2], rt.Nonces[2], 1),
}
// .RoutingHeader(rt)
rHdr := codec.Encode(ont.Assemble(rh))
@@ -216,9 +219,11 @@ func (x *Route) Handle(s *splice.Splice, p ont.Onion, ng ont.Ngin) (e error) {
}
mr := []ont.Onion{
forward.New(addrs[3]),
crypt.New(ss[3].Header.Pub, ss[3].Payload.Pub, ng.Keyset().Next(), n[3], 0),
crypt.New(ss[3].Header.Pub, ss[3].Payload.Pub, ng.Keyset().Next(),
n[3], 0),
forward.New(addrs[4]),
crypt.New(ss[4].Header.Pub, ss[4].Payload.Pub, ng.Keyset().Next(), n[4], 0),
crypt.New(ss[4].Header.Pub, ss[4].Payload.Pub, ng.Keyset().Next(),
n[4], 0),
ready.New(x.ID, x.HiddenService,
x.RoutingHeaderBytes,
hidden.GetRoutingHeaderFromCursor(rHdr),

View File

@@ -93,7 +93,7 @@ func (x *Reverse) Handle(s *splice.Splice, p ont.Onion, ng ont.Ngin) (e error) {
if e = in.Decode(s); fails(e) {
return e
}
if in.Magic() != crypt.CryptMagic {
if in.Magic() != crypt.Magic {
return e
}
on := in.(*crypt.Crypt)
@@ -111,7 +111,7 @@ func (x *Reverse) Handle(s *splice.Splice, p ont.Onion, ng ont.Ngin) (e error) {
on.ToPriv = hdr
// Decrypt using the Payload key and header nonce.
c := s.GetCursor()
ciph.Encipher(ciph.GetBlock(on.ToPriv, on.FromPub, "reverse header"),
ciph.Encipher(ciph.GetBlock(on.ToPriv, on.FromPub),
on.IV, s.GetRange(c, c+2*consts.ReverseCryptLen))
// shift the header segment upwards and pad the
// remainder.
@@ -119,7 +119,7 @@ func (x *Reverse) Handle(s *splice.Splice, p ont.Onion, ng ont.Ngin) (e error) {
s.CopyRanges(first, second, second, last)
s.CopyIntoRange(slice.NoisePad(consts.ReverseCryptLen), second, last)
if last != s.Len() {
ciph.Encipher(ciph.GetBlock(pld, on.FromPub, "reverse payload"),
ciph.Encipher(ciph.GetBlock(pld, on.FromPub),
on.IV, s.GetFrom(last))
}
if string(s.GetRange(start, start+magic.Len)) != Magic {

View File

@@ -20,6 +20,7 @@ var (
// BlockFromHash creates an AES block cipher from an sha256.Hash.
func BlockFromHash(h sha256.Hash) (block cipher.Block) {
// We can ignore the error because sha256.Hash is a valid key size.
block, _ = aes.NewCipher(h[:])
return
@@ -29,20 +30,23 @@ func BlockFromHash(h sha256.Hash) (block cipher.Block) {
// and decrypts encrypted data. If the cipher.Block is nil, it panics (this
// should never happen).
func Encipher(blk cipher.Block, n nonce.IV, b []byte) {
if blk == nil {
panic("Encipher called without a block cipher provided")
} else {
cipher.NewCTR(blk, n[:]).XORKeyStream(b, b)
}
}
// GetBlock returns a block cipher with a secret generated from the provided
// keys using ECDH.
func GetBlock(from *crypto.Prv, to *crypto.Pub, note string) (block cipher.Block) {
func GetBlock(from *crypto.Prv, to *crypto.Pub) (block cipher.Block) {
secret := crypto.ComputeSharedSecret(from, to)
// fb := from.ToBytes()
// log.T.Ln(note, "secret", color.Red.Sprint(enc(secret[:])[:52]), "<-",
// color.Blue.Sprint(enc(fb[:])[:52]), "+", to.ToBased32())
block, _ = aes.NewCipher(secret[:])
return
}

View File

@@ -126,7 +126,7 @@ func DecodePacket(d []byte, from *crypto.Pub, to *crypto.Prv,
c := new(slice.Cursor)
copy(iv[:], d[c.Inc(4+crypto.PubKeyLen+crypto.CloakLen):c.Inc(nonce.IVLen)])
var blk cipher.Block
if blk = ciph.GetBlock(to, from, "packet decode"); fails(e) {
if blk = ciph.GetBlock(to, from); fails(e) {
return
}
// This decrypts the rest of the packet.
@@ -151,7 +151,7 @@ func DecodePacket(d []byte, from *crypto.Pub, to *crypto.Prv,
// signature to the end.
func EncodePacket(ep *PacketParams) (pkt []byte, e error) {
var blk cipher.Block
if blk = ciph.GetBlock(ep.From, ep.To, "packet encode"); fails(e) {
if blk = ciph.GetBlock(ep.From, ep.To); fails(e) {
return
}
nonc := nonce.New()
@@ -191,7 +191,8 @@ func EncodePacket(ep *PacketParams) (pkt []byte, e error) {
// found, it is combined with the public key to generate the cipher and the
// entire packet should then be decrypted, and the DecodePacket function will
// then decode a OnionSkin.
func GetKeysFromPacket(d []byte) (from *crypto.Pub, to crypto.CloakedPubKey, iv nonce.IV,
func GetKeysFromPacket(d []byte) (from *crypto.Pub, to crypto.CloakedPubKey,
iv nonce.IV,
e error) {
pktLen := len(d)
if pktLen < Overhead {

View File

@@ -349,6 +349,38 @@ func (s *Splice) Bytes(b []byte) *Splice {
return s
}
const MaxUint24 = 1<<24 - 1
// Offset writes a 24 bit value into the Splice. Used with the Crypt payload
// cipher offset. A value over MaxUint24 is not recoverable so it will panic.
func (s *Splice) Offset(o uint32) *Splice {
// This offset value being over MaxUint24 is a programmer error.
if o > MaxUint24 {
panic(fmt.Sprintf("payload cipher offset cannot be over %d", MaxUint24))
}
index := s.GetCursor()
// little endian, smallest byte first, bigger bytes after.
s.b[index] = byte(o)
s.b[index+1] = byte(o >> 8)
s.b[index+2] = byte(o >> 16)
s.Advance(3, "payload cipher offset")
return s
}
// ReadOffset decodes the offset and fills the integer with the uint24 value.
func (s *Splice) ReadOffset(o *int) *Splice {
index := s.GetCursor()
// little endian, smallest byte first, bigger bytes after.
*o = int(s.b[index])
*o += int(s.b[index+1]) << 8
*o += int(s.b[index+2]) << 16
s.Advance(3, "payload cipher offset")
return s
}
func (s *Splice) ReadBytes(b *slice.Bytes) *Splice {
bytesLen := slice.DecodeUint32(s.b[*s.c:s.c.Inc(slice.Uint32Len)])
s.Segments = append(s.Segments,

View File

@@ -19,11 +19,11 @@ const (
// URL is the git URL for the repository.
URL = "git.indra-labs.org/dev/ind"
// GitRef is the gitref, as in refs/heads/branchname.
GitRef = "refs/heads/peerstore"
GitRef = "refs/heads/15"
// ParentGitCommit is the commit hash of the parent HEAD.
ParentGitCommit = "ccc276f67b42f2eaeeb10d8274d677749ffc7436"
ParentGitCommit = "742a44445cc6862042a76fdb02e64236fd4340bb"
// BuildTime stores the time when the current binary was built.
BuildTime = "2023-07-23T21:23:39+01:00"
BuildTime = "2023-08-09T21:04:58+01:00"
// SemVer lists the (latest) git tag on the release.
SemVer = "v0.1.20"
// Major is the major number from the tag.