]> Cypherpunks.ru repositories - gogost.git/blob - src/cypherpunks.ru/gogost/gost28147/cipher.go
Simplify keys and IVs arguments passing: use slices instead of arrays
[gogost.git] / src / cypherpunks.ru / gogost / gost28147 / cipher.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, 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 // GOST 28147-89 block cipher with ECB, CFB, CTR, MAC modes of operation.
18 // RFC 5830.
19 package gost28147
20
21 const (
22         BlockSize = 8
23         KeySize   = 32
24 )
25
26 // All 28147 operations are going with two 32-bit halves of the whole
27 // block. nv is representation of that one half.
28 type nv uint32
29
30 // Cyclic 11-bit shift.
31 func (n nv) shift11() nv {
32         return ((n << 11) & (1<<32 - 1)) | ((n >> (32 - 11)) & (1<<32 - 1))
33 }
34
35 // Seq contains iteration numbers used in the encryption function
36 // itself. For example 28147 encryption and decryption process differs
37 // only with this sequence.
38 type Seq []uint8
39
40 var (
41         SeqEncrypt = Seq([]uint8{
42                 0, 1, 2, 3, 4, 5, 6, 7,
43                 0, 1, 2, 3, 4, 5, 6, 7,
44                 0, 1, 2, 3, 4, 5, 6, 7,
45                 7, 6, 5, 4, 3, 2, 1, 0,
46         })
47         SeqDecrypt = Seq([]uint8{
48                 0, 1, 2, 3, 4, 5, 6, 7,
49                 7, 6, 5, 4, 3, 2, 1, 0,
50                 7, 6, 5, 4, 3, 2, 1, 0,
51                 7, 6, 5, 4, 3, 2, 1, 0,
52         })
53 )
54
55 type Cipher struct {
56         key  [KeySize]byte
57         sbox *Sbox
58         x    [8]nv
59 }
60
61 func NewCipher(key []byte, sbox *Sbox) *Cipher {
62         if len(key) != KeySize {
63                 panic("invalid key size")
64         }
65         c := Cipher{sbox: sbox}
66         copy(c.key[:], key)
67         c.x = [8]nv{
68                 nv(key[0]) | nv(key[1])<<8 | nv(key[2])<<16 | nv(key[3])<<24,
69                 nv(key[4]) | nv(key[5])<<8 | nv(key[6])<<16 | nv(key[7])<<24,
70                 nv(key[8]) | nv(key[9])<<8 | nv(key[10])<<16 | nv(key[11])<<24,
71                 nv(key[12]) | nv(key[13])<<8 | nv(key[14])<<16 | nv(key[15])<<24,
72                 nv(key[16]) | nv(key[17])<<8 | nv(key[18])<<16 | nv(key[19])<<24,
73                 nv(key[20]) | nv(key[21])<<8 | nv(key[22])<<16 | nv(key[23])<<24,
74                 nv(key[24]) | nv(key[25])<<8 | nv(key[26])<<16 | nv(key[27])<<24,
75                 nv(key[28]) | nv(key[29])<<8 | nv(key[30])<<16 | nv(key[31])<<24,
76         }
77         return &c
78 }
79
80 func (c *Cipher) BlockSize() int {
81         return BlockSize
82 }
83
84 // Convert binary byte block to two 32-bit internal integers.
85 func block2nvs(b []byte) (n1, n2 nv) {
86         n1 = nv(b[0]) | nv(b[1])<<8 | nv(b[2])<<16 | nv(b[3])<<24
87         n2 = nv(b[4]) | nv(b[5])<<8 | nv(b[6])<<16 | nv(b[7])<<24
88         return
89 }
90
91 // Convert two 32-bit internal integers to binary byte block.
92 func nvs2block(n1, n2 nv, b []byte) {
93         b[0] = byte((n2 >> 0) & 255)
94         b[1] = byte((n2 >> 8) & 255)
95         b[2] = byte((n2 >> 16) & 255)
96         b[3] = byte((n2 >> 24) & 255)
97         b[4] = byte((n1 >> 0) & 255)
98         b[5] = byte((n1 >> 8) & 255)
99         b[6] = byte((n1 >> 16) & 255)
100         b[7] = byte((n1 >> 24) & 255)
101 }
102
103 func (c *Cipher) xcrypt(seq Seq, n1, n2 nv) (nv, nv) {
104         for _, i := range seq {
105                 n1, n2 = c.sbox.k(n1+c.x[i]).shift11()^n2, n1
106         }
107         return n1, n2
108 }
109
110 // Encrypt single block.
111 // If provided slices are shorter than the block size, then it will panic.
112 func (c *Cipher) Encrypt(dst, src []byte) {
113         n1, n2 := block2nvs(src)
114         n1, n2 = c.xcrypt(SeqEncrypt, n1, n2)
115         nvs2block(n1, n2, dst)
116 }
117
118 // Decrypt single block.
119 // If provided slices are shorter than the block size, then it will panic.
120 func (c *Cipher) Decrypt(dst, src []byte) {
121         n1, n2 := block2nvs(src)
122         n1, n2 = c.xcrypt(SeqDecrypt, n1, n2)
123         nvs2block(n1, n2, dst)
124 }