mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
crypto/{aes,cipher,rand}: use binary.{Big,Little}Endian methods
Use the binary.{Big,Little}Endian integer encoding methods rather
than unsafe or local implementations. These methods are tested to
ensure they inline correctly and don't add unnecessary bounds checks,
so it seems better to use them wherever possible.
This introduces a dependency on encoding/binary to crypto/cipher. I
think this is OK because other "L3" packages already import
encoding/binary.
Change-Id: I5cf01800d08554ca364e46cfc1d9445cf3c711a0
Reviewed-on: https://go-review.googlesource.com/115555
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
3649fe299d
commit
4a842f2559
6 changed files with 56 additions and 103 deletions
|
|
@ -36,14 +36,17 @@
|
|||
|
||||
package aes
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Encrypt one block from src into dst, using the expanded key xk.
|
||||
func encryptBlockGo(xk []uint32, dst, src []byte) {
|
||||
var s0, s1, s2, s3, t0, t1, t2, t3 uint32
|
||||
|
||||
s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
|
||||
s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
|
||||
s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
|
||||
s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
|
||||
_ = src[15] // early bounds check
|
||||
s0 := binary.BigEndian.Uint32(src[0:4])
|
||||
s1 := binary.BigEndian.Uint32(src[4:8])
|
||||
s2 := binary.BigEndian.Uint32(src[8:12])
|
||||
s3 := binary.BigEndian.Uint32(src[12:16])
|
||||
|
||||
// First round just XORs input with key.
|
||||
s0 ^= xk[0]
|
||||
|
|
@ -55,6 +58,7 @@ func encryptBlockGo(xk []uint32, dst, src []byte) {
|
|||
// Number of rounds is set by length of expanded key.
|
||||
nr := len(xk)/4 - 2 // - 2: one above, one more below
|
||||
k := 4
|
||||
var t0, t1, t2, t3 uint32
|
||||
for r := 0; r < nr; r++ {
|
||||
t0 = xk[k+0] ^ te0[uint8(s0>>24)] ^ te1[uint8(s1>>16)] ^ te2[uint8(s2>>8)] ^ te3[uint8(s3)]
|
||||
t1 = xk[k+1] ^ te0[uint8(s1>>24)] ^ te1[uint8(s2>>16)] ^ te2[uint8(s3>>8)] ^ te3[uint8(s0)]
|
||||
|
|
@ -75,20 +79,20 @@ func encryptBlockGo(xk []uint32, dst, src []byte) {
|
|||
s2 ^= xk[k+2]
|
||||
s3 ^= xk[k+3]
|
||||
|
||||
dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
|
||||
dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
|
||||
dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
|
||||
dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
|
||||
_ = dst[15] // early bounds check
|
||||
binary.BigEndian.PutUint32(dst[0:4], s0)
|
||||
binary.BigEndian.PutUint32(dst[4:8], s1)
|
||||
binary.BigEndian.PutUint32(dst[8:12], s2)
|
||||
binary.BigEndian.PutUint32(dst[12:16], s3)
|
||||
}
|
||||
|
||||
// Decrypt one block from src into dst, using the expanded key xk.
|
||||
func decryptBlockGo(xk []uint32, dst, src []byte) {
|
||||
var s0, s1, s2, s3, t0, t1, t2, t3 uint32
|
||||
|
||||
s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3])
|
||||
s1 = uint32(src[4])<<24 | uint32(src[5])<<16 | uint32(src[6])<<8 | uint32(src[7])
|
||||
s2 = uint32(src[8])<<24 | uint32(src[9])<<16 | uint32(src[10])<<8 | uint32(src[11])
|
||||
s3 = uint32(src[12])<<24 | uint32(src[13])<<16 | uint32(src[14])<<8 | uint32(src[15])
|
||||
_ = src[15] // early bounds check
|
||||
s0 := binary.BigEndian.Uint32(src[0:4])
|
||||
s1 := binary.BigEndian.Uint32(src[4:8])
|
||||
s2 := binary.BigEndian.Uint32(src[8:12])
|
||||
s3 := binary.BigEndian.Uint32(src[12:16])
|
||||
|
||||
// First round just XORs input with key.
|
||||
s0 ^= xk[0]
|
||||
|
|
@ -100,6 +104,7 @@ func decryptBlockGo(xk []uint32, dst, src []byte) {
|
|||
// Number of rounds is set by length of expanded key.
|
||||
nr := len(xk)/4 - 2 // - 2: one above, one more below
|
||||
k := 4
|
||||
var t0, t1, t2, t3 uint32
|
||||
for r := 0; r < nr; r++ {
|
||||
t0 = xk[k+0] ^ td0[uint8(s0>>24)] ^ td1[uint8(s3>>16)] ^ td2[uint8(s2>>8)] ^ td3[uint8(s1)]
|
||||
t1 = xk[k+1] ^ td0[uint8(s1>>24)] ^ td1[uint8(s0>>16)] ^ td2[uint8(s3>>8)] ^ td3[uint8(s2)]
|
||||
|
|
@ -120,10 +125,11 @@ func decryptBlockGo(xk []uint32, dst, src []byte) {
|
|||
s2 ^= xk[k+2]
|
||||
s3 ^= xk[k+3]
|
||||
|
||||
dst[0], dst[1], dst[2], dst[3] = byte(s0>>24), byte(s0>>16), byte(s0>>8), byte(s0)
|
||||
dst[4], dst[5], dst[6], dst[7] = byte(s1>>24), byte(s1>>16), byte(s1>>8), byte(s1)
|
||||
dst[8], dst[9], dst[10], dst[11] = byte(s2>>24), byte(s2>>16), byte(s2>>8), byte(s2)
|
||||
dst[12], dst[13], dst[14], dst[15] = byte(s3>>24), byte(s3>>16), byte(s3>>8), byte(s3)
|
||||
_ = dst[15] // early bounds check
|
||||
binary.BigEndian.PutUint32(dst[0:4], s0)
|
||||
binary.BigEndian.PutUint32(dst[4:8], s1)
|
||||
binary.BigEndian.PutUint32(dst[8:12], s2)
|
||||
binary.BigEndian.PutUint32(dst[12:16], s3)
|
||||
}
|
||||
|
||||
// Apply sbox0 to each byte in w.
|
||||
|
|
@ -144,7 +150,7 @@ func expandKeyGo(key []byte, enc, dec []uint32) {
|
|||
var i int
|
||||
nk := len(key) / 4
|
||||
for i = 0; i < nk; i++ {
|
||||
enc[i] = uint32(key[4*i])<<24 | uint32(key[4*i+1])<<16 | uint32(key[4*i+2])<<8 | uint32(key[4*i+3])
|
||||
enc[i] = binary.BigEndian.Uint32(key[4*i:])
|
||||
}
|
||||
for ; i < len(enc); i++ {
|
||||
t := enc[i-1]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ package aes
|
|||
import (
|
||||
"crypto/cipher"
|
||||
"crypto/internal/subtle"
|
||||
"unsafe"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
// Assert that aesCipherAsm implements the ctrAble interface.
|
||||
|
|
@ -38,8 +38,8 @@ func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream {
|
|||
}
|
||||
var ac aesctr
|
||||
ac.block = c
|
||||
ac.ctr[0] = *(*uint64)(unsafe.Pointer((&iv[0]))) // high bits
|
||||
ac.ctr[1] = *(*uint64)(unsafe.Pointer((&iv[8]))) // low bits
|
||||
ac.ctr[0] = binary.BigEndian.Uint64(iv[0:]) // high bits
|
||||
ac.ctr[1] = binary.BigEndian.Uint64(iv[8:]) // low bits
|
||||
ac.buffer = ac.storage[:0]
|
||||
return &ac
|
||||
}
|
||||
|
|
@ -48,10 +48,10 @@ func (c *aesctr) refill() {
|
|||
// Fill up the buffer with an incrementing count.
|
||||
c.buffer = c.storage[:streamBufferSize]
|
||||
c0, c1 := c.ctr[0], c.ctr[1]
|
||||
for i := 0; i < streamBufferSize; i += BlockSize {
|
||||
b0 := (*uint64)(unsafe.Pointer(&c.buffer[i]))
|
||||
b1 := (*uint64)(unsafe.Pointer(&c.buffer[i+BlockSize/2]))
|
||||
*b0, *b1 = c0, c1
|
||||
for i := 0; i < streamBufferSize; i += 16 {
|
||||
binary.BigEndian.PutUint64(c.buffer[i+0:], c0)
|
||||
binary.BigEndian.PutUint64(c.buffer[i+8:], c1)
|
||||
|
||||
// Increment in big endian: c0 is high, c1 is low.
|
||||
c1++
|
||||
if c1 == 0 {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"crypto/cipher"
|
||||
subtleoverlap "crypto/internal/subtle"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"internal/cpu"
|
||||
)
|
||||
|
|
@ -22,35 +23,15 @@ type gcmCount [16]byte
|
|||
|
||||
// inc increments the rightmost 32-bits of the count value by 1.
|
||||
func (x *gcmCount) inc() {
|
||||
// The compiler should optimize this to a 32-bit addition.
|
||||
n := uint32(x[15]) | uint32(x[14])<<8 | uint32(x[13])<<16 | uint32(x[12])<<24
|
||||
n += 1
|
||||
x[12] = byte(n >> 24)
|
||||
x[13] = byte(n >> 16)
|
||||
x[14] = byte(n >> 8)
|
||||
x[15] = byte(n)
|
||||
binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1)
|
||||
}
|
||||
|
||||
// gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
|
||||
func gcmLengths(len0, len1 uint64) [16]byte {
|
||||
return [16]byte{
|
||||
byte(len0 >> 56),
|
||||
byte(len0 >> 48),
|
||||
byte(len0 >> 40),
|
||||
byte(len0 >> 32),
|
||||
byte(len0 >> 24),
|
||||
byte(len0 >> 16),
|
||||
byte(len0 >> 8),
|
||||
byte(len0),
|
||||
byte(len1 >> 56),
|
||||
byte(len1 >> 48),
|
||||
byte(len1 >> 40),
|
||||
byte(len1 >> 32),
|
||||
byte(len1 >> 24),
|
||||
byte(len1 >> 16),
|
||||
byte(len1 >> 8),
|
||||
byte(len1),
|
||||
}
|
||||
v := [16]byte{}
|
||||
binary.BigEndian.PutUint64(v[0:], len0)
|
||||
binary.BigEndian.PutUint64(v[8:], len1)
|
||||
return v
|
||||
}
|
||||
|
||||
// gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ package cipher
|
|||
import (
|
||||
subtleoverlap "crypto/internal/subtle"
|
||||
"crypto/subtle"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
)
|
||||
|
||||
|
|
@ -53,8 +54,8 @@ type gcmAble interface {
|
|||
}
|
||||
|
||||
// gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM
|
||||
// standard and make getUint64 suitable for marshaling these values, the bits
|
||||
// are stored backwards. For example:
|
||||
// standard and make binary.BigEndian suitable for marshaling these values, the
|
||||
// bits are stored in big endian order. For example:
|
||||
// the coefficient of x⁰ can be obtained by v.low >> 63.
|
||||
// the coefficient of x⁶³ can be obtained by v.low & 1.
|
||||
// the coefficient of x⁶⁴ can be obtained by v.high >> 63.
|
||||
|
|
@ -130,8 +131,8 @@ func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, erro
|
|||
// would expect, say, 4*key to be in index 4 of the table but due to
|
||||
// this bit ordering it will actually be in index 0010 (base 2) = 2.
|
||||
x := gcmFieldElement{
|
||||
getUint64(key[:8]),
|
||||
getUint64(key[8:]),
|
||||
binary.BigEndian.Uint64(key[:8]),
|
||||
binary.BigEndian.Uint64(key[8:]),
|
||||
}
|
||||
g.productTable[reverseBits(1)] = x
|
||||
|
||||
|
|
@ -316,8 +317,8 @@ func (g *gcm) mul(y *gcmFieldElement) {
|
|||
// Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks.
|
||||
func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) {
|
||||
for len(blocks) > 0 {
|
||||
y.low ^= getUint64(blocks)
|
||||
y.high ^= getUint64(blocks[8:])
|
||||
y.low ^= binary.BigEndian.Uint64(blocks)
|
||||
y.high ^= binary.BigEndian.Uint64(blocks[8:])
|
||||
g.mul(y)
|
||||
blocks = blocks[gcmBlockSize:]
|
||||
}
|
||||
|
|
@ -339,12 +340,8 @@ func (g *gcm) update(y *gcmFieldElement, data []byte) {
|
|||
// gcmInc32 treats the final four bytes of counterBlock as a big-endian value
|
||||
// and increments it.
|
||||
func gcmInc32(counterBlock *[16]byte) {
|
||||
for i := gcmBlockSize - 1; i >= gcmBlockSize-4; i-- {
|
||||
counterBlock[i]++
|
||||
if counterBlock[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
ctr := counterBlock[len(counterBlock)-4:]
|
||||
binary.BigEndian.PutUint32(ctr, binary.BigEndian.Uint32(ctr)+1)
|
||||
}
|
||||
|
||||
// sliceForAppend takes a slice and a requested number of bytes. It returns a
|
||||
|
|
@ -400,8 +397,8 @@ func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
|
|||
g.update(&y, nonce)
|
||||
y.high ^= uint64(len(nonce)) * 8
|
||||
g.mul(&y)
|
||||
putUint64(counter[:8], y.low)
|
||||
putUint64(counter[8:], y.high)
|
||||
binary.BigEndian.PutUint64(counter[:8], y.low)
|
||||
binary.BigEndian.PutUint64(counter[8:], y.high)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -417,33 +414,8 @@ func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]
|
|||
|
||||
g.mul(&y)
|
||||
|
||||
putUint64(out, y.low)
|
||||
putUint64(out[8:], y.high)
|
||||
binary.BigEndian.PutUint64(out, y.low)
|
||||
binary.BigEndian.PutUint64(out[8:], y.high)
|
||||
|
||||
xorWords(out, out, tagMask[:])
|
||||
}
|
||||
|
||||
func getUint64(data []byte) uint64 {
|
||||
_ = data[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
r := uint64(data[0])<<56 |
|
||||
uint64(data[1])<<48 |
|
||||
uint64(data[2])<<40 |
|
||||
uint64(data[3])<<32 |
|
||||
uint64(data[4])<<24 |
|
||||
uint64(data[5])<<16 |
|
||||
uint64(data[6])<<8 |
|
||||
uint64(data[7])
|
||||
return r
|
||||
}
|
||||
|
||||
func putUint64(out []byte, v uint64) {
|
||||
_ = out[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
out[0] = byte(v >> 56)
|
||||
out[1] = byte(v >> 48)
|
||||
out[2] = byte(v >> 40)
|
||||
out[3] = byte(v >> 32)
|
||||
out[4] = byte(v >> 24)
|
||||
out[5] = byte(v >> 16)
|
||||
out[6] = byte(v >> 8)
|
||||
out[7] = byte(v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"bufio"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/binary"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
|
|
@ -137,14 +138,7 @@ func (r *reader) Read(b []byte) (n int, err error) {
|
|||
// dst = encrypt(t^seed)
|
||||
// seed = encrypt(t^dst)
|
||||
ns := time.Now().UnixNano()
|
||||
r.time[0] = byte(ns >> 56)
|
||||
r.time[1] = byte(ns >> 48)
|
||||
r.time[2] = byte(ns >> 40)
|
||||
r.time[3] = byte(ns >> 32)
|
||||
r.time[4] = byte(ns >> 24)
|
||||
r.time[5] = byte(ns >> 16)
|
||||
r.time[6] = byte(ns >> 8)
|
||||
r.time[7] = byte(ns)
|
||||
binary.BigEndian.PutUint64(r.time[:], uint64(ns))
|
||||
r.cipher.Encrypt(r.time[0:], r.time[0:])
|
||||
for i := 0; i < aes.BlockSize; i++ {
|
||||
r.dst[i] = r.time[i] ^ r.seed[i]
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ var pkgDeps = map[string][]string{
|
|||
// and interface definitions, but nothing that makes
|
||||
// system calls.
|
||||
"crypto": {"L2", "hash"}, // interfaces
|
||||
"crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"},
|
||||
"crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle", "encoding/binary"},
|
||||
"crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag
|
||||
"crypto/subtle": {},
|
||||
"encoding/base32": {"L2"},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue