diff --git a/src/crypto/aes/asm_s390x.s b/src/crypto/aes/asm_s390x.s new file mode 100644 index 0000000000..4a0720ca17 --- /dev/null +++ b/src/crypto/aes/asm_s390x.s @@ -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 diff --git a/src/crypto/aes/cipher_generic.go b/src/crypto/aes/cipher_generic.go index c5e02fe79b..fc2c4c52cf 100644 --- a/src/crypto/aes/cipher_generic.go +++ b/src/crypto/aes/cipher_generic.go @@ -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 index 0000000000..dfb95d7d5d --- /dev/null +++ b/src/crypto/aes/cipher_s390x.go @@ -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) +}