mirror of https://gogs.blitter.com/RLabs/xs
				
				
				
			Merge branch 'remodulate-on-rekey' of RLabs/xs into master
Add optional cipher/hmac algo remodulate on rekey
This commit is contained in:
		
						commit
						faf8769ac4
					
				
							
								
								
									
										2
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										2
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
VERSION := 0.9.6
 | 
			
		||||
VERSION := 0.9.7
 | 
			
		||||
.PHONY: lint vis clean common client server passwd\
 | 
			
		||||
 subpkgs install uninstall reinstall scc
 | 
			
		||||
 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										12
									
								
								xs/xs.go
								
								
								
								
							
							
						
						
									
										12
									
								
								xs/xs.go
								
								
								
								
							| 
						 | 
				
			
			@ -702,6 +702,7 @@ func main() { //nolint: funlen, gocyclo
 | 
			
		|||
		cmdStr        string
 | 
			
		||||
		tunSpecStr    string // lport1:rport1[,lport2:rport2,...]
 | 
			
		||||
		rekeySecs     uint
 | 
			
		||||
		remodRequested    bool // true: when rekeying, switch to random cipher/hmac alg
 | 
			
		||||
		copySrc       []byte
 | 
			
		||||
		copyDst       string
 | 
			
		||||
		copyQuiet     bool
 | 
			
		||||
| 
						 | 
				
			
			@ -745,8 +746,9 @@ func main() { //nolint: funlen, gocyclo
 | 
			
		|||
      KEX_FRODOKEM_976AES
 | 
			
		||||
      KEX_FRODOKEM_976SHAKE`)
 | 
			
		||||
	flag.StringVar(&kcpMode, "K", "unused", "KCP `alg`, one of [KCP_NONE | KCP_AES | KCP_BLOWFISH | KCP_CAST5 | KCP_SM4 | KCP_SALSA20 | KCP_SIMPLEXOR | KCP_TEA | KCP_3DES | KCP_TWOFISH | KCP_XTEA] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP") //nolint:lll
 | 
			
		||||
	flag.UintVar(&port, "p", 2000, "``port") //nolint:gomnd,lll
 | 
			
		||||
	flag.UintVar(&port, "p", 2000, "``port")                                                                                                                                                                                                                            //nolint:gomnd,lll
 | 
			
		||||
	flag.UintVar(&rekeySecs, "r", 300, "rekey interval in `secs`")
 | 
			
		||||
	flag.BoolVar(&remodRequested, "R", false, "Borg Countermeasures (remodulate cipher/hmac alg on each rekey)")
 | 
			
		||||
	//nolint:gocritic,nolintlint // flag.StringVar(&authCookie, "a", "", "auth cookie")
 | 
			
		||||
	flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
 | 
			
		||||
	flag.UintVar(&chaffFreqMin, "f", 100, "chaff pkt freq min `msecs`")  //nolint:gomnd
 | 
			
		||||
| 
						 | 
				
			
			@ -967,7 +969,13 @@ func main() { //nolint: funlen, gocyclo
 | 
			
		|||
	if kcpMode != "unused" {
 | 
			
		||||
		proto = "kcp"
 | 
			
		||||
	}
 | 
			
		||||
	conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode)
 | 
			
		||||
	
 | 
			
		||||
	remodExtArg := ""
 | 
			
		||||
	if remodRequested {
 | 
			
		||||
		remodExtArg = "OPT_REMOD"
 | 
			
		||||
	}
 | 
			
		||||
	// Pass opt to Dial() via extensions arg
 | 
			
		||||
	conn, err := xsnet.Dial(proto, server, cipherAlg, hmacAlg, kexAlg, kcpMode, remodExtArg)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		fmt.Println(err)
 | 
			
		||||
		exitWithStatus(XSNetDialFailed)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								xsd/xsd.go
								
								
								
								
							
							
						
						
									
										20
									
								
								xsd/xsd.go
								
								
								
								
							| 
						 | 
				
			
			@ -530,12 +530,14 @@ func main() { //nolint:funlen,gocyclo
 | 
			
		|||
	var dbg bool
 | 
			
		||||
	var laddr string
 | 
			
		||||
	var rekeySecs uint
 | 
			
		||||
	var remodSupported bool // true: when rekeying, switch to random cipher/hmac alg
 | 
			
		||||
 | 
			
		||||
	var useSystemPasswd bool
 | 
			
		||||
 | 
			
		||||
	flag.BoolVar(&vopt, "v", false, "show version")
 | 
			
		||||
	flag.UintVar(&rekeySecs, "r", 300, "rekey interval in `secs`")
 | 
			
		||||
	flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") //nolint:gomnd,lll
 | 
			
		||||
	flag.BoolVar(&remodSupported, "R", false, "Borg Countermeasures (remodulate cipher/hmac alg on each rekey)")
 | 
			
		||||
	flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen")                                                                                                                                                                                                         //nolint:gomnd,lll
 | 
			
		||||
	flag.StringVar(&kcpMode, "K", "unused", `set to one of ["KCP_NONE","KCP_AES", "KCP_BLOWFISH", "KCP_CAST5", "KCP_SM4", "KCP_SALSA20", "KCP_SIMPLEXOR", "KCP_TEA", "KCP_3DES", "KCP_TWOFISH", "KCP_XTEA"] to use KCP (github.com/xtaci/kcp-go) reliable UDP instead of TCP`) //nolint:lll
 | 
			
		||||
	flag.BoolVar(&useSysLogin, "L", false, "use system login")
 | 
			
		||||
	flag.BoolVar(&chaffEnabled, "e", true, "enable chaff pkts")
 | 
			
		||||
| 
						 | 
				
			
			@ -702,6 +704,22 @@ func main() { //nolint:funlen,gocyclo
 | 
			
		|||
			} else {
 | 
			
		||||
				log.Println("Accepted client")
 | 
			
		||||
 | 
			
		||||
				// Only enable cipher alg changes on re-key if we were told
 | 
			
		||||
				// to support it (launching xsd with -R), *and* the client
 | 
			
		||||
				// proposes to use it.
 | 
			
		||||
				if !remodSupported {
 | 
			
		||||
					if (conn.Opts() & xsnet.CORemodulateShields) != 0 {
 | 
			
		||||
						logger.LogDebug("[client proposed cipher/hmac remod, but we don't support it.]")
 | 
			
		||||
						conn.Close()
 | 
			
		||||
						continue
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					if conn.Opts()&xsnet.CORemodulateShields != 0 {
 | 
			
		||||
						logger.LogDebug("[cipher/hmac remodulation active]")
 | 
			
		||||
					} else {
 | 
			
		||||
						logger.LogDebug("[cipher/hmac remodulation inactive]")
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
				conn.RekeyHelper(rekeySecs)
 | 
			
		||||
 | 
			
		||||
				// Set up chaffing to client
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								xsnet/net.go
								
								
								
								
							
							
						
						
									
										49
									
								
								xsnet/net.go
								
								
								
								
							| 
						 | 
				
			
			@ -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 {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue