]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/aes: add s390x assembly implementation
authorMichael Munday <munday@ca.ibm.com>
Fri, 15 Apr 2016 22:45:17 +0000 (18:45 -0400)
committerMichael Munday <munday@ca.ibm.com>
Wed, 20 Apr 2016 17:02:14 +0000 (17:02 +0000)
Adds support for single block encryption using the cipher message
(KM) instruction. KM handles key expansion internally and
therefore it is not done up front when using the assembly
implementation on s390x.

Change-Id: I69954b8ae36d549e1dc40d7acd5a10bedfaaef9c
Reviewed-on: https://go-review.googlesource.com/22194
Run-TryBot: Michael Munday <munday@ca.ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bill O'Farrell <billotosyr@gmail.com>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
src/crypto/aes/asm_s390x.s [new file with mode: 0644]
src/crypto/aes/cipher_generic.go
src/crypto/aes/cipher_s390x.go [new file with mode: 0644]

diff --git a/src/crypto/aes/asm_s390x.s b/src/crypto/aes/asm_s390x.s
new file mode 100644 (file)
index 0000000..4a0720c
--- /dev/null
@@ -0,0 +1,35 @@
+// Copyright 2016 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.
+
+#include "textflag.h"
+
+// func hasAsm() bool
+TEXT ·hasAsm(SB),NOSPLIT,$16-1
+       XOR     R0, R0          // set function code to 0 (query)
+       LA      mask-16(SP), R1 // 16-byte stack variable for mask
+       WORD    $0xB92E0024     // cipher message (KM)
+
+       // check if bits 18-20 (big endian) are set
+       MOVD    mask-16(SP), R2
+       MOVD    $(0x38<<40), R3
+       AND     R3, R2
+       CMPBNE  R2, R3, notfound
+       MOVB    $1, ret+0(FP)
+       RET
+notfound:
+       MOVB    $0, ret+0(FP)
+       RET
+
+// func cryptBlocks(function code, key, dst, src *byte, length int)
+TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
+       MOVD    key+8(FP), R1
+       MOVD    dst+16(FP), R2
+       MOVD    src+24(FP), R4
+       MOVD    length+32(FP), R5
+       MOVD    function+0(FP), R0
+loop:
+       WORD    $0xB92E0024 // cipher message (KM)
+       BVS     loop        // branch back if interrupted
+       XOR     R0, R0
+       RET
index c5e02fe79b49be5b25652dc753fe8736b78500d5..fc2c4c52cf0c97c5c081b6da1f7fc5618d988e91 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !amd64
+// +build !amd64,!s390x
 
 package aes
 
diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go
new file mode 100644 (file)
index 0000000..dfb95d7
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2016 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"
+)
+
+type code int
+
+// Function codes for the cipher message family of instructions.
+const (
+       aes128 code = 18
+       aes192      = 19
+       aes256      = 20
+)
+
+type aesCipherAsm struct {
+       function code      // code for cipher message instruction
+       key      []byte    // key (128, 192 or 256 bytes)
+       storage  [256]byte // array backing key slice
+}
+
+// hasAsm reports whether the AES-128, AES-192 and AES-256
+// cipher message (KM) function codes are supported.
+// Note: this function call is expensive.
+func hasAsm() bool
+
+// cryptBlocks invokes the cipher message (KM) instruction with
+// the given function code. This is equivalent to AES in ECB
+// mode. The length must be a multiple of BlockSize (16).
+//go:noesape
+func cryptBlocks(c code, key, dst, src *byte, length int)
+
+var useAsm = hasAsm()
+
+func newCipher(key []byte) (cipher.Block, error) {
+       if !useAsm {
+               return newCipherGeneric(key)
+       }
+
+       var function code
+       switch len(key) {
+       case 128 / 8:
+               function = aes128
+       case 192 / 8:
+               function = aes192
+       case 256 / 8:
+               function = aes256
+       default:
+               return nil, KeySizeError(len(key))
+       }
+
+       var c aesCipherAsm
+       c.function = function
+       c.key = c.storage[:len(key)]
+       copy(c.key, key)
+       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")
+       }
+       cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+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")
+       }
+       // The decrypt function code is equal to the function code + 128.
+       cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
+}