goxifrat/xifrat.go
2021-03-08 19:07:24 +01:00

196 lines
4.1 KiB
Go

package goxifrat
import (
"crypto"
"crypto/subtle"
"strconv"
//"crypto/sha512"
"errors"
"io"
)
const (
P = 16
N = 64
R = 64
)
var st = [P][P]uint8{
{7, 9, 13, 10, 15, 2, 0, 6, 3, 12, 8, 4, 1, 5, 14, 11},
{1, 15, 6, 3, 9, 4, 11, 13, 10, 5, 14, 2, 7, 12, 8, 0},
{3, 0, 12, 1, 11, 8, 9, 5, 7, 13, 2, 14, 10, 6, 4, 15},
{4, 6, 15, 8, 13, 1, 5, 9, 14, 11, 10, 7, 2, 0, 3, 12},
{0, 3, 8, 15, 10, 12, 7, 14, 9, 2, 13, 5, 11, 4, 6, 1},
{10, 11, 5, 7, 0, 14, 15, 12, 1, 6, 4, 8, 3, 13, 2, 9},
{5, 14, 10, 13, 8, 11, 4, 3, 6, 1, 15, 0, 12, 7, 9, 2},
{15, 1, 4, 0, 7, 6, 10, 2, 11, 14, 5, 13, 9, 8, 12, 3},
{12, 8, 3, 6, 14, 0, 2, 10, 13, 7, 9, 11, 5, 1, 15, 4},
{13, 2, 7, 5, 4, 9, 8, 1, 12, 3, 0, 15, 6, 10, 11, 14},
{6, 4, 1, 12, 2, 15, 14, 7, 5, 10, 11, 9, 13, 3, 0, 8},
{9, 7, 2, 11, 1, 13, 3, 4, 0, 8, 12, 6, 15, 14, 5, 10},
{11, 10, 14, 9, 3, 5, 1, 8, 15, 4, 6, 12, 0, 2, 13, 7},
{14, 5, 11, 2, 12, 10, 6, 0, 4, 15, 1, 3, 8, 9, 7, 13},
{8, 12, 0, 4, 5, 3, 13, 11, 2, 9, 7, 10, 14, 15, 1, 6},
{2, 13, 9, 14, 6, 7, 12, 15, 8, 0, 3, 1, 4, 11, 10, 5},
}
func m(a, b [N]uint8) (r [N]uint8) {
for j := 0; j < N; j++ {
r[j] = st[a[j]][b[j]]
}
e := rn[0]
for i := 0; i < R*N; i++ {
d := rn[i+1]
r[d] = st[r[d]][r[e]]
e = d
}
for j := 0; j < N; j++ {
r[j] = st[r[j]][b[j]]
}
return
}
type KeyAgreement struct {
P [N]uint8
C [N]uint8
S1 [N]uint8
S2 [N]uint8
init bool
}
func NewKeyAgreement(random io.Reader) (k *KeyAgreement, err error) {
p, err := randomArray(random)
if err != nil {
return nil, err
}
return &KeyAgreement{P: p}, nil
}
func (k *KeyAgreement) InitPhase(random io.Reader) (b []byte, err error) {
k.C, err = randomArray(random)
if err != nil {
return
}
k.S1 = m(k.C, k.P)
k.S2 = m(k.P, k.C)
b = append(b, encode(k.C)...)
b = append(b, encode(k.S1)...)
k.init = true
return
}
func (k *KeyAgreement) SharedSecret(buf []byte) (sec, b []byte, err error) {
if !k.init {
if l := len(buf); l != 64 {
return nil, nil, errors.New("xifrat: bad buffer length: " + strconv.Itoa(l))
}
k.C = decode(buf[:32])
buf = buf[32:]
k.S1 = m(k.C, k.P)
k.S2 = m(k.P, k.C)
k.init = true
}
if l := len(buf); l != KeySize {
return nil, nil, errors.New("xifrat: bad buffer length: " + strconv.Itoa(l))
}
b = encode(k.S1)
sec = encode(m(decode(buf), k.S2))
return
}
func encode(a [N]uint8) (buf []byte) {
buf = make([]byte, len(a)/2)
c := 0
for i := 0; i < len(a); i++ {
b := byte(a[i])
i++
buf[c] = (b << 4) | a[i]
c++
}
return
}
const (
KeySize = 32
SigSize = 96
)
func decode(buf []byte) (a [N]uint8) {
c := 0
for _, b := range buf {
a[c] = uint8(b >> 4)
c++
a[c] = uint8((b << 4) >> 4)
c++
}
return
}
type PublicKey struct {
C [N]uint8
}
type PrivateKey struct {
PublicKey
Q [N]uint8
}
func (priv *PrivateKey) Public() crypto.PublicKey {
return &priv.PublicKey
}
func (priv *PrivateKey) Sign(random io.Reader, digest []byte) (sig []byte, err error) {
if l := len(digest); l != KeySize {
return nil, errors.New("xifrat: bad digest length: " + strconv.Itoa(l))
}
k, err := randomArray(random)
if err != nil {
return
}
hash := decode(digest)
s := m(hash, priv.Q)
ck := m(priv.PublicKey.C, k)
qk := m(priv.Q, k)
sig = append(sig, encode(s)...)
sig = append(sig, encode(ck)...)
sig = append(sig, encode(qk)...)
return
}
func Verify(pub *PublicKey, digest, sig []byte) bool {
if l := len(digest); l != KeySize {
panic("xifrat: bad digest length: " + strconv.Itoa(l))
}
if l := len(sig); l != SigSize {
panic("xifrat: bad signature length: " + strconv.Itoa(l))
}
s := decode(sig[:32])
ck := decode(sig[32:64])
qk := decode(sig[64:96])
hash := decode(digest)
v1 := m(s, ck)
v2 := m(m(hash, pub.C), qk)
return subtle.ConstantTimeCompare(encode(v1), encode(v2)) == 1
}
func randomArray(random io.Reader) (a [N]uint8, err error) {
buf := make([]byte, 32)
_, err = random.Read(buf)
if err != nil {
return
}
a = decode(buf)
return
}
func GenerateKey(random io.Reader) (p *PrivateKey, err error) {
pub, err := randomArray(random)
if err != nil {
return nil, err
}
priv, err := randomArray(random)
if err != nil {
return nil, err
}
return &PrivateKey{PublicKey{pub}, priv}, nil
}