Add optional cipher/hmac algo remodulate on rekey

This commit is contained in:
Russ Magee 2023-12-02 01:58:30 -08:00
parent e82d968381
commit 32b669192b
6 changed files with 103 additions and 11 deletions

View file

@ -22,6 +22,7 @@ import (
"blitter.com/go/cryptmt"
"blitter.com/go/hopscotch"
"blitter.com/go/xs/logger"
"github.com/aead/chacha20/chacha"
"golang.org/x/crypto/blowfish"
"golang.org/x/crypto/twofish"
@ -57,9 +58,19 @@ func expandKeyMat(keymat []byte, blocksize int) []byte {
return keymat
}
/* (Re-)initialize the keystream and hmac state for an xsnet.Conn, returning
a cipherStream and hash
*/
// Choose a cipher and hmac alg from supported sets, given two uint8 values
func getNewStreamAlgs(cb uint8, hb uint8) (config uint32) {
// Get new cipher and hash algs (clamped to valid values) based on
// the input rekeying data
c := (cb % CAlgNoneDisallowed)
h := (hb % HmacNoneDisallowed)
config = uint32(h<<8) | uint32(c)
logger.LogDebug(fmt.Sprintf("[Chose new algs [%d:%d]", h, c))
return
}
// (Re-)initialize the keystream and hmac state for an xsnet.Conn, returning
// a cipherStream and hash
func (hc *Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err error) {
var key []byte
var block cipher.Block

View file

@ -122,5 +122,19 @@ const (
HmacNoneDisallowed
)
// Conn opts outside of basic kex/cipher/hmac connect config
const (
CONone = iota
CORemodulateShields // if set, rekeying also reselects random cipher/hmac alg
)
type COValue uint32
// Available HMACs for hkex.Conn
type CSHmacAlg uint32
// Some bounds-checking consts
const (
REKEY_SECS_MIN = 1
CHAFF_FREQ_MSECS_MIN = 1
)

View file

@ -241,7 +241,7 @@ func (hc *Conn) SetConnOpts(copts uint32) {
//
// Consumers of this lib may use this for protocol-level options not part
// of the KEx or encryption info used by the connection.
func (hc Conn) Opts() uint32 {
func (hc *Conn) Opts() uint32 {
return hc.opts
}
@ -363,6 +363,9 @@ func (hc *Conn) applyConnExtensions(extensions ...string) {
log.Println("[extension arg = H_SHA512]")
hc.cipheropts &= (0xFFFF00FF)
hc.cipheropts |= (HmacSHA512 << 8)
case "OPT_REMOD":
log.Println("[extension arg = OPT_REMOD]")
hc.opts |= CORemodulateShields
//default:
// log.Printf("[Dial ext \"%s\" ignored]\n", s)
}
@ -1351,6 +1354,11 @@ func (hc *Conn) Read(b []byte) (n int, err error) {
//logger.LogDebug(fmt.Sprintf("[Got rekey [%02x %02x %02x ...]\n",
// payloadBytes[0], payloadBytes[1], payloadBytes[2]))
rekeyData := payloadBytes
if (hc.opts & CORemodulateShields) != 0 {
hc.Lock()
hc.cipheropts = getNewStreamAlgs(rekeyData[0], rekeyData[1])
hc.Unlock()
}
hc.r, hc.rm, err = hc.getStream(rekeyData)
case CSOTermSize:
fmt.Sscanf(string(payloadBytes), "%d %d", &hc.Rows, &hc.Cols)
@ -1585,7 +1593,9 @@ func (hc *Conn) StartupChaff() {
}
func (hc *Conn) ShutdownChaff() {
hc.Lock()
hc.chaff.shutdown = true
hc.Unlock()
log.Println("Chaffing SHUTDOWN")
}
@ -1596,16 +1606,28 @@ func (hc *Conn) SetupChaff(msecsMin uint, msecsMax uint, szMax uint) {
}
func (hc *Conn) ShutdownRekey() {
hc.Lock()
hc.rekey = 0
hc.Unlock()
}
func (hc *Conn) RekeyHelper(intervalSecs uint) {
if intervalSecs < REKEY_SECS_MIN {
intervalSecs = REKEY_SECS_MIN
}
go func() {
hc.Lock()
hc.rekey = intervalSecs
hc.Unlock()
for {
if hc.rekey != 0 {
hc.Lock()
rekey := hc.rekey
hc.Unlock()
if rekey != 0 {
//logger.LogDebug(fmt.Sprintf("[rekeyHelper Loop]\n"))
time.Sleep(time.Duration(hc.rekey) * time.Second)
time.Sleep(time.Duration(rekey) * time.Second)
// Send rekey to other end
rekeyData := make([]byte, 64)
@ -1615,6 +1637,9 @@ func (hc *Conn) RekeyHelper(intervalSecs uint) {
//logger.LogDebug("[+rekeyHelper]")
_, err = hc.WritePacket(rekeyData, CSORekey)
hc.Lock()
if (hc.opts & CORemodulateShields) != 0 {
hc.cipheropts = getNewStreamAlgs(rekeyData[0], rekeyData[1])
}
hc.w, hc.wm, err = hc.getStream(rekeyData)
//logger.LogDebug("[-rekeyHelper]")
hc.Unlock()
@ -1631,11 +1656,21 @@ func (hc *Conn) RekeyHelper(intervalSecs uint) {
// Helper routine to spawn a chaffing goroutine for each Conn
func (hc *Conn) chaffHelper() {
// Enforce bounds on chaff frequency and pkt size
hc.Lock()
if hc.chaff.msecsMin < CHAFF_FREQ_MSECS_MIN {
hc.chaff.msecsMin = CHAFF_FREQ_MSECS_MIN
}
hc.Unlock()
go func() {
var nextDuration int
for {
//logger.LogDebug(fmt.Sprintf("[chaffHelper Loop]\n"))
if !hc.chaff.shutdown {
hc.Lock()
shutdown := hc.chaff.shutdown
hc.Unlock()
if !shutdown {
var bufTmp []byte
bufTmp = make([]byte, rand.Intn(int(hc.chaff.szMax)))
min := int(hc.chaff.msecsMin)
@ -1646,7 +1681,9 @@ func (hc *Conn) chaffHelper() {
//logger.LogDebug("[-chaffHelper]")
if err != nil {
log.Println("[ *** error - chaffHelper shutting down *** ]")
hc.Lock()
hc.chaff.shutdown = true
hc.Unlock()
break
}
} else {
@ -1670,7 +1707,9 @@ func (hc *Conn) ShutdownKeepAlive() {
}
func (hc *Conn) ResetKeepAlive() {
hc.Lock()
hc.keepalive = 3
hc.Unlock()
log.Println("KeepAlive RESET")
}
@ -1689,7 +1728,9 @@ func (hc *Conn) keepaliveHelper() {
break
}
time.Sleep(time.Duration(nextDuration) * time.Millisecond)
hc.Lock()
hc.keepalive -= 1
hc.Unlock()
//logger.LogDebug(fmt.Sprintf("[keepAlive is now %d]\n", hc.keepalive))
//if rand.Intn(8) == 0 {