2018-01-13 06:13:01 +00:00
|
|
|
// Package herradurakex - socket lib conforming to
|
|
|
|
// golang.org/pkg/net Conn interface, with
|
|
|
|
// experimental key exchange algorithm by
|
|
|
|
// Omar Alejandro Herrera Reyna
|
|
|
|
// (https://github.com/Caume/HerraduraKEx)
|
|
|
|
//
|
|
|
|
// See README.md for full license info.
|
2018-01-06 15:30:56 +00:00
|
|
|
package herradurakex
|
|
|
|
|
2018-01-09 03:16:55 +00:00
|
|
|
/* This is the core KEx algorithm. For client/server net support code,
|
|
|
|
See hkexnet.go for a golang/pkg/net for the compatible Conn interface
|
|
|
|
using this to transparently negotiate keys and secure a network channel. */
|
|
|
|
|
2018-01-06 15:30:56 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/big"
|
|
|
|
"math/rand"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2018-01-11 21:44:11 +00:00
|
|
|
// HerraduraKEx holds the session state for a key exchange.
|
2018-01-06 15:30:56 +00:00
|
|
|
type HerraduraKEx struct {
|
|
|
|
intSz, pubSz int
|
|
|
|
randctx *rand.Rand
|
|
|
|
a *big.Int
|
|
|
|
b *big.Int
|
|
|
|
d, PeerD *big.Int
|
|
|
|
fa *big.Int
|
|
|
|
}
|
|
|
|
|
2018-01-13 06:13:01 +00:00
|
|
|
// New returns a HerraduraKEx struct.
|
|
|
|
//
|
2018-01-11 21:44:11 +00:00
|
|
|
// i - internal (private) random nonce
|
|
|
|
// p - public (exchanged) random nonce (typically 1/4 bitsize of i)
|
|
|
|
//
|
|
|
|
// If i or p are passed as zero, they will default to 256 and 64,
|
|
|
|
// respectively.
|
2018-01-06 15:30:56 +00:00
|
|
|
func New(i int, p int) (h *HerraduraKEx) {
|
|
|
|
h = new(HerraduraKEx)
|
|
|
|
|
2018-01-06 21:18:58 +00:00
|
|
|
if i == 0 {
|
|
|
|
i = 256
|
|
|
|
}
|
2018-01-06 23:58:30 +00:00
|
|
|
if p == 0 {
|
2018-01-06 21:18:58 +00:00
|
|
|
p = 64
|
|
|
|
}
|
|
|
|
|
2018-01-06 15:30:56 +00:00
|
|
|
h.intSz = i
|
|
|
|
h.pubSz = p
|
|
|
|
|
|
|
|
h.seed()
|
|
|
|
h.a = h.rand()
|
|
|
|
h.b = h.rand()
|
|
|
|
|
|
|
|
h.d = h.fscxRevolve(h.a, h.b, h.pubSz)
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HerraduraKEx) seed() {
|
|
|
|
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
|
|
h.randctx = r
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HerraduraKEx) rand() (v *big.Int) {
|
|
|
|
v = big.NewInt(0)
|
|
|
|
v.Rand(h.randctx, h.getMax())
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2018-01-13 06:13:01 +00:00
|
|
|
// getMax returns the max value for an n-bit big.Int
|
|
|
|
func (h *HerraduraKEx) getMax() (n *big.Int) {
|
|
|
|
n = big.NewInt(0)
|
2018-01-06 15:30:56 +00:00
|
|
|
var max big.Int
|
|
|
|
|
|
|
|
for i := 0; i < h.intSz; i++ {
|
2018-01-13 06:13:01 +00:00
|
|
|
max.SetBit(n, i, 1)
|
2018-01-06 15:30:56 +00:00
|
|
|
}
|
2018-01-13 06:13:01 +00:00
|
|
|
n = &max
|
|
|
|
return n
|
2018-01-06 15:30:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HerraduraKEx) bitX(x *big.Int, pos int) (ret int64) {
|
|
|
|
if pos < 0 {
|
|
|
|
pos = h.intSz - pos
|
|
|
|
}
|
|
|
|
|
|
|
|
if pos == 0 {
|
|
|
|
ret = int64(x.Bit(1) ^ x.Bit(0) ^ x.Bit(h.intSz-1))
|
|
|
|
} else if pos == h.intSz-1 {
|
|
|
|
ret = int64(x.Bit(0) ^ x.Bit(pos) ^ x.Bit(pos-1))
|
|
|
|
} else {
|
|
|
|
ret = int64(x.Bit((pos+1)%h.intSz) ^ x.Bit(pos) ^ x.Bit(pos-1))
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HerraduraKEx) bit(up, down *big.Int, posU, posD int) (ret *big.Int) {
|
|
|
|
return big.NewInt(h.bitX(up, posU) ^ h.bitX(down, posD))
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HerraduraKEx) fscx(up, down *big.Int) (result *big.Int) {
|
|
|
|
result = big.NewInt(0)
|
|
|
|
|
|
|
|
for count := 0; count < h.intSz; count++ {
|
|
|
|
result.Lsh(result, 1)
|
|
|
|
result.Add(result, h.bit(up, down, count, count))
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2018-01-11 21:44:11 +00:00
|
|
|
// This is the iteration function using the result of the previous iteration
|
|
|
|
// as the first parameter and the second parameter of the first iteration.
|
2018-01-06 15:30:56 +00:00
|
|
|
func (h *HerraduraKEx) fscxRevolve(x, y *big.Int, passes int) (result *big.Int) {
|
|
|
|
result = x
|
|
|
|
for count := 0; count < passes; count++ {
|
|
|
|
result = h.fscx(result, y)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2018-01-13 06:13:01 +00:00
|
|
|
// D returns the D (FSCX Revolved) value, input to generate FA
|
2018-01-11 21:44:11 +00:00
|
|
|
// (the value for peer KEx)
|
2018-01-06 15:30:56 +00:00
|
|
|
func (h *HerraduraKEx) D() *big.Int {
|
|
|
|
return h.d
|
|
|
|
}
|
|
|
|
|
2018-01-13 06:13:01 +00:00
|
|
|
// FA returns the FA value, which must be sent to peer for KEx.
|
2018-01-06 15:30:56 +00:00
|
|
|
func (h *HerraduraKEx) FA() {
|
|
|
|
h.fa = h.fscxRevolve(h.PeerD, h.b, h.intSz-h.pubSz)
|
|
|
|
h.fa.Xor(h.fa, h.a)
|
|
|
|
}
|
2018-01-11 21:44:11 +00:00
|
|
|
// Output HerraduraKEx type value as a string. Implements Stringer interface.
|
2018-01-06 15:30:56 +00:00
|
|
|
func (h *HerraduraKEx) String() string {
|
|
|
|
return fmt.Sprintf("s:%d p:%d\na:%s\nb:%s\nd:->%s\n<-PeerD:%s\nfa:%s",
|
|
|
|
h.intSz, h.pubSz,
|
|
|
|
h.a.Text(16), h.b.Text(16),
|
|
|
|
h.d.Text(16),
|
|
|
|
h.PeerD.Text(16),
|
|
|
|
h.fa.Text(16))
|
|
|
|
}
|