Home | History | Annotate | Download | only in chacha20poly1305
      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