1
2
3
4
5
6
7
8
9
10
11
12 package ascon
13
14 import (
15 "crypto/subtle"
16 "encoding/binary"
17 "errors"
18 "math/bits"
19 )
20
21 const (
22 KeySize = 16
23 KeySize80pq = 20
24 NonceSize = 16
25 TagSize = 16
26 )
27
28 type Mode int
29
30
31 func (m Mode) KeySize() int {
32 switch m {
33 case Ascon128, Ascon128a, Ascon80pq:
34 v := int(m) >> 2
35 return KeySize&^v | KeySize80pq&v
36 default:
37 panic(ErrMode)
38 }
39 }
40
41 func (m Mode) String() string {
42 switch m {
43 case Ascon128:
44 return "Ascon128"
45 case Ascon128a:
46 return "Ascon128a"
47 case Ascon80pq:
48 return "Ascon80pq"
49 default:
50 panic(ErrMode)
51 }
52 }
53
54 const (
55 Ascon128 Mode = 1
56 Ascon128a Mode = 2
57 Ascon80pq Mode = -1
58 )
59
60 const permA = 12
61
62 type Cipher struct {
63 key [3]uint64
64 mode Mode
65 }
66
67
68
69
70 func New(key []byte, m Mode) (*Cipher, error) {
71 if (m == Ascon128 || m == Ascon128a) && len(key) != KeySize {
72 return nil, ErrKeySize
73 }
74 if m == Ascon80pq && len(key) != KeySize80pq {
75 return nil, ErrKeySize
76 }
77 if !(m == Ascon128 || m == Ascon128a || m == Ascon80pq) {
78 return nil, ErrMode
79 }
80 c := new(Cipher)
81 c.mode = m
82 if m == Ascon80pq {
83 c.key[0] = uint64(binary.BigEndian.Uint32(key[0:4]))
84 c.key[1] = binary.BigEndian.Uint64(key[4:12])
85 c.key[2] = binary.BigEndian.Uint64(key[12:20])
86 } else {
87 c.key[0] = 0
88 c.key[1] = binary.BigEndian.Uint64(key[0:8])
89 c.key[2] = binary.BigEndian.Uint64(key[8:16])
90 }
91
92 return c, nil
93 }
94
95
96
97 func (a *Cipher) NonceSize() int { return NonceSize }
98
99
100
101 func (a *Cipher) Overhead() int { return TagSize }
102
103
104
105
106
107
108
109
110 func (a *Cipher) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
111 if len(nonce) != NonceSize {
112 panic(ErrNonceSize)
113 }
114
115 ptLen := len(plaintext)
116 ret, out := sliceForAppend(dst, ptLen+TagSize)
117 ciphertext, tag := out[:ptLen], out[ptLen:]
118
119 var s [5]uint64
120 a.initialize(nonce, &s)
121 a.assocData(additionalData, &s)
122 a.procText(plaintext, ciphertext, true, &s)
123 a.finalize(tag, &s)
124
125 return ret
126 }
127
128
129
130
131
132
133
134
135
136
137
138
139 func (a *Cipher) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
140 if len(nonce) != NonceSize {
141 panic(ErrNonceSize)
142 }
143 if len(ciphertext) < TagSize {
144 return nil, ErrDecryption
145 }
146
147 ptLen := len(ciphertext) - TagSize
148 ret, out := sliceForAppend(dst, ptLen)
149 plaintext := out[:ptLen]
150 ciphertext, tag0 := ciphertext[:ptLen], ciphertext[ptLen:]
151 tag1 := (&[TagSize]byte{})[:]
152
153 var s [5]uint64
154 a.initialize(nonce, &s)
155 a.assocData(additionalData, &s)
156 a.procText(ciphertext, plaintext, false, &s)
157 a.finalize(tag1, &s)
158
159 if subtle.ConstantTimeCompare(tag0, tag1) == 0 {
160 return nil, ErrDecryption
161 }
162
163 return ret, nil
164 }
165
166 func abs(x int) int { m := uint(x >> (bits.UintSize - 1)); return int((uint(x) + m) ^ m) }
167
168
169 func (a *Cipher) blockSize() int { return abs(int(a.mode)) << 3 }
170
171
172 func (a *Cipher) permB() int { return (abs(int(a.mode)) + 2) << 1 }
173
174 func (a *Cipher) initialize(nonce []byte, s *[5]uint64) {
175 bcs := uint64(a.blockSize())
176 pB := uint64(a.permB())
177 kS := uint64(a.mode.KeySize())
178
179 s[0] = ((kS * 8) << 56) | ((bcs * 8) << 48) | (permA << 40) | (pB << 32) | a.key[0]
180 s[1] = a.key[1]
181 s[2] = a.key[2]
182 s[3] = binary.BigEndian.Uint64(nonce[0:8])
183 s[4] = binary.BigEndian.Uint64(nonce[8:16])
184
185 perm(permA, s)
186
187 s[2] ^= a.key[0]
188 s[3] ^= a.key[1]
189 s[4] ^= a.key[2]
190 }
191
192 func (a *Cipher) assocData(add []byte, s *[5]uint64) {
193 bcs := a.blockSize()
194 pB := a.permB()
195 if len(add) > 0 {
196 for ; len(add) >= bcs; add = add[bcs:] {
197 for i := 0; i < bcs; i += 8 {
198 s[i/8] ^= binary.BigEndian.Uint64(add[i : i+8])
199 }
200 perm(pB, s)
201 }
202 for i := 0; i < len(add); i++ {
203 s[i/8] ^= uint64(add[i]) << (56 - 8*(i%8))
204 }
205 s[len(add)/8] ^= uint64(0x80) << (56 - 8*(len(add)%8))
206 perm(pB, s)
207 }
208 s[4] ^= 0x01
209 }
210
211 func (a *Cipher) procText(in, out []byte, enc bool, s *[5]uint64) {
212 bcs := a.blockSize()
213 pB := a.permB()
214 mask := uint64(0)
215 if enc {
216 mask -= 1
217 }
218
219 for ; len(in) >= bcs; in, out = in[bcs:], out[bcs:] {
220 for i := 0; i < bcs; i += 8 {
221 inW := binary.BigEndian.Uint64(in[i : i+8])
222 outW := s[i/8] ^ inW
223 binary.BigEndian.PutUint64(out[i:i+8], outW)
224
225 s[i/8] = (inW &^ mask) | (outW & mask)
226 }
227 perm(pB, s)
228 }
229
230 mask8 := byte(mask & 0xFF)
231 for i := 0; i < len(in); i++ {
232 off := 56 - (8 * (i % 8))
233 si := byte((s[i/8] >> off) & 0xFF)
234 inB := in[i]
235 outB := si ^ inB
236 out[i] = outB
237 ss := inB&^mask8 | outB&mask8
238 s[i/8] = (s[i/8] &^ (0xFF << off)) | uint64(ss)<<off
239 }
240 s[len(in)/8] ^= uint64(0x80) << (56 - 8*(len(in)%8))
241 }
242
243 func (a *Cipher) finalize(tag []byte, s *[5]uint64) {
244 bcs := a.blockSize()
245 if a.mode == Ascon80pq {
246 s[bcs/8+0] ^= a.key[0]<<32 | a.key[1]>>32
247 s[bcs/8+1] ^= a.key[1]<<32 | a.key[2]>>32
248 s[bcs/8+2] ^= a.key[2] << 32
249 } else {
250 s[bcs/8+0] ^= a.key[1]
251 s[bcs/8+1] ^= a.key[2]
252 }
253
254 perm(permA, s)
255 binary.BigEndian.PutUint64(tag[0:8], s[3]^a.key[1])
256 binary.BigEndian.PutUint64(tag[8:16], s[4]^a.key[2])
257 }
258
259 func perm(n int, s *[5]uint64) {
260 x0, x1, x2, x3, x4 := s[0], s[1], s[2], s[3], s[4]
261 for i := permA - n; i < permA; i++ {
262
263 x2 ^= uint64((0xF-i)<<4 | i)
264
265
266
267
268 x0 ^= x4
269 x4 ^= x3
270 x2 ^= x1
271 t0 := x0 & (^x4)
272 t1 := x2 & (^x1)
273 x0 ^= t1
274 t1 = x4 & (^x3)
275 x2 ^= t1
276 t1 = x1 & (^x0)
277 x4 ^= t1
278 t1 = x3 & (^x2)
279 x1 ^= t1
280 x3 ^= t0
281 x1 ^= x0
282 x3 ^= x2
283 x0 ^= x4
284 x2 = ^x2
285
286
287 x0 ^= bits.RotateLeft64(x0, -19) ^ bits.RotateLeft64(x0, -28)
288 x1 ^= bits.RotateLeft64(x1, -61) ^ bits.RotateLeft64(x1, -39)
289 x2 ^= bits.RotateLeft64(x2, -1) ^ bits.RotateLeft64(x2, -6)
290 x3 ^= bits.RotateLeft64(x3, -10) ^ bits.RotateLeft64(x3, -17)
291 x4 ^= bits.RotateLeft64(x4, -7) ^ bits.RotateLeft64(x4, -41)
292 }
293 s[0], s[1], s[2], s[3], s[4] = x0, x1, x2, x3, x4
294 }
295
296
297
298
299
300 func sliceForAppend(in []byte, n int) (head, tail []byte) {
301 if total := len(in) + n; cap(in) >= total {
302 head = in[:total]
303 } else {
304 head = make([]byte, total)
305 copy(head, in)
306 }
307 tail = head[len(in):]
308 return
309 }
310
311 var (
312 ErrKeySize = errors.New("ascon: bad key size")
313 ErrNonceSize = errors.New("ascon: bad nonce size")
314 ErrDecryption = errors.New("ascon: invalid ciphertext")
315 ErrMode = errors.New("ascon: invalid cipher mode")
316 )
317
View as plain text