blob: 47550332126e28fa61dbc2ab2295bba23154fee9 [file] [log] [blame]
Adam Langley594708b2016-10-10 14:34:47 -07001// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Alex Vaghin9477e0b2016-10-31 16:37:30 +01005// +build go1.7,amd64,!gccgo,!appengine
Adam Langley594708b2016-10-10 14:34:47 -07006
7package chacha20poly1305
8
9import "encoding/binary"
10
11//go:noescape
12func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
13
14//go:noescape
15func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
16
17//go:noescape
18func haveSSSE3() bool
19
20var canUseASM bool
21
22func init() {
23 canUseASM = haveSSSE3()
24}
25
26// setupState writes a ChaCha20 input matrix to state. See
27// https://tools.ietf.org/html/rfc7539#section-2.3.
28func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
29 state[0] = 0x61707865
30 state[1] = 0x3320646e
31 state[2] = 0x79622d32
32 state[3] = 0x6b206574
33
34 state[4] = binary.LittleEndian.Uint32(key[:4])
35 state[5] = binary.LittleEndian.Uint32(key[4:8])
36 state[6] = binary.LittleEndian.Uint32(key[8:12])
37 state[7] = binary.LittleEndian.Uint32(key[12:16])
38 state[8] = binary.LittleEndian.Uint32(key[16:20])
39 state[9] = binary.LittleEndian.Uint32(key[20:24])
40 state[10] = binary.LittleEndian.Uint32(key[24:28])
41 state[11] = binary.LittleEndian.Uint32(key[28:32])
42
43 state[12] = 0
44 state[13] = binary.LittleEndian.Uint32(nonce[:4])
45 state[14] = binary.LittleEndian.Uint32(nonce[4:8])
46 state[15] = binary.LittleEndian.Uint32(nonce[8:12])
47}
48
49func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
50 if !canUseASM {
51 return c.sealGeneric(dst, nonce, plaintext, additionalData)
52 }
53
54 var state [16]uint32
55 setupState(&state, &c.key, nonce)
56
57 ret, out := sliceForAppend(dst, len(plaintext)+16)
58 chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
59 return ret
60}
61
62func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
63 if !canUseASM {
64 return c.openGeneric(dst, nonce, ciphertext, additionalData)
65 }
66
67 var state [16]uint32
68 setupState(&state, &c.key, nonce)
69
70 ciphertext = ciphertext[:len(ciphertext)-16]
71 ret, out := sliceForAppend(dst, len(ciphertext))
72 if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
73 for i := range out {
74 out[i] = 0
75 }
76 return nil, errOpen
77 }
78
79 return ret, nil
80}