]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/aes: de-couple asm and go implementations
authorMichael Munday <munday@ca.ibm.com>
Fri, 15 Apr 2016 20:56:37 +0000 (16:56 -0400)
committerMichael Munday <munday@ca.ibm.com>
Tue, 19 Apr 2016 18:50:51 +0000 (18:50 +0000)
There is currently only one assembly implementation of AES
(amd64). While it is possible to fit other implementations to the
same pattern it complicates the code. For example s390x does not
use expanded keys, so having enc and dec in the aesCipher struct
is confusing.

By separating out the asm implementations we can more closely
match the data structures to the underlying implementation. This
also opens the door for AES implementations that support block
cipher modes other than GCM (e.g. CTR and CBC).

This commit changes BenchmarkExpandKey to test the go
implementation of key expansion. It might be better to have some
sort of 'initialisation' benchmark instead to cover the startup
costs of the assembly implementations (which might be doing
key expansion in a different way, or not at all).

Change-Id: I094a7176b5bbe2177df73163a9c0b711a61c12d6
Reviewed-on: https://go-review.googlesource.com/22193
Run-TryBot: Michael Munday <munday@ca.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/crypto/aes/aes_gcm.go
src/crypto/aes/aes_test.go
src/crypto/aes/cipher.go
src/crypto/aes/cipher_amd64.go [new file with mode: 0644]
src/crypto/aes/cipher_asm.go [deleted file]
src/crypto/aes/cipher_generic.go

index 13775789509041d475ac2e7809bab9c18a4784be..b55714d57ab7f660bd1b7ea4129f4e1f8e0b81cf 100644 (file)
@@ -45,7 +45,7 @@ var errOpen = errors.New("cipher: message authentication failed")
 // will use the optimised implementation in this file when possible. Instances
 // of this type only exist when hasGCMAsm returns true.
 type aesCipherGCM struct {
-       aesCipher
+       aesCipherAsm
 }
 
 // NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
index 28144968fcfd258d889840782bff0c25b81b407f..3cc390d4e2a7f1e65f046cb1f35d2497c528898e 100644 (file)
@@ -380,6 +380,6 @@ func BenchmarkExpand(b *testing.B) {
        c := &aesCipher{make([]uint32, n), make([]uint32, n)}
        b.ResetTimer()
        for i := 0; i < b.N; i++ {
-               expandKey(tt.key, c.enc, c.dec)
+               expandKeyGo(tt.key, c.enc, c.dec)
        }
 }
index 04d2be1283fb8566199d68d616446d67205283c0..c5a8e91d009b790da6d790edc04e26e175dcb736 100644 (file)
@@ -36,15 +36,15 @@ func NewCipher(key []byte) (cipher.Block, error) {
        case 16, 24, 32:
                break
        }
+       return newCipher(key)
+}
 
-       n := k + 28
+// newCipherGeneric creates and returns a new cipher.Block
+// implemented in pure Go.
+func newCipherGeneric(key []byte) (cipher.Block, error) {
+       n := len(key) + 28
        c := aesCipher{make([]uint32, n), make([]uint32, n)}
-       expandKey(key, c.enc, c.dec)
-
-       if hasGCMAsm() {
-               return &aesCipherGCM{c}, nil
-       }
-
+       expandKeyGo(key, c.enc, c.dec)
        return &c, nil
 }
 
@@ -57,7 +57,7 @@ func (c *aesCipher) Encrypt(dst, src []byte) {
        if len(dst) < BlockSize {
                panic("crypto/aes: output not full block")
        }
-       encryptBlock(c.enc, dst, src)
+       encryptBlockGo(c.enc, dst, src)
 }
 
 func (c *aesCipher) Decrypt(dst, src []byte) {
@@ -67,5 +67,5 @@ func (c *aesCipher) Decrypt(dst, src []byte) {
        if len(dst) < BlockSize {
                panic("crypto/aes: output not full block")
        }
-       decryptBlock(c.dec, dst, src)
+       decryptBlockGo(c.dec, dst, src)
 }
diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_amd64.go
new file mode 100644 (file)
index 0000000..3b600c3
--- /dev/null
@@ -0,0 +1,66 @@
+// Copyright 2012 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 aes
+
+import (
+       "crypto/cipher"
+)
+
+// defined in asm_amd64.s
+func hasAsm() bool
+func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
+
+type aesCipherAsm struct {
+       aesCipher
+}
+
+var useAsm = hasAsm()
+
+func newCipher(key []byte) (cipher.Block, error) {
+       if !useAsm {
+               return newCipherGeneric(key)
+       }
+       n := len(key) + 28
+       c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
+       rounds := 10
+       switch len(key) {
+       case 128 / 8:
+               rounds = 10
+       case 192 / 8:
+               rounds = 12
+       case 256 / 8:
+               rounds = 14
+       }
+       expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0])
+       if hasGCMAsm() {
+               return &aesCipherGCM{c}, nil
+       }
+
+       return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+       if len(src) < BlockSize {
+               panic("crypto/aes: input not full block")
+       }
+       if len(dst) < BlockSize {
+               panic("crypto/aes: output not full block")
+       }
+       encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+       if len(src) < BlockSize {
+               panic("crypto/aes: input not full block")
+       }
+       if len(dst) < BlockSize {
+               panic("crypto/aes: output not full block")
+       }
+       decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
+}
diff --git a/src/crypto/aes/cipher_asm.go b/src/crypto/aes/cipher_asm.go
deleted file mode 100644 (file)
index 964eaaa..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2012 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 aes
-
-// defined in asm_$GOARCH.s
-func hasAsm() bool
-func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
-func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
-func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
-
-var useAsm = hasAsm()
-
-func encryptBlock(xk []uint32, dst, src []byte) {
-       if useAsm {
-               encryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
-       } else {
-               encryptBlockGo(xk, dst, src)
-       }
-}
-
-func decryptBlock(xk []uint32, dst, src []byte) {
-       if useAsm {
-               decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0])
-       } else {
-               decryptBlockGo(xk, dst, src)
-       }
-}
-
-func expandKey(key []byte, enc, dec []uint32) {
-       if useAsm {
-               rounds := 10
-               switch len(key) {
-               case 128 / 8:
-                       rounds = 10
-               case 192 / 8:
-                       rounds = 12
-               case 256 / 8:
-                       rounds = 14
-               }
-               expandKeyAsm(rounds, &key[0], &enc[0], &dec[0])
-       } else {
-               expandKeyGo(key, enc, dec)
-       }
-}
index 32b2b3cc56d67b54a6cbcaf30aaaf1615e6af319..c5e02fe79b49be5b25652dc753fe8736b78500d5 100644 (file)
@@ -6,22 +6,15 @@
 
 package aes
 
-func encryptBlock(xk []uint32, dst, src []byte) {
-       encryptBlockGo(xk, dst, src)
-}
-
-func decryptBlock(xk []uint32, dst, src []byte) {
-       decryptBlockGo(xk, dst, src)
-}
-
-func expandKey(key []byte, enc, dec []uint32) {
-       expandKeyGo(key, enc, dec)
-}
-
-func hasGCMAsm() bool {
-       return false
-}
+import (
+       "crypto/cipher"
+)
 
-type aesCipherGCM struct {
-       aesCipher
+// newCipher calls the newCipherGeneric function
+// directly. Platforms with hardware accelerated
+// implementations of AES should implement their
+// own version of newCipher (which may then call
+// newCipherGeneric if needed).
+func newCipher(key []byte) (cipher.Block, error) {
+       return newCipherGeneric(key)
 }