1 // 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 5 // +build go1.7,amd64,!gccgo,!appengine 6 7 package chacha20poly1305 8 9 import "encoding/binary" 10 11 //go:noescape 12 func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool 13 14 //go:noescape 15 func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte) 16 17 //go:noescape 18 func haveSSSE3() bool 19 20 var canUseASM bool 21 22 func 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. 28 func 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 49 func (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 62 func (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 } 81