This change adds a package, chacha20poly1305, which implements the
ChaCha20-Poly1305 AEAD from RFC 7539. This AEAD has several attractive
features:
1. It's naturally constant time. AES-GCM needs either dedicated
hardware or extreme effort to be fast and constant-time, while
this design is easy to make constant-time.
2. It's fast on modern processors: it runs at 1GB/s on my IvyBrige
system.
3. It's seeing significant use in TLS. (A change for crypto/tls is
forthcoming.)
This change merges two CLs:
https://go-review.googlesource.com/#/c/24717
https://go-review.googlesource.com/#/c/26691
I took the amd64-optimised AEAD implementation from the former because
it was significantly faster. But the structure of the change is taken
from the latter.
This version will be checked into x/crypto. This package will then be
vendored into the stdlib so that it can be used from crypto/tls.
Change-Id: I5a60587958b7afeec81ca1091e603a7e8517000b
Reviewed-on: https://go-review.googlesource.com/30728
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
81 lines
2.2 KiB
Go
81 lines
2.2 KiB
Go
// Copyright 2016 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// +build amd64
|
|
|
|
package chacha20poly1305
|
|
|
|
import "encoding/binary"
|
|
|
|
//go:noescape
|
|
func chacha20Poly1305Open(dst []byte, key []uint32, src, ad []byte) bool
|
|
|
|
//go:noescape
|
|
func chacha20Poly1305Seal(dst []byte, key []uint32, src, ad []byte)
|
|
|
|
//go:noescape
|
|
func haveSSSE3() bool
|
|
|
|
var canUseASM bool
|
|
|
|
func init() {
|
|
canUseASM = haveSSSE3()
|
|
}
|
|
|
|
// setupState writes a ChaCha20 input matrix to state. See
|
|
// https://tools.ietf.org/html/rfc7539#section-2.3.
|
|
func setupState(state *[16]uint32, key *[32]byte, nonce []byte) {
|
|
state[0] = 0x61707865
|
|
state[1] = 0x3320646e
|
|
state[2] = 0x79622d32
|
|
state[3] = 0x6b206574
|
|
|
|
state[4] = binary.LittleEndian.Uint32(key[:4])
|
|
state[5] = binary.LittleEndian.Uint32(key[4:8])
|
|
state[6] = binary.LittleEndian.Uint32(key[8:12])
|
|
state[7] = binary.LittleEndian.Uint32(key[12:16])
|
|
state[8] = binary.LittleEndian.Uint32(key[16:20])
|
|
state[9] = binary.LittleEndian.Uint32(key[20:24])
|
|
state[10] = binary.LittleEndian.Uint32(key[24:28])
|
|
state[11] = binary.LittleEndian.Uint32(key[28:32])
|
|
|
|
state[12] = 0
|
|
state[13] = binary.LittleEndian.Uint32(nonce[:4])
|
|
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
|
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
|
}
|
|
|
|
func (c *chacha20poly1305) seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
|
if !canUseASM {
|
|
return c.sealGeneric(dst, nonce, plaintext, additionalData)
|
|
}
|
|
|
|
var state [16]uint32
|
|
setupState(&state, &c.key, nonce)
|
|
|
|
ret, out := sliceForAppend(dst, len(plaintext)+16)
|
|
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
|
return ret
|
|
}
|
|
|
|
func (c *chacha20poly1305) open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
|
if !canUseASM {
|
|
return c.openGeneric(dst, nonce, ciphertext, additionalData)
|
|
}
|
|
|
|
var state [16]uint32
|
|
setupState(&state, &c.key, nonce)
|
|
|
|
ciphertext = ciphertext[:len(ciphertext)-16]
|
|
ret, out := sliceForAppend(dst, len(ciphertext))
|
|
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
|
for i := range out {
|
|
out[i] = 0
|
|
}
|
|
return nil, errOpen
|
|
}
|
|
|
|
return ret, nil
|
|
}
|