]> Cypherpunks.ru repositories - gogost.git/blob - gost341194/hash.go
e386ddd207e0ef1637e9faffff7db6976f991488
[gogost.git] / gost341194 / hash.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2019 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, version 3 of the License.
7 //
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
15
16 // GOST R 34.11-94 hash function.
17 // RFC 5831.
18 package gost341194
19
20 import (
21         "encoding/binary"
22         "math/big"
23
24         "go.cypherpunks.ru/gogost/v4/gost28147"
25 )
26
27 const (
28         BlockSize = 32
29         Size      = 32
30 )
31
32 var (
33         SboxDefault *gost28147.Sbox = &gost28147.SboxIdGostR341194TestParamSet
34
35         c2 [BlockSize]byte = [BlockSize]byte{
36                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
37                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
38                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
39                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40         }
41         c3 [BlockSize]byte = [BlockSize]byte{
42                 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff,
43                 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00,
44                 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff,
45                 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
46         }
47         c4 [BlockSize]byte = [BlockSize]byte{
48                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
50                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52         }
53
54         big256 *big.Int = big.NewInt(0).SetBit(big.NewInt(0), 256, 1)
55 )
56
57 type Hash struct {
58         sbox *gost28147.Sbox
59         size uint64
60         hsh  [BlockSize]byte
61         chk  *big.Int
62         buf  []byte
63         tmp  [BlockSize]byte
64 }
65
66 func New(sbox *gost28147.Sbox) *Hash {
67         h := Hash{sbox: sbox}
68         h.Reset()
69         return &h
70 }
71
72 func (h *Hash) Reset() {
73         h.size = 0
74         h.hsh = [BlockSize]byte{
75                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
76                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79         }
80         h.chk = big.NewInt(0)
81         h.buf = h.buf[:0]
82 }
83
84 func (h *Hash) BlockSize() int {
85         return BlockSize
86 }
87
88 func (h *Hash) Size() int {
89         return BlockSize
90 }
91
92 func fA(in *[BlockSize]byte) *[BlockSize]byte {
93         out := new([BlockSize]byte)
94         out[0] = in[16+0] ^ in[24+0]
95         out[1] = in[16+1] ^ in[24+1]
96         out[2] = in[16+2] ^ in[24+2]
97         out[3] = in[16+3] ^ in[24+3]
98         out[4] = in[16+4] ^ in[24+4]
99         out[5] = in[16+5] ^ in[24+5]
100         out[6] = in[16+6] ^ in[24+6]
101         out[7] = in[16+7] ^ in[24+7]
102         copy(out[8:], in[0:24])
103         return out
104 }
105
106 func fP(in *[BlockSize]byte) *[BlockSize]byte {
107         return &[BlockSize]byte{
108                 in[0], in[8], in[16], in[24], in[1], in[9], in[17],
109                 in[25], in[2], in[10], in[18], in[26], in[3],
110                 in[11], in[19], in[27], in[4], in[12], in[20],
111                 in[28], in[5], in[13], in[21], in[29], in[6],
112                 in[14], in[22], in[30], in[7], in[15], in[23], in[31],
113         }
114 }
115
116 func fChi(in *[BlockSize]byte) *[BlockSize]byte {
117         out := new([BlockSize]byte)
118         out[0] = in[32-2] ^ in[32-4] ^ in[32-6] ^ in[32-8] ^ in[32-32] ^ in[32-26]
119         out[1] = in[32-1] ^ in[32-3] ^ in[32-5] ^ in[32-7] ^ in[32-31] ^ in[32-25]
120         copy(out[2:32], in[0:30])
121         return out
122 }
123
124 func blockReverse(dst, src []byte) {
125         for i, j := 0, BlockSize-1; i < j; i, j = i+1, j-1 {
126                 dst[i], dst[j] = src[j], src[i]
127         }
128 }
129
130 func blockXor(dst, a, b *[BlockSize]byte) {
131         for i := 0; i < BlockSize; i++ {
132                 dst[i] = a[i] ^ b[i]
133         }
134         return
135 }
136
137 func (h *Hash) step(hin, m [BlockSize]byte) [BlockSize]byte {
138         out := new([BlockSize]byte)
139         u := new([BlockSize]byte)
140         v := new([BlockSize]byte)
141         k := new([BlockSize]byte)
142         (*u) = hin
143         (*v) = m
144         blockXor(k, u, v)
145         k = fP(k)
146         blockReverse(k[:], k[:])
147         c := gost28147.NewCipher(k[:], h.sbox)
148         s := make([]byte, gost28147.BlockSize)
149         c.Encrypt(s, []byte{
150                 hin[31], hin[30], hin[29], hin[28], hin[27], hin[26], hin[25], hin[24],
151         })
152         out[31] = s[0]
153         out[30] = s[1]
154         out[29] = s[2]
155         out[28] = s[3]
156         out[27] = s[4]
157         out[26] = s[5]
158         out[25] = s[6]
159         out[24] = s[7]
160
161         blockXor(u, fA(u), &c2)
162         v = fA(fA(v))
163         blockXor(k, u, v)
164         k = fP(k)
165         blockReverse(k[:], k[:])
166         c = gost28147.NewCipher(k[:], h.sbox)
167         c.Encrypt(s, []byte{
168                 hin[23], hin[22], hin[21], hin[20], hin[19], hin[18], hin[17], hin[16],
169         })
170         out[23] = s[0]
171         out[22] = s[1]
172         out[21] = s[2]
173         out[20] = s[3]
174         out[19] = s[4]
175         out[18] = s[5]
176         out[17] = s[6]
177         out[16] = s[7]
178
179         blockXor(u, fA(u), &c3)
180         v = fA(fA(v))
181         blockXor(k, u, v)
182         k = fP(k)
183         blockReverse(k[:], k[:])
184         c = gost28147.NewCipher(k[:], h.sbox)
185         c.Encrypt(s, []byte{
186                 hin[15], hin[14], hin[13], hin[12], hin[11], hin[10], hin[9], hin[8],
187         })
188         out[15] = s[0]
189         out[14] = s[1]
190         out[13] = s[2]
191         out[12] = s[3]
192         out[11] = s[4]
193         out[10] = s[5]
194         out[9] = s[6]
195         out[8] = s[7]
196
197         blockXor(u, fA(u), &c4)
198         v = fA(fA(v))
199         blockXor(k, u, v)
200         k = fP(k)
201         blockReverse(k[:], k[:])
202         c = gost28147.NewCipher(k[:], h.sbox)
203         c.Encrypt(s, []byte{
204                 hin[7], hin[6], hin[5], hin[4], hin[3], hin[2], hin[1], hin[0],
205         })
206         out[7] = s[0]
207         out[6] = s[1]
208         out[5] = s[2]
209         out[4] = s[3]
210         out[3] = s[4]
211         out[2] = s[5]
212         out[1] = s[6]
213         out[0] = s[7]
214
215         for i := 0; i < 12; i++ {
216                 out = fChi(out)
217         }
218         blockXor(out, out, &m)
219         out = fChi(out)
220         blockXor(out, out, &hin)
221         for i := 0; i < 61; i++ {
222                 out = fChi(out)
223         }
224         return *out
225 }
226
227 func (h *Hash) chkAdd(data []byte) *big.Int {
228         i := big.NewInt(0).SetBytes(data)
229         i.Add(i, h.chk)
230         if i.Cmp(big256) != -1 {
231                 i.Sub(i, big256)
232         }
233         return i
234 }
235
236 func (h *Hash) Write(data []byte) (int, error) {
237         h.buf = append(h.buf, data...)
238         for len(h.buf) >= BlockSize {
239                 h.size += BlockSize * 8
240                 blockReverse(h.tmp[:], h.buf[:BlockSize])
241                 h.chk = h.chkAdd(h.tmp[:])
242                 h.buf = h.buf[BlockSize:]
243                 h.hsh = h.step(h.hsh, h.tmp)
244         }
245         return len(data), nil
246 }
247
248 func (h *Hash) Sum(in []byte) []byte {
249         size := h.size
250         chk := h.chk
251         hsh := h.hsh
252         block := new([BlockSize]byte)
253         if len(h.buf) != 0 {
254                 size += uint64(len(h.buf)) * 8
255                 copy(block[:], h.buf)
256                 blockReverse(block[:], block[:])
257                 chk = h.chkAdd(block[:])
258                 hsh = h.step(hsh, *block)
259                 block = new([BlockSize]byte)
260         }
261         binary.BigEndian.PutUint64(block[24:], size)
262         hsh = h.step(hsh, *block)
263         block = new([BlockSize]byte)
264         chkBytes := chk.Bytes()
265         copy(block[BlockSize-len(chkBytes):], chkBytes)
266         hsh = h.step(hsh, *block)
267         blockReverse(hsh[:], hsh[:])
268         return append(in, hsh[:]...)
269 }