]> Cypherpunks.ru repositories - gogost.git/blob - src/cypherpunks.ru/gogost/gost3410/private.go
VKO 34.10-2001 implementation
[gogost.git] / src / cypherpunks.ru / gogost / gost3410 / private.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2016 Sergey Matveev <stargrave@stargrave.org>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 package gost3410
18
19 import (
20         "errors"
21         "io"
22         "math/big"
23
24         "cypherpunks.ru/gogost/gost28147"
25         "cypherpunks.ru/gogost/gost341194"
26 )
27
28 type PrivateKey struct {
29         c   *Curve
30         ds  int
31         key *big.Int
32 }
33
34 func NewPrivateKey(curve *Curve, ds DigestSize, raw []byte) (*PrivateKey, error) {
35         key := make([]byte, len(raw))
36         copy(key, raw)
37         reverse(key)
38         k := bytes2big(key)
39         if k.Cmp(zero) == 0 {
40                 return nil, errors.New("zero private key")
41         }
42         return &PrivateKey{curve, int(ds), k}, nil
43 }
44
45 func GenPrivateKey(curve *Curve, ds DigestSize, rand io.Reader) (*PrivateKey, error) {
46         raw := make([]byte, int(ds))
47         if _, err := io.ReadFull(rand, raw); err != nil {
48                 return nil, err
49         }
50         return NewPrivateKey(curve, ds, raw)
51 }
52
53 func (pk *PrivateKey) Raw() []byte {
54         raw := pad(pk.key.Bytes(), pk.ds)
55         reverse(raw)
56         return raw
57 }
58
59 func (pk *PrivateKey) PublicKey() (*PublicKey, error) {
60         x, y, err := pk.c.Exp(pk.key, pk.c.Bx, pk.c.By)
61         if err != nil {
62                 return nil, err
63         }
64         return &PublicKey{pk.c, pk.ds, x, y}, nil
65 }
66
67 func (pk *PrivateKey) SignDigest(digest []byte, rand io.Reader) ([]byte, error) {
68         if len(digest) != pk.ds {
69                 return nil, errors.New("Invalid input digest length")
70         }
71         e := bytes2big(digest)
72         e.Mod(e, pk.c.Q)
73         if e.Cmp(zero) == 0 {
74                 e = big.NewInt(1)
75         }
76         kRaw := make([]byte, pk.ds)
77         var err error
78         var k *big.Int
79         var r *big.Int
80         d := big.NewInt(0)
81         s := big.NewInt(0)
82 Retry:
83         if _, err = io.ReadFull(rand, kRaw); err != nil {
84                 return nil, err
85         }
86         k = bytes2big(kRaw)
87         k.Mod(k, pk.c.Q)
88         if k.Cmp(zero) == 0 {
89                 goto Retry
90         }
91         r, _, err = pk.c.Exp(k, pk.c.Bx, pk.c.By)
92         if err != nil {
93                 return nil, err
94         }
95         r.Mod(r, pk.c.Q)
96         if r.Cmp(zero) == 0 {
97                 goto Retry
98         }
99         d.Mul(pk.key, r)
100         k.Mul(k, e)
101         s.Add(d, k)
102         s.Mod(s, pk.c.Q)
103         if s.Cmp(zero) == 0 {
104                 goto Retry
105         }
106         return append(pad(s.Bytes(), pk.ds), pad(r.Bytes(), pk.ds)...), nil
107 }
108
109 // Make Diffie-Hellman computation. Key Encryption Key calculation.
110 // UKM is user keying material, also called VKO-factor, 8-bytes long.
111 // It is based on RFC 4357 VKO GOST 34.10-2001 with little-endian hash
112 // output.
113 func (pk *PrivateKey) KEK(pub *PublicKey, ukm []byte) ([]byte, error) {
114         if len(ukm) != 8 {
115                 return nil, errors.New("UKM must be 8 bytes long")
116         }
117         keyX, keyY, err := pk.c.Exp(pk.key, pub.x, pub.y)
118         if err != nil {
119                 return nil, err
120         }
121         t := make([]byte, DigestSize2001)
122         copy(t[int(DigestSize2001)-len(ukm):], ukm)
123         keyX, keyY, err = pk.c.Exp(bytes2big(t), keyX, keyY)
124         if err != nil {
125                 return nil, err
126         }
127         h := gost341194.New(&gost28147.GostR3411_94_CryptoProParamSet)
128         copy(t, pad(keyX.Bytes(), int(DigestSize2001)))
129         reverse(t)
130         h.Write(t)
131         copy(t, pad(keyY.Bytes(), int(DigestSize2001)))
132         reverse(t)
133         h.Write(t)
134         t = h.Sum(t[:0])
135         reverse(t)
136         return t, nil
137 }