-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'merged-main-go1.17.10' into main
This commit merges go1.17.10 unmodified src/crypto's subtree into the main branch of this repository. The code would most likely not compile because it would most certainly import from internal packages.
- Loading branch information
Showing
397 changed files
with
105,003 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
// Copyright 2015 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. | ||
|
||
//go:build amd64 || arm64 | ||
// +build amd64 arm64 | ||
|
||
package aes | ||
|
||
import ( | ||
"crypto/cipher" | ||
subtleoverlap "crypto/internal/subtle" | ||
"crypto/subtle" | ||
"errors" | ||
) | ||
|
||
// The following functions are defined in gcm_*.s. | ||
|
||
//go:noescape | ||
func gcmAesInit(productTable *[256]byte, ks []uint32) | ||
|
||
//go:noescape | ||
func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte) | ||
|
||
//go:noescape | ||
func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) | ||
|
||
//go:noescape | ||
func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32) | ||
|
||
//go:noescape | ||
func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64) | ||
|
||
const ( | ||
gcmBlockSize = 16 | ||
gcmTagSize = 16 | ||
gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes. | ||
gcmStandardNonceSize = 12 | ||
) | ||
|
||
var errOpen = errors.New("cipher: message authentication failed") | ||
|
||
// aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM | ||
// will use the optimised implementation in this file when possible. Instances | ||
// of this type only exist when hasGCMAsm returns true. | ||
type aesCipherGCM struct { | ||
aesCipherAsm | ||
} | ||
|
||
// Assert that aesCipherGCM implements the gcmAble interface. | ||
var _ gcmAble = (*aesCipherGCM)(nil) | ||
|
||
// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only | ||
// called by crypto/cipher.NewGCM via the gcmAble interface. | ||
func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { | ||
g := &gcmAsm{ks: c.enc, nonceSize: nonceSize, tagSize: tagSize} | ||
gcmAesInit(&g.productTable, g.ks) | ||
return g, nil | ||
} | ||
|
||
type gcmAsm struct { | ||
// ks is the key schedule, the length of which depends on the size of | ||
// the AES key. | ||
ks []uint32 | ||
// productTable contains pre-computed multiples of the binary-field | ||
// element used in GHASH. | ||
productTable [256]byte | ||
// nonceSize contains the expected size of the nonce, in bytes. | ||
nonceSize int | ||
// tagSize contains the size of the tag, in bytes. | ||
tagSize int | ||
} | ||
|
||
func (g *gcmAsm) NonceSize() int { | ||
return g.nonceSize | ||
} | ||
|
||
func (g *gcmAsm) Overhead() int { | ||
return g.tagSize | ||
} | ||
|
||
// sliceForAppend takes a slice and a requested number of bytes. It returns a | ||
// slice with the contents of the given slice followed by that many bytes and a | ||
// second slice that aliases into it and contains only the extra bytes. If the | ||
// original slice has sufficient capacity then no allocation is performed. | ||
func sliceForAppend(in []byte, n int) (head, tail []byte) { | ||
if total := len(in) + n; cap(in) >= total { | ||
head = in[:total] | ||
} else { | ||
head = make([]byte, total) | ||
copy(head, in) | ||
} | ||
tail = head[len(in):] | ||
return | ||
} | ||
|
||
// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for | ||
// details. | ||
func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte { | ||
if len(nonce) != g.nonceSize { | ||
panic("crypto/cipher: incorrect nonce length given to GCM") | ||
} | ||
if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize { | ||
panic("crypto/cipher: message too large for GCM") | ||
} | ||
|
||
var counter, tagMask [gcmBlockSize]byte | ||
|
||
if len(nonce) == gcmStandardNonceSize { | ||
// Init counter to nonce||1 | ||
copy(counter[:], nonce) | ||
counter[gcmBlockSize-1] = 1 | ||
} else { | ||
// Otherwise counter = GHASH(nonce) | ||
gcmAesData(&g.productTable, nonce, &counter) | ||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) | ||
} | ||
|
||
encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) | ||
|
||
var tagOut [gcmTagSize]byte | ||
gcmAesData(&g.productTable, data, &tagOut) | ||
|
||
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize) | ||
if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) { | ||
panic("crypto/cipher: invalid buffer overlap") | ||
} | ||
if len(plaintext) > 0 { | ||
gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks) | ||
} | ||
gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data))) | ||
copy(out[len(plaintext):], tagOut[:]) | ||
|
||
return ret | ||
} | ||
|
||
// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface | ||
// for details. | ||
func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { | ||
if len(nonce) != g.nonceSize { | ||
panic("crypto/cipher: incorrect nonce length given to GCM") | ||
} | ||
// Sanity check to prevent the authentication from always succeeding if an implementation | ||
// leaves tagSize uninitialized, for example. | ||
if g.tagSize < gcmMinimumTagSize { | ||
panic("crypto/cipher: incorrect GCM tag size") | ||
} | ||
|
||
if len(ciphertext) < g.tagSize { | ||
return nil, errOpen | ||
} | ||
if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) { | ||
return nil, errOpen | ||
} | ||
|
||
tag := ciphertext[len(ciphertext)-g.tagSize:] | ||
ciphertext = ciphertext[:len(ciphertext)-g.tagSize] | ||
|
||
// See GCM spec, section 7.1. | ||
var counter, tagMask [gcmBlockSize]byte | ||
|
||
if len(nonce) == gcmStandardNonceSize { | ||
// Init counter to nonce||1 | ||
copy(counter[:], nonce) | ||
counter[gcmBlockSize-1] = 1 | ||
} else { | ||
// Otherwise counter = GHASH(nonce) | ||
gcmAesData(&g.productTable, nonce, &counter) | ||
gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0)) | ||
} | ||
|
||
encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0]) | ||
|
||
var expectedTag [gcmTagSize]byte | ||
gcmAesData(&g.productTable, data, &expectedTag) | ||
|
||
ret, out := sliceForAppend(dst, len(ciphertext)) | ||
if subtleoverlap.InexactOverlap(out, ciphertext) { | ||
panic("crypto/cipher: invalid buffer overlap") | ||
} | ||
if len(ciphertext) > 0 { | ||
gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks) | ||
} | ||
gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data))) | ||
|
||
if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 { | ||
for i := range out { | ||
out[i] = 0 | ||
} | ||
return nil, errOpen | ||
} | ||
|
||
return ret, nil | ||
} |
Oops, something went wrong.