* 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
import (
"bytes"
"crypto/rand"
- "encoding/hex"
"testing"
"testing/quick"
)
if err != nil {
t.FailNow()
}
- prv, err := NewPrivateKey(c, DigestSize2001, priv)
+ prv, err := NewPrivateKey(c, Mode2001, priv)
if err != nil {
t.FailNow()
}
f := func(data [31]byte, digest [32]byte) bool {
prv, err := NewPrivateKey(
c,
- DigestSize2001,
+ Mode2001,
append([]byte{0xde}, data[:]...),
)
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
}
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()
}
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()
}
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)
- }
-}
if err != nil {
t.FailNow()
}
- prv, err := NewPrivateKey(c, DigestSize2012, priv)
+ prv, err := NewPrivateKey(c, Mode2012, priv)
if err != nil {
t.FailNow()
}
f := func(data [31]byte, digest [64]byte) bool {
prv, err := NewPrivateKey(
c,
- DigestSize2012,
+ Mode2012,
append([]byte{0xde}, data[:]...),
)
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
}
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()
}
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()
}
-// 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
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,
"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
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
}
)
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
}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+package gost3410
+
+import (
+ "math/big"
+)
+
+func NewUKM(raw []byte) *big.Int {
+ t := make([]byte, len(raw))
+ copy(t, raw)
+ reverse(t)
+ return bytes2big(t)
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+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
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+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
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+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)
+ }
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+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
+}
--- /dev/null
+// GoGOST -- Pure Go GOST cryptographic functions library
+// Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
+//
+// 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 <http://www.gnu.org/licenses/>.
+
+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)
+ }
+}
(@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