While both impractical and unlikely, the multiplication could overflow on 32-bit architectures. The 64-bit architecture case is unaffected by both the maximum length of Go slices being too small to trigger the overflow (everything except s390), and it being safe to assume no machine has more than 2 EiB of memory. Fixes golang/go#66232 Change-Id: I19c15d42d2d6af35e296697159d43d02f513e614 GitHub-Last-Rev: 503e180debfdc93ab99977172af2b64290cb80e8 GitHub-Pull-Request: golang/crypto#286 Reviewed-on: https://go-review.googlesource.com/c/crypto/+/570876 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Filippo Valsorda <filippo@golang.org> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
175 lines
5.4 KiB
Go
175 lines
5.4 KiB
Go
// Copyright 2014 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.
|
|
|
|
package sha3
|
|
|
|
// This file defines the ShakeHash interface, and provides
|
|
// functions for creating SHAKE and cSHAKE instances, as well as utility
|
|
// functions for hashing bytes to arbitrary-length output.
|
|
//
|
|
//
|
|
// SHAKE implementation is based on FIPS PUB 202 [1]
|
|
// cSHAKE implementations is based on NIST SP 800-185 [2]
|
|
//
|
|
// [1] https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
|
|
// [2] https://doi.org/10.6028/NIST.SP.800-185
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"hash"
|
|
"io"
|
|
)
|
|
|
|
// ShakeHash defines the interface to hash functions that support
|
|
// arbitrary-length output. When used as a plain [hash.Hash], it
|
|
// produces minimum-length outputs that provide full-strength generic
|
|
// security.
|
|
type ShakeHash interface {
|
|
hash.Hash
|
|
|
|
// Read reads more output from the hash; reading affects the hash's
|
|
// state. (ShakeHash.Read is thus very different from Hash.Sum)
|
|
// It never returns an error, but subsequent calls to Write or Sum
|
|
// will panic.
|
|
io.Reader
|
|
|
|
// Clone returns a copy of the ShakeHash in its current state.
|
|
Clone() ShakeHash
|
|
}
|
|
|
|
// cSHAKE specific context
|
|
type cshakeState struct {
|
|
*state // SHA-3 state context and Read/Write operations
|
|
|
|
// initBlock is the cSHAKE specific initialization set of bytes. It is initialized
|
|
// by newCShake function and stores concatenation of N followed by S, encoded
|
|
// by the method specified in 3.3 of [1].
|
|
// It is stored here in order for Reset() to be able to put context into
|
|
// initial state.
|
|
initBlock []byte
|
|
}
|
|
|
|
// Consts for configuring initial SHA-3 state
|
|
const (
|
|
dsbyteShake = 0x1f
|
|
dsbyteCShake = 0x04
|
|
rate128 = 168
|
|
rate256 = 136
|
|
)
|
|
|
|
func bytepad(input []byte, w int) []byte {
|
|
// leftEncode always returns max 9 bytes
|
|
buf := make([]byte, 0, 9+len(input)+w)
|
|
buf = append(buf, leftEncode(uint64(w))...)
|
|
buf = append(buf, input...)
|
|
padlen := w - (len(buf) % w)
|
|
return append(buf, make([]byte, padlen)...)
|
|
}
|
|
|
|
func leftEncode(value uint64) []byte {
|
|
var b [9]byte
|
|
binary.BigEndian.PutUint64(b[1:], value)
|
|
// Trim all but last leading zero bytes
|
|
i := byte(1)
|
|
for i < 8 && b[i] == 0 {
|
|
i++
|
|
}
|
|
// Prepend number of encoded bytes
|
|
b[i-1] = 9 - i
|
|
return b[i-1:]
|
|
}
|
|
|
|
func newCShake(N, S []byte, rate, outputLen int, dsbyte byte) ShakeHash {
|
|
c := cshakeState{state: &state{rate: rate, outputLen: outputLen, dsbyte: dsbyte}}
|
|
|
|
// leftEncode returns max 9 bytes
|
|
c.initBlock = make([]byte, 0, 9*2+len(N)+len(S))
|
|
c.initBlock = append(c.initBlock, leftEncode(uint64(len(N))*8)...)
|
|
c.initBlock = append(c.initBlock, N...)
|
|
c.initBlock = append(c.initBlock, leftEncode(uint64(len(S))*8)...)
|
|
c.initBlock = append(c.initBlock, S...)
|
|
c.Write(bytepad(c.initBlock, c.rate))
|
|
return &c
|
|
}
|
|
|
|
// Reset resets the hash to initial state.
|
|
func (c *cshakeState) Reset() {
|
|
c.state.Reset()
|
|
c.Write(bytepad(c.initBlock, c.rate))
|
|
}
|
|
|
|
// Clone returns copy of a cSHAKE context within its current state.
|
|
func (c *cshakeState) Clone() ShakeHash {
|
|
b := make([]byte, len(c.initBlock))
|
|
copy(b, c.initBlock)
|
|
return &cshakeState{state: c.clone(), initBlock: b}
|
|
}
|
|
|
|
// Clone returns copy of SHAKE context within its current state.
|
|
func (c *state) Clone() ShakeHash {
|
|
return c.clone()
|
|
}
|
|
|
|
// NewShake128 creates a new SHAKE128 variable-output-length ShakeHash.
|
|
// Its generic security strength is 128 bits against all attacks if at
|
|
// least 32 bytes of its output are used.
|
|
func NewShake128() ShakeHash {
|
|
return newShake128()
|
|
}
|
|
|
|
// NewShake256 creates a new SHAKE256 variable-output-length ShakeHash.
|
|
// Its generic security strength is 256 bits against all attacks if
|
|
// at least 64 bytes of its output are used.
|
|
func NewShake256() ShakeHash {
|
|
return newShake256()
|
|
}
|
|
|
|
func newShake128Generic() *state {
|
|
return &state{rate: rate128, outputLen: 32, dsbyte: dsbyteShake}
|
|
}
|
|
|
|
func newShake256Generic() *state {
|
|
return &state{rate: rate256, outputLen: 64, dsbyte: dsbyteShake}
|
|
}
|
|
|
|
// NewCShake128 creates a new instance of cSHAKE128 variable-output-length ShakeHash,
|
|
// a customizable variant of SHAKE128.
|
|
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
|
|
// desired. S is a customization byte string used for domain separation - two cSHAKE
|
|
// computations on same input with different S yield unrelated outputs.
|
|
// When N and S are both empty, this is equivalent to NewShake128.
|
|
func NewCShake128(N, S []byte) ShakeHash {
|
|
if len(N) == 0 && len(S) == 0 {
|
|
return NewShake128()
|
|
}
|
|
return newCShake(N, S, rate128, 32, dsbyteCShake)
|
|
}
|
|
|
|
// NewCShake256 creates a new instance of cSHAKE256 variable-output-length ShakeHash,
|
|
// a customizable variant of SHAKE256.
|
|
// N is used to define functions based on cSHAKE, it can be empty when plain cSHAKE is
|
|
// desired. S is a customization byte string used for domain separation - two cSHAKE
|
|
// computations on same input with different S yield unrelated outputs.
|
|
// When N and S are both empty, this is equivalent to NewShake256.
|
|
func NewCShake256(N, S []byte) ShakeHash {
|
|
if len(N) == 0 && len(S) == 0 {
|
|
return NewShake256()
|
|
}
|
|
return newCShake(N, S, rate256, 64, dsbyteCShake)
|
|
}
|
|
|
|
// ShakeSum128 writes an arbitrary-length digest of data into hash.
|
|
func ShakeSum128(hash, data []byte) {
|
|
h := NewShake128()
|
|
h.Write(data)
|
|
h.Read(hash)
|
|
}
|
|
|
|
// ShakeSum256 writes an arbitrary-length digest of data into hash.
|
|
func ShakeSum256(hash, data []byte) {
|
|
h := NewShake256()
|
|
h.Write(data)
|
|
h.Read(hash)
|
|
}
|