README | 3 ++- src/cypherpunks.ru/gogost/gost3410/2001_test.go | 53 +++++------------------------------------------------ src/cypherpunks.ru/gogost/gost3410/2012_test.go | 10 +++++----- src/cypherpunks.ru/gogost/gost3410/doc.go | 5 ++++- src/cypherpunks.ru/gogost/gost3410/params.go | 6 +++--- src/cypherpunks.ru/gogost/gost3410/private.go | 89 ++++++++++++++++++----------------------------------- src/cypherpunks.ru/gogost/gost3410/public.go | 68 +++++++++++++++++++++++++++--------------------------- src/cypherpunks.ru/gogost/gost3410/ukm.go | 28 ++++++++++++++++++++++++++++ src/cypherpunks.ru/gogost/gost3410/vko.go | 34 ++++++++++++++++++++++++++++++++++ src/cypherpunks.ru/gogost/gost3410/vko2001.go | 40 ++++++++++++++++++++++++++++++++++++++++ src/cypherpunks.ru/gogost/gost3410/vko2001_test.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cypherpunks.ru/gogost/gost3410/vko2012.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/cypherpunks.ru/gogost/gost3410/vko2012_test.go | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++ www.texi | 4 +++- diff --git a/README b/README index 5967e6a4bebe41fec943418d53193a1405fd528b5c4d983579f19624a0530a5b..4fa4ae3a8a16b960f83d84d9cd31ad483705f4630c552695ddcd9620bb5eeae4 100644 --- a/README +++ b/README @@ -10,7 +10,8 @@ * GOST R 34.11-2012 Стрибог (Streebog) hash function (RFC 6986) * GOST R 34.10-2001 (RFC 5832) public key signature function * GOST R 34.10-2012 (RFC 7091) public key signature function * various 34.10 curve parameters included -* VKO GOST R 34.10-2001 Diffie-Hellman function (RFC 4357) +* VKO GOST R 34.10-2001 key agreement function (RFC 4357) +* VKO GOST R 34.10-2012 key agreement function (RFC 7836) * GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (RFC 7801) * GOST R 34.13-2015 padding methods diff --git a/src/cypherpunks.ru/gogost/gost3410/2001_test.go b/src/cypherpunks.ru/gogost/gost3410/2001_test.go index 8e9993c059f87725693a3317bfc92625191aa436e0d8e74015f48cfa5fcc6b54..161c653a25dbe4bc75c083dc5a1b9bd73f9c62b9d16fac28aa7e6f368e2cb8e7 100644 --- a/src/cypherpunks.ru/gogost/gost3410/2001_test.go +++ b/src/cypherpunks.ru/gogost/gost3410/2001_test.go @@ -19,7 +19,6 @@ import ( "bytes" "crypto/rand" - "encoding/hex" "testing" "testing/quick" ) @@ -64,7 +63,7 @@ c, err := NewCurveFromParams(CurveParamsGostR34102001Test) if err != nil { t.FailNow() } - prv, err := NewPrivateKey(c, DigestSize2001, priv) + prv, err := NewPrivateKey(c, Mode2001, priv) if err != nil { t.FailNow() } @@ -97,7 +96,7 @@ c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) f := func(data [31]byte, digest [32]byte) bool { prv, err := NewPrivateKey( c, - DigestSize2001, + Mode2001, append([]byte{0xde}, data[:]...), ) if err != nil { @@ -108,7 +107,7 @@ if err != nil { return false } pubRaw := pub.Raw() - pub, err = NewPublicKey(c, DigestSize2001, pubRaw) + pub, err = NewPublicKey(c, Mode2001, pubRaw) if err != nil { return false } @@ -129,7 +128,7 @@ } func BenchmarkSign2001(b *testing.B) { c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) - prv, err := GenPrivateKey(c, DigestSize2001, rand.Reader) + prv, err := GenPrivateKey(c, Mode2001, rand.Reader) if err != nil { b.FailNow() } @@ -143,7 +142,7 @@ } func BenchmarkVerify2001(b *testing.B) { c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) - prv, err := GenPrivateKey(c, DigestSize2001, rand.Reader) + prv, err := GenPrivateKey(c, Mode2001, rand.Reader) if err != nil { b.FailNow() } @@ -162,45 +161,3 @@ for i := 0; i < b.N; i++ { pub.VerifyDigest(digest, sign) } } - -func TestVKO(t *testing.T) { - c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) - ukm, _ := hex.DecodeString("33a252f825be7251") - prvRaw1, _ := hex.DecodeString("1df129e43dab345b68f6a852f4162dc69f36b2f84717d08755cc5c44150bf928") - prvRaw2, _ := hex.DecodeString("5b9356c6474f913f1e83885ea0edd5df1a43fd9d799d219093241157ac9ed473") - kek, _ := hex.DecodeString("ee4618a0dbb10cb31777b4b86a53d9e7ef6cb3e400101410f0c0f2af46c494a6") - prv1, _ := NewPrivateKey(c, DigestSize2001, prvRaw1) - prv2, _ := NewPrivateKey(c, DigestSize2001, prvRaw2) - pub1, _ := prv1.PublicKey() - pub2, _ := prv2.PublicKey() - kek1, _ := prv1.KEK(pub2, ukm) - kek2, _ := prv2.KEK(pub1, ukm) - if bytes.Compare(kek1, kek2) != 0 { - t.FailNow() - } - if bytes.Compare(kek1, kek) != 0 { - t.FailNow() - } -} - -func TestRandomVKO(t *testing.T) { - c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) - f := func(prvRaw1 [32]byte, prvRaw2 [32]byte, ukm [8]byte) bool { - prv1, err := NewPrivateKey(c, DigestSize2001, prvRaw1[:]) - if err != nil { - return false - } - prv2, err := NewPrivateKey(c, DigestSize2001, prvRaw2[:]) - if err != nil { - return false - } - pub1, _ := prv1.PublicKey() - pub2, _ := prv2.PublicKey() - kek1, _ := prv1.KEK(pub2, ukm[:]) - kek2, _ := prv2.KEK(pub1, ukm[:]) - return bytes.Compare(kek1, kek2) == 0 - } - if err := quick.Check(f, nil); err != nil { - t.Error(err) - } -} diff --git a/src/cypherpunks.ru/gogost/gost3410/2012_test.go b/src/cypherpunks.ru/gogost/gost3410/2012_test.go index a340493967a4ea6080df098f6d6aea02f4e6cece504912cbfff990b3a95ffe15..a7377087b69bbc74e3e1d2fcf941b61d68f4a80db4591b145364acc3945ee24f 100644 --- a/src/cypherpunks.ru/gogost/gost3410/2012_test.go +++ b/src/cypherpunks.ru/gogost/gost3410/2012_test.go @@ -146,7 +146,7 @@ c, err := NewCurve(p, q, a, b, x, y) if err != nil { t.FailNow() } - prv, err := NewPrivateKey(c, DigestSize2012, priv) + prv, err := NewPrivateKey(c, Mode2012, priv) if err != nil { t.FailNow() } @@ -179,7 +179,7 @@ c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) f := func(data [31]byte, digest [64]byte) bool { prv, err := NewPrivateKey( c, - DigestSize2012, + Mode2012, append([]byte{0xde}, data[:]...), ) if err != nil { @@ -190,7 +190,7 @@ if err != nil { return false } pubRaw := pub.Raw() - pub, err = NewPublicKey(c, DigestSize2012, pubRaw) + pub, err = NewPublicKey(c, Mode2012, pubRaw) if err != nil { return false } @@ -211,7 +211,7 @@ } func BenchmarkSign2012(b *testing.B) { c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) - prv, err := GenPrivateKey(c, DigestSize2012, rand.Reader) + prv, err := GenPrivateKey(c, Mode2012, rand.Reader) if err != nil { b.FailNow() } @@ -225,7 +225,7 @@ } func BenchmarkVerify2012(b *testing.B) { c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) - prv, err := GenPrivateKey(c, DigestSize2012, rand.Reader) + prv, err := GenPrivateKey(c, Mode2012, rand.Reader) if err != nil { b.FailNow() } diff --git a/src/cypherpunks.ru/gogost/gost3410/doc.go b/src/cypherpunks.ru/gogost/gost3410/doc.go index a57387212c6db45ff19bef9dab91fa6f4a75a0414dabb2ec14d1cb6e6b6280f7..9ef8000aca3171d52d6c9f88ec3036dfd676ca2144c8d32bc4329b577397b522 100644 --- a/src/cypherpunks.ru/gogost/gost3410/doc.go +++ b/src/cypherpunks.ru/gogost/gost3410/doc.go @@ -1,2 +1,5 @@ -// GOST R 34.10-2001 (RFC 5832) and 34.10-2012 (RFC 7091) signature algorithm. +// GOST R 34.10-2001 (RFC 5832), +// GOST R 34.10-2012 (RFC 7091) signature algorithms and +// VKO GOST R 34.10-2001 (RFC 4357), +// VKO GOST R 34.10-2012 (RFC 7836) key agreement algorithms. package gost3410 diff --git a/src/cypherpunks.ru/gogost/gost3410/params.go b/src/cypherpunks.ru/gogost/gost3410/params.go index 4e637055728478dc80cb8ecc0147765e6eefae2a9fce3e629267b91a09919754..dab4dfd60d4196245deb9ad44c389a5fa44ffad4406926c0fffa5355016b34f6 100644 --- a/src/cypherpunks.ru/gogost/gost3410/params.go +++ b/src/cypherpunks.ru/gogost/gost3410/params.go @@ -16,14 +16,14 @@ // along with this program. If not, see . package gost3410 -type DigestSize uint8 +type Mode int // Curve params: p, q, a, b, bx, by type CurveParams [6][]byte var ( - DigestSize2001 DigestSize = 32 - DigestSize2012 DigestSize = 64 + Mode2001 Mode = Mode(32) + Mode2012 Mode = Mode(64) CurveParamsGostR34102001cc CurveParams = CurveParams([6][]byte{ {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, diff --git a/src/cypherpunks.ru/gogost/gost3410/private.go b/src/cypherpunks.ru/gogost/gost3410/private.go index ee3f841af33e486c5dd2011875099459cb3addaef595e31a1d28f347f9160a3c..b0c9e0ebb460babc52da0ec87a463608500c21ab6254c76433abf727e86009e7 100644 --- a/src/cypherpunks.ru/gogost/gost3410/private.go +++ b/src/cypherpunks.ru/gogost/gost3410/private.go @@ -20,60 +20,57 @@ import ( "errors" "io" "math/big" - - "cypherpunks.ru/gogost/gost28147" - "cypherpunks.ru/gogost/gost341194" ) type PrivateKey struct { - c *Curve - ds int - key *big.Int + c *Curve + mode Mode + key *big.Int } -func NewPrivateKey(curve *Curve, ds DigestSize, raw []byte) (*PrivateKey, error) { - key := make([]byte, len(raw)) +func NewPrivateKey(curve *Curve, mode Mode, raw []byte) (*PrivateKey, error) { + if len(raw) != int(mode) { + errors.New("Invalid private key length") + } + key := make([]byte, int(mode)) copy(key, raw) reverse(key) k := bytes2big(key) if k.Cmp(zero) == 0 { - return nil, errors.New("zero private key") + return nil, errors.New("Zero private key") } - return &PrivateKey{curve, int(ds), k}, nil + return &PrivateKey{curve, mode, k}, nil } -func GenPrivateKey(curve *Curve, ds DigestSize, rand io.Reader) (*PrivateKey, error) { - raw := make([]byte, int(ds)) +func GenPrivateKey(curve *Curve, mode Mode, rand io.Reader) (*PrivateKey, error) { + raw := make([]byte, int(mode)) if _, err := io.ReadFull(rand, raw); err != nil { return nil, err } - return NewPrivateKey(curve, ds, raw) + return NewPrivateKey(curve, mode, raw) } -func (pk *PrivateKey) Raw() []byte { - raw := pad(pk.key.Bytes(), pk.ds) +func (prv *PrivateKey) Raw() []byte { + raw := pad(prv.key.Bytes(), int(prv.mode)) reverse(raw) return raw } -func (pk *PrivateKey) PublicKey() (*PublicKey, error) { - x, y, err := pk.c.Exp(pk.key, pk.c.Bx, pk.c.By) +func (prv *PrivateKey) PublicKey() (*PublicKey, error) { + x, y, err := prv.c.Exp(prv.key, prv.c.Bx, prv.c.By) if err != nil { return nil, err } - return &PublicKey{pk.c, pk.ds, x, y}, nil + return &PublicKey{prv.c, prv.mode, x, y}, nil } -func (pk *PrivateKey) SignDigest(digest []byte, rand io.Reader) ([]byte, error) { - if len(digest) != pk.ds { - return nil, errors.New("Invalid input digest length") - } +func (prv *PrivateKey) SignDigest(digest []byte, rand io.Reader) ([]byte, error) { e := bytes2big(digest) - e.Mod(e, pk.c.Q) + e.Mod(e, prv.c.Q) if e.Cmp(zero) == 0 { e = big.NewInt(1) } - kRaw := make([]byte, pk.ds) + kRaw := make([]byte, int(prv.mode)) var err error var k *big.Int var r *big.Int @@ -84,53 +81,27 @@ if _, err = io.ReadFull(rand, kRaw); err != nil { return nil, err } k = bytes2big(kRaw) - k.Mod(k, pk.c.Q) + k.Mod(k, prv.c.Q) if k.Cmp(zero) == 0 { goto Retry } - r, _, err = pk.c.Exp(k, pk.c.Bx, pk.c.By) + r, _, err = prv.c.Exp(k, prv.c.Bx, prv.c.By) if err != nil { return nil, err } - r.Mod(r, pk.c.Q) + r.Mod(r, prv.c.Q) if r.Cmp(zero) == 0 { goto Retry } - d.Mul(pk.key, r) + d.Mul(prv.key, r) k.Mul(k, e) s.Add(d, k) - s.Mod(s, pk.c.Q) + s.Mod(s, prv.c.Q) if s.Cmp(zero) == 0 { goto Retry } - return append(pad(s.Bytes(), pk.ds), pad(r.Bytes(), pk.ds)...), nil -} - -// Make Diffie-Hellman computation. Key Encryption Key calculation. -// UKM is user keying material, also called VKO-factor, 8-bytes long. -// It is based on RFC 4357 VKO GOST R 34.10-2001 with little-endian hash -// output. -func (pk *PrivateKey) KEK(pub *PublicKey, ukm []byte) ([]byte, error) { - if len(ukm) != 8 { - return nil, errors.New("UKM must be 8 bytes long") - } - keyX, keyY, err := pk.c.Exp(pk.key, pub.x, pub.y) - if err != nil { - return nil, err - } - t := make([]byte, DigestSize2001) - copy(t[int(DigestSize2001)-len(ukm):], ukm) - keyX, keyY, err = pk.c.Exp(bytes2big(t), keyX, keyY) - if err != nil { - return nil, err - } - h := gost341194.New(&gost28147.GostR3411_94_CryptoProParamSet) - copy(t, pad(keyX.Bytes(), int(DigestSize2001))) - reverse(t) - h.Write(t) - copy(t, pad(keyY.Bytes(), int(DigestSize2001))) - reverse(t) - h.Write(t) - t = h.Sum(t[:0]) - return t, nil + return append( + pad(s.Bytes(), int(prv.mode)), + pad(r.Bytes(), int(prv.mode))..., + ), nil } diff --git a/src/cypherpunks.ru/gogost/gost3410/public.go b/src/cypherpunks.ru/gogost/gost3410/public.go index b2a1013479a4c48d5210380892789b4d0220afd78ee648fc4e19f17f310938e7..0743313a7d905a5a69c1ec8432d774858e3f0888d002f5031d527d643ac9f2c7 100644 --- a/src/cypherpunks.ru/gogost/gost3410/public.go +++ b/src/cypherpunks.ru/gogost/gost3410/public.go @@ -22,84 +22,84 @@ "math/big" ) type PublicKey struct { - c *Curve - ds int - x *big.Int - y *big.Int + c *Curve + mode Mode + x *big.Int + y *big.Int } -func NewPublicKey(curve *Curve, ds DigestSize, raw []byte) (*PublicKey, error) { - if len(raw) != 2*int(ds) { +func NewPublicKey(curve *Curve, mode Mode, raw []byte) (*PublicKey, error) { + if len(raw) != 2*int(mode) { return nil, errors.New("Invalid public key length") } - key := make([]byte, 2*int(ds)) + key := make([]byte, 2*int(mode)) copy(key, raw) reverse(key) return &PublicKey{ curve, - int(ds), - bytes2big(key[int(ds) : 2*int(ds)]), - bytes2big(key[:int(ds)]), + mode, + bytes2big(key[int(mode) : 2*int(mode)]), + bytes2big(key[:int(mode)]), }, nil } -func (pk *PublicKey) Raw() []byte { - raw := append(pad(pk.y.Bytes(), pk.ds), pad(pk.x.Bytes(), pk.ds)...) +func (pub *PublicKey) Raw() []byte { + raw := append( + pad(pub.y.Bytes(), int(pub.mode)), + pad(pub.x.Bytes(), int(pub.mode))..., + ) reverse(raw) return raw } -func (pk *PublicKey) VerifyDigest(digest, signature []byte) (bool, error) { - if len(digest) != pk.ds { - return false, errors.New("Invalid input digest length") - } - if len(signature) != 2*pk.ds { +func (pub *PublicKey) VerifyDigest(digest, signature []byte) (bool, error) { + if len(signature) != 2*int(pub.mode) { return false, errors.New("Invalid signature length") } - s := bytes2big(signature[:pk.ds]) - r := bytes2big(signature[pk.ds:]) - if r.Cmp(zero) <= 0 || r.Cmp(pk.c.Q) >= 0 || s.Cmp(zero) <= 0 || s.Cmp(pk.c.Q) >= 0 { + s := bytes2big(signature[:pub.mode]) + r := bytes2big(signature[pub.mode:]) + if r.Cmp(zero) <= 0 || r.Cmp(pub.c.Q) >= 0 || s.Cmp(zero) <= 0 || s.Cmp(pub.c.Q) >= 0 { return false, nil } e := bytes2big(digest) - e.Mod(e, pk.c.Q) + e.Mod(e, pub.c.Q) if e.Cmp(zero) == 0 { e = big.NewInt(1) } v := big.NewInt(0) - v.ModInverse(e, pk.c.Q) + v.ModInverse(e, pub.c.Q) z1 := big.NewInt(0) z2 := big.NewInt(0) z1.Mul(s, v) - z1.Mod(z1, pk.c.Q) + z1.Mod(z1, pub.c.Q) z2.Mul(r, v) - z2.Mod(z2, pk.c.Q) - z2.Sub(pk.c.Q, z2) - p1x, p1y, err := pk.c.Exp(z1, pk.c.Bx, pk.c.By) + z2.Mod(z2, pub.c.Q) + z2.Sub(pub.c.Q, z2) + p1x, p1y, err := pub.c.Exp(z1, pub.c.Bx, pub.c.By) if err != nil { return false, err } - q1x, q1y, err := pk.c.Exp(z2, pk.x, pk.y) + q1x, q1y, err := pub.c.Exp(z2, pub.x, pub.y) if err != nil { return false, err } lm := big.NewInt(0) lm.Sub(q1x, p1x) if lm.Cmp(zero) < 0 { - lm.Add(lm, pk.c.P) + lm.Add(lm, pub.c.P) } - lm.ModInverse(lm, pk.c.P) + lm.ModInverse(lm, pub.c.P) z1.Sub(q1y, p1y) lm.Mul(lm, z1) - lm.Mod(lm, pk.c.P) + lm.Mod(lm, pub.c.P) lm.Mul(lm, lm) - lm.Mod(lm, pk.c.P) + lm.Mod(lm, pub.c.P) lm.Sub(lm, p1x) lm.Sub(lm, q1x) - lm.Mod(lm, pk.c.P) + lm.Mod(lm, pub.c.P) if lm.Cmp(zero) < 0 { - lm.Add(lm, pk.c.P) + lm.Add(lm, pub.c.P) } - lm.Mod(lm, pk.c.Q) + lm.Mod(lm, pub.c.Q) return lm.Cmp(r) == 0, nil } diff --git a/src/cypherpunks.ru/gogost/gost3410/ukm.go b/src/cypherpunks.ru/gogost/gost3410/ukm.go new file mode 100644 index 0000000000000000000000000000000000000000..be6641a7cf7603a8559d20be7b462baaf50945590d75fd14325f450d0abc769f --- /dev/null +++ b/src/cypherpunks.ru/gogost/gost3410/ukm.go @@ -0,0 +1,28 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2016 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost3410 + +import ( + "math/big" +) + +func NewUKM(raw []byte) *big.Int { + t := make([]byte, len(raw)) + copy(t, raw) + reverse(t) + return bytes2big(t) +} diff --git a/src/cypherpunks.ru/gogost/gost3410/vko.go b/src/cypherpunks.ru/gogost/gost3410/vko.go new file mode 100644 index 0000000000000000000000000000000000000000..cc69106508a8fb0238ff3812a3985b15664a946a7a7009389250e2a766017ac1 --- /dev/null +++ b/src/cypherpunks.ru/gogost/gost3410/vko.go @@ -0,0 +1,34 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2016 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost3410 + +import ( + "math/big" +) + +func (prv *PrivateKey) KEK(pub *PublicKey, ukm *big.Int) ([]byte, error) { + keyX, keyY, err := prv.c.Exp(prv.key, pub.x, pub.y) + if err != nil { + return nil, err + } + keyX, keyY, err = prv.c.Exp(ukm, keyX, keyY) + if err != nil { + return nil, err + } + pk := PublicKey{prv.c, prv.mode, keyX, keyY} + return pk.Raw(), nil +} diff --git a/src/cypherpunks.ru/gogost/gost3410/vko2001.go b/src/cypherpunks.ru/gogost/gost3410/vko2001.go new file mode 100644 index 0000000000000000000000000000000000000000..c0943b6faf9d620c87ce7ee83212d92ece45658e2ca2c76f80da51616f295097 --- /dev/null +++ b/src/cypherpunks.ru/gogost/gost3410/vko2001.go @@ -0,0 +1,40 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2016 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost3410 + +import ( + "errors" + "math/big" + + "cypherpunks.ru/gogost/gost28147" + "cypherpunks.ru/gogost/gost341194" +) + +// RFC 4357 VKO GOST R 34.10-2001 key agreement function. +// UKM is user keying material, also called VKO-factor. +func (prv *PrivateKey) KEK2001(pub *PublicKey, ukm *big.Int) ([]byte, error) { + if prv.mode != Mode2001 { + return nil, errors.New("KEK2001 can not be used in Mode2012") + } + key, err := prv.KEK(pub, ukm) + if err != nil { + return nil, err + } + h := gost341194.New(&gost28147.GostR3411_94_CryptoProParamSet) + h.Write(key) + return h.Sum(key[:0]), nil +} diff --git a/src/cypherpunks.ru/gogost/gost3410/vko2001_test.go b/src/cypherpunks.ru/gogost/gost3410/vko2001_test.go new file mode 100644 index 0000000000000000000000000000000000000000..cdfddbb51e7190e53f744280e54016b62474a459c9cfe55e1a5939aff46af89b --- /dev/null +++ b/src/cypherpunks.ru/gogost/gost3410/vko2001_test.go @@ -0,0 +1,68 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2016 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost3410 + +import ( + "bytes" + "encoding/hex" + "testing" + "testing/quick" +) + +func TestVKO2001(t *testing.T) { + c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) + ukmRaw, _ := hex.DecodeString("5172be25f852a233") + ukm := NewUKM(ukmRaw) + prvRaw1, _ := hex.DecodeString("1df129e43dab345b68f6a852f4162dc69f36b2f84717d08755cc5c44150bf928") + prvRaw2, _ := hex.DecodeString("5b9356c6474f913f1e83885ea0edd5df1a43fd9d799d219093241157ac9ed473") + kek, _ := hex.DecodeString("ee4618a0dbb10cb31777b4b86a53d9e7ef6cb3e400101410f0c0f2af46c494a6") + prv1, _ := NewPrivateKey(c, Mode2001, prvRaw1) + prv2, _ := NewPrivateKey(c, Mode2001, prvRaw2) + pub1, _ := prv1.PublicKey() + pub2, _ := prv2.PublicKey() + kek1, _ := prv1.KEK2001(pub2, ukm) + kek2, _ := prv2.KEK2001(pub1, ukm) + if bytes.Compare(kek1, kek2) != 0 { + t.FailNow() + } + if bytes.Compare(kek1, kek) != 0 { + t.FailNow() + } +} + +func TestRandomVKO2001(t *testing.T) { + c, _ := NewCurveFromParams(CurveParamsGostR34102001Test) + f := func(prvRaw1 [32]byte, prvRaw2 [32]byte, ukmRaw [8]byte) bool { + prv1, err := NewPrivateKey(c, Mode2001, prvRaw1[:]) + if err != nil { + return false + } + prv2, err := NewPrivateKey(c, Mode2001, prvRaw2[:]) + if err != nil { + return false + } + pub1, _ := prv1.PublicKey() + pub2, _ := prv2.PublicKey() + ukm := NewUKM(ukmRaw[:]) + kek1, _ := prv1.KEK2001(pub2, ukm) + kek2, _ := prv2.KEK2001(pub1, ukm) + return bytes.Compare(kek1, kek2) == 0 + } + if err := quick.Check(f, nil); err != nil { + t.Error(err) + } +} diff --git a/src/cypherpunks.ru/gogost/gost3410/vko2012.go b/src/cypherpunks.ru/gogost/gost3410/vko2012.go new file mode 100644 index 0000000000000000000000000000000000000000..5e31f4d0d0d122cb74ef43209a927d0026f810c871ed595b8a6d5546f3278fb1 --- /dev/null +++ b/src/cypherpunks.ru/gogost/gost3410/vko2012.go @@ -0,0 +1,55 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2016 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost3410 + +import ( + "errors" + "math/big" + + "cypherpunks.ru/gogost/gost34112012256" + "cypherpunks.ru/gogost/gost34112012512" +) + +// RFC 7836 VKO GOST R 34.10-2012 256-bit key agreement function. +// UKM is user keying material, also called VKO-factor. +func (prv *PrivateKey) KEK2012256(pub *PublicKey, ukm *big.Int) ([]byte, error) { + if prv.mode != Mode2012 { + return nil, errors.New("KEK2012 can not be used in Mode2001") + } + key, err := prv.KEK(pub, ukm) + if err != nil { + return nil, err + } + h := gost34112012256.New() + h.Write(key) + return h.Sum(key[:0]), nil +} + +// RFC 7836 VKO GOST R 34.10-2012 512-bit key agreement function. +// UKM is user keying material, also called VKO-factor. +func (prv *PrivateKey) KEK2012512(pub *PublicKey, ukm *big.Int) ([]byte, error) { + if prv.mode != Mode2012 { + return nil, errors.New("KEK2012 can not be used in Mode2001") + } + key, err := prv.KEK(pub, ukm) + if err != nil { + return nil, err + } + h := gost34112012512.New() + h.Write(key) + return h.Sum(key[:0]), nil +} diff --git a/src/cypherpunks.ru/gogost/gost3410/vko2012_test.go b/src/cypherpunks.ru/gogost/gost3410/vko2012_test.go new file mode 100644 index 0000000000000000000000000000000000000000..1885a4cdebab90a4ddf6bf6b470e3f4d698cc1707fd0a415e517b1521df03401 --- /dev/null +++ b/src/cypherpunks.ru/gogost/gost3410/vko2012_test.go @@ -0,0 +1,116 @@ +// GoGOST -- Pure Go GOST cryptographic functions library +// Copyright (C) 2015-2016 Sergey Matveev +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +package gost3410 + +import ( + "bytes" + "encoding/hex" + "testing" + "testing/quick" +) + +func TestVKO2012256(t *testing.T) { + c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) + ukmRaw, _ := hex.DecodeString("1d80603c8544c727") + ukm := NewUKM(ukmRaw) + prvRawA, _ := hex.DecodeString("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667") + pubRawA, _ := hex.DecodeString("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a") + prvRawB, _ := hex.DecodeString("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db") + pubRawB, _ := hex.DecodeString("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79") + pubA, _ := NewPublicKey(c, Mode2012, pubRawA) + pubB, _ := NewPublicKey(c, Mode2012, pubRawB) + kek, _ := hex.DecodeString("c9a9a77320e2cc559ed72dce6f47e2192ccea95fa648670582c054c0ef36c221") + prvA, _ := NewPrivateKey(c, Mode2012, prvRawA) + prvB, _ := NewPrivateKey(c, Mode2012, prvRawB) + kekA, _ := prvA.KEK2012256(pubB, ukm) + kekB, _ := prvB.KEK2012256(pubA, ukm) + if bytes.Compare(kekA, kekB) != 0 { + t.FailNow() + } + if bytes.Compare(kekA, kek) != 0 { + t.FailNow() + } +} + +func TestRandomVKO2012256(t *testing.T) { + c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) + f := func(prvRaw1 [64]byte, prvRaw2 [64]byte, ukmRaw [8]byte) bool { + prv1, err := NewPrivateKey(c, Mode2012, prvRaw1[:]) + if err != nil { + return false + } + prv2, err := NewPrivateKey(c, Mode2012, prvRaw2[:]) + if err != nil { + return false + } + pub1, _ := prv1.PublicKey() + pub2, _ := prv2.PublicKey() + ukm := NewUKM(ukmRaw[:]) + kek1, _ := prv1.KEK2012256(pub2, ukm) + kek2, _ := prv2.KEK2012256(pub1, ukm) + return bytes.Compare(kek1, kek2) == 0 + } + if err := quick.Check(f, nil); err != nil { + t.Error(err) + } +} + +func TestVKO2012512(t *testing.T) { + c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) + ukmRaw, _ := hex.DecodeString("1d80603c8544c727") + ukm := NewUKM(ukmRaw) + prvRawA, _ := hex.DecodeString("c990ecd972fce84ec4db022778f50fcac726f46708384b8d458304962d7147f8c2db41cef22c90b102f2968404f9b9be6d47c79692d81826b32b8daca43cb667") + pubRawA, _ := hex.DecodeString("aab0eda4abff21208d18799fb9a8556654ba783070eba10cb9abb253ec56dcf5d3ccba6192e464e6e5bcb6dea137792f2431f6c897eb1b3c0cc14327b1adc0a7914613a3074e363aedb204d38d3563971bd8758e878c9db11403721b48002d38461f92472d40ea92f9958c0ffa4c93756401b97f89fdbe0b5e46e4a4631cdb5a") + prvRawB, _ := hex.DecodeString("48c859f7b6f11585887cc05ec6ef1390cfea739b1a18c0d4662293ef63b79e3b8014070b44918590b4b996acfea4edfbbbcccc8c06edd8bf5bda92a51392d0db") + pubRawB, _ := hex.DecodeString("192fe183b9713a077253c72c8735de2ea42a3dbc66ea317838b65fa32523cd5efca974eda7c863f4954d1147f1f2b25c395fce1c129175e876d132e94ed5a65104883b414c9b592ec4dc84826f07d0b6d9006dda176ce48c391e3f97d102e03bb598bf132a228a45f7201aba08fc524a2d77e43a362ab022ad4028f75bde3b79") + pubA, _ := NewPublicKey(c, Mode2012, pubRawA) + pubB, _ := NewPublicKey(c, Mode2012, pubRawB) + kek, _ := hex.DecodeString("79f002a96940ce7bde3259a52e015297adaad84597a0d205b50e3e1719f97bfa7ee1d2661fa9979a5aa235b558a7e6d9f88f982dd63fc35a8ec0dd5e242d3bdf") + prvA, _ := NewPrivateKey(c, Mode2012, prvRawA) + prvB, _ := NewPrivateKey(c, Mode2012, prvRawB) + kekA, _ := prvA.KEK2012512(pubB, ukm) + kekB, _ := prvB.KEK2012512(pubA, ukm) + if bytes.Compare(kekA, kekB) != 0 { + t.FailNow() + } + if bytes.Compare(kekA, kek) != 0 { + t.FailNow() + } +} + +func TestRandomVKO2012512(t *testing.T) { + c, _ := NewCurveFromParams(CurveParamsGostR34102012TC26ParamSetA) + f := func(prvRaw1 [64]byte, prvRaw2 [64]byte, ukmRaw [8]byte) bool { + prv1, err := NewPrivateKey(c, Mode2012, prvRaw1[:]) + if err != nil { + return false + } + prv2, err := NewPrivateKey(c, Mode2012, prvRaw2[:]) + if err != nil { + return false + } + pub1, _ := prv1.PublicKey() + pub2, _ := prv2.PublicKey() + ukm := NewUKM(ukmRaw[:]) + kek1, _ := prv1.KEK2012512(pub2, ukm) + kek2, _ := prv2.KEK2012512(pub1, ukm) + return bytes.Compare(kek1, kek2) == 0 + } + if err := quick.Check(f, nil); err != nil { + t.Error(err) + } +} diff --git a/www.texi b/www.texi index 49d646ce5910fc37b2630112096798a438647088ab618b824ea9ea1f5bef0d1d..92da7fad0481cf3b4a25e309b13a08e4d710203fc4a8732c2b7e0900889987a0 100644 --- a/www.texi +++ b/www.texi @@ -36,8 +36,10 @@ @item GOST R 34.10-2012 (@url{https://tools.ietf.org/html/rfc7091.html, RFC 7091}) public key signature function @item various 34.10 curve parameters included -@item VKO GOST R 34.10-2001 Diffie-Hellman function +@item VKO GOST R 34.10-2001 key agreement function (@url{https://tools.ietf.org/html/rfc4357.html, RFC 4357}) +@item VKO GOST R 34.10-2012 key agreement function + (@url{https://tools.ietf.org/html/rfc7836.html, RFC 7836}) @item GOST R 34.12-2015 128-bit block cipher Кузнечик (Kuznechik) (@url{https://tools.ietf.org/html/rfc7801.html, RFC 7801}) @item GOST R 34.13-2015 padding methods