Update
This commit is contained in:
1 parent
3530afb854
commit
6903fcff27
2146 files changed
+112256
-190703
No files matched your search
Generated
Vendored
+162
@@ -0,0 +1,162 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
//go:build amd64 && gc && !purego
|
||||
|
||||
/*
|
||||
Package chacha20poly1305 provides a ChaCha20-Poly1305 AEAD backed by the SSE assembly kernel golang.org/x/crypto deleted in commit 7ee5970 ("chacha20poly1305: drop pre-AVX assembly impl", v0.52.0). It is used on amd64 CPUs with SSSE3 that cannot use x/crypto's AVX2 kernel.
|
||||
*/
|
||||
package chacha20poly1305
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
|
||||
xchacha20poly1305 "golang.org/x/crypto/chacha20poly1305"
|
||||
)
|
||||
|
||||
const (
|
||||
KeySize = 32
|
||||
NonceSize = 12
|
||||
Overhead = 16
|
||||
)
|
||||
|
||||
// Available reports whether this CPU can run the kernel, which requires SSSE3.
|
||||
func Available() bool { return cpu.X86.HasSSSE3 }
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Open(dst []byte, key []uint32, src []byte, ad []byte) bool
|
||||
|
||||
//go:noescape
|
||||
func chacha20Poly1305Seal(dst []byte, key []uint32, src []byte, ad []byte)
|
||||
|
||||
type aead struct {
|
||||
key [KeySize]byte
|
||||
}
|
||||
|
||||
// New returns a ChaCha20-Poly1305 AEAD using the assembly kernel.
|
||||
func New(key []byte) (cipher.AEAD, error) {
|
||||
// Delegate to x/crypto rather than checking the key length here: its New also
|
||||
// refuses ChaCha20-Poly1305 under fips140=only, and this package is reached
|
||||
// instead of x/crypto on the CPUs it covers.
|
||||
if _, err := xchacha20poly1305.New(key); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !Available() {
|
||||
return nil, errors.New("chacha20poly1305: CPU lacks SSSE3")
|
||||
}
|
||||
a := &aead{}
|
||||
copy(a.key[:], key)
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (a *aead) NonceSize() int { return NonceSize }
|
||||
func (a *aead) Overhead() int { return Overhead }
|
||||
|
||||
// setupState writes a ChaCha20 input matrix to state, per RFC 8439 §2.3.
|
||||
// Copied from x/crypto's chacha20poly1305_amd64.go.
|
||||
func setupState(state *[16]uint32, key *[KeySize]byte, nonce []byte) {
|
||||
state[0] = 0x61707865
|
||||
state[1] = 0x3320646e
|
||||
state[2] = 0x79622d32
|
||||
state[3] = 0x6b206574
|
||||
|
||||
state[4] = binary.LittleEndian.Uint32(key[0: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[0:4])
|
||||
state[14] = binary.LittleEndian.Uint32(nonce[4:8])
|
||||
state[15] = binary.LittleEndian.Uint32(nonce[8:12])
|
||||
}
|
||||
|
||||
func (a *aead) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||
if len(nonce) != NonceSize {
|
||||
panic("chacha20poly1305: bad nonce length passed to Seal")
|
||||
}
|
||||
if uint64(len(plaintext)) > (1<<38)-64 {
|
||||
panic("chacha20poly1305: plaintext too large")
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &a.key, nonce)
|
||||
|
||||
ret, out := sliceForAppend(dst, len(plaintext)+Overhead)
|
||||
if inexactOverlap(out, plaintext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if anyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
chacha20Poly1305Seal(out[:], state[:], plaintext, additionalData)
|
||||
return ret
|
||||
}
|
||||
|
||||
var errOpen = errors.New("chacha20poly1305: message authentication failed")
|
||||
|
||||
func (a *aead) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
|
||||
if len(nonce) != NonceSize {
|
||||
// Matches x/crypto: a wrong-size nonce is API misuse, not a decrypt failure.
|
||||
panic("chacha20poly1305: bad nonce length passed to Open")
|
||||
}
|
||||
if len(ciphertext) < Overhead {
|
||||
return nil, errOpen
|
||||
}
|
||||
if uint64(len(ciphertext)) > (1<<38)-48 {
|
||||
panic("chacha20poly1305: ciphertext too large")
|
||||
}
|
||||
|
||||
var state [16]uint32
|
||||
setupState(&state, &a.key, nonce)
|
||||
|
||||
ciphertext = ciphertext[:len(ciphertext)-Overhead]
|
||||
ret, out := sliceForAppend(dst, len(ciphertext))
|
||||
if inexactOverlap(out, ciphertext) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and input")
|
||||
}
|
||||
if anyOverlap(out, additionalData) {
|
||||
panic("chacha20poly1305: invalid buffer overlap of output and additional data")
|
||||
}
|
||||
if !chacha20Poly1305Open(out, state[:], ciphertext, additionalData) {
|
||||
for i := range out {
|
||||
out[i] = 0
|
||||
}
|
||||
return nil, errOpen
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func sliceForAppend(dst []byte, n int) (head, tail []byte) {
|
||||
if total := len(dst) + n; cap(dst) >= total {
|
||||
head = dst[:total]
|
||||
} else {
|
||||
head = make([]byte, total)
|
||||
copy(head, dst)
|
||||
}
|
||||
tail = head[len(dst):]
|
||||
return
|
||||
}
|
||||
|
||||
// anyOverlap and inexactOverlap reproduce x/crypto/internal/alias, which cannot be
|
||||
// imported from outside x/crypto: exact aliasing is fine, partial overlap is not.
|
||||
func anyOverlap(x, y []byte) bool {
|
||||
return len(x) > 0 && len(y) > 0 &&
|
||||
uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
|
||||
uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
|
||||
}
|
||||
|
||||
func inexactOverlap(x, y []byte) bool {
|
||||
if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
|
||||
return false
|
||||
}
|
||||
return anyOverlap(x, y)
|
||||
}
|
||||
Reference in new issue
Block a user