]> Cypherpunks.ru repositories - gogost.git/blob - gost28147/wrap.go
28147-89 and CryptoPro key wrapping support
[gogost.git] / gost28147 / wrap.go
1 // GoGOST -- Pure Go GOST cryptographic functions library
2 // Copyright (C) 2015-2023 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 package gost28147
17
18 import (
19         "bytes"
20         "crypto/subtle"
21         "encoding/binary"
22 )
23
24 func WrapGost(ukm, kek, cek []byte) []byte {
25         c := NewCipher(kek, &SboxIdGost2814789CryptoProAParamSet)
26         mac, err := c.NewMAC(4, ukm)
27         if err != nil {
28                 panic(err)
29         }
30         _, err = mac.Write(cek)
31         if err != nil {
32                 panic(err)
33         }
34         cekMac := mac.Sum(nil)
35         cekEnc := make([]byte, 32)
36         c.NewECBEncrypter().CryptBlocks(cekEnc, cek)
37         return bytes.Join([][]byte{ukm, cekEnc, cekMac}, nil)
38 }
39
40 func UnwrapGost(kek, data []byte) []byte {
41         ukm, data := data[:8], data[8:]
42         cekEnc, cekMac := data[:KeySize], data[KeySize:]
43         c := NewCipher(kek, &SboxIdGost2814789CryptoProAParamSet)
44         cek := make([]byte, 32)
45         c.NewECBDecrypter().CryptBlocks(cek, cekEnc)
46         mac, err := c.NewMAC(4, ukm)
47         if err != nil {
48                 panic(err)
49         }
50         _, err = mac.Write(cek)
51         if err != nil {
52                 panic(err)
53         }
54         if subtle.ConstantTimeCompare(mac.Sum(nil), cekMac) != 1 {
55                 return nil
56         }
57         return cek
58 }
59
60 func DiversifyCryptoPro(kek, ukm []byte) []byte {
61         out := kek
62         for i := 0; i < 8; i++ {
63                 var s1, s2 uint64
64                 for j := 0; j < 8; j++ {
65                         k := binary.LittleEndian.Uint32(out[j*4 : j*4+4])
66                         if (ukm[i]>>j)&1 > 0 {
67                                 s1 += uint64(k)
68                         } else {
69                                 s2 += uint64(k)
70                         }
71                 }
72                 iv := make([]byte, 8)
73                 binary.LittleEndian.PutUint32(iv[:4], uint32(s1%(1<<32)))
74                 binary.LittleEndian.PutUint32(iv[4:], uint32(s2%(1<<32)))
75                 c := NewCipher(out, &SboxIdGost2814789CryptoProAParamSet)
76                 c.NewCFBEncrypter(iv).XORKeyStream(out, out)
77         }
78         return out
79 }
80
81 func UnwrapCryptoPro(kek, data []byte) []byte {
82         return UnwrapGost(DiversifyCryptoPro(kek, data[:8]), data)
83 }