Merge branch '15'
This commit is contained in:
@@ -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) }
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user