POWER8 是基于 POWER 架构的一组超标量对称多处理器(super-scalar symmetric multiprocessor)。POWER8 系列增强了其加密功能,通过使用高级加密标准 (AES) 对称密钥加密标准实现了核心增强。
POWER8 AES 指令集提供了 5 个矢量指令来处理 AES 块密码加密/解密。POWER8 还为 Galois Field 中的乘法提供了一些指令,用于实现 Galois Counter Mode (GCM) 和 GHASH 算法[1]。
这篇文章将介绍这些加密指令,并提供一些简单的示例,以便说明如何使用这些指令在您的应用程序或驱动程序中实现 AES 或 AES 模式。
高级加密标准也被称为 Rijndael。它是作为电子数据的加密标准而建立的,由美国国立标准与技术研究院 (NIST) 于 2001 年建立。它是处理 16 字节/128 位的数据块的对称密钥算法。换句话说,它是一种数据块加密算法。128 位数据块适用于 128 位寄存器。此算法的密钥可以是 128、192 或 256 位长。POWER8 架构使您能够用 5 个指令实现 AES 算法,在 AES 算法核心(尤其是扩展密钥和围绕部分算法的 AES 加密/解密)中运行关键步骤。
POWER8 的增强功能之一就是实现综合的多管道矢量类型指令,该指令支持 32、128 位 VMX 矢量寄存器。矢量数据可以用不同的方式表示,如下表中所示。
qword | |||||||||||||||
dword | dword | ||||||||||||||
word | word | word | word | ||||||||||||
hword | hword | wword | hword | hword | hword | hword | hword | ||||||||
0x00 | 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0a | 0x0b | 0x0c | 0x0d | 0x0e | 0x0f |
* hword = 2 字节、word = 4 字节、dword = 8 字节、qword = 16 字节。
为了使用 AES,可以考虑使用完整的 16 字节向量,该向量可以在加密/解密步骤中处理最大的 AES 密钥或状态/密码文本。
AES 算法可分为以下步骤:
Key Expansion/Generate Round Keys 显示了一个算法概述。每个步骤都会在下面的各小节中进行介绍。
图 1. AES fluxogram
Key Expansion/Generate Round Keys 步骤从提供一个给定密钥开始,并将它扩展为多个密钥。128 位密钥被扩展为 11 个密钥。192 位密钥被扩展为 13 个密钥。256 位密钥被扩展为 15 个密钥。
第一个扩展的密钥是从初始密钥的最后一个单词中生成的,在生成一个单词的三个步骤中被处理,然后使用这个单词生成扩展密钥的所有 4 个单词。下一轮使用了前一轮生成的密钥中的最后一个单词。此过程一直重复,直到生成所有密钥。请记住,无论初始密钥的大小如何,AES 总是内部使用 16 字节的密钥。
Rotate Word (RotWord) 步骤处理一个单词并按以下方式旋转其字节:
字节 0 1 2 3 -> 1 2 3 0
示例:
给定一个单词:
79 d2 85 46
RotWord 步骤会生成以下结果:
d2 85 46 79
SubBytes 步骤使用了一个替换盒 (S-Box),使用 Galois Field GF(28) = GF(2)[x]/(x 8 +X 4 +x 3 +x+1)[2]中某个单词的乘法逆元来替代这个单词中的字节。在解密时,它使用了逆向 S-Box。
图 2. S-Box
点击查看大图
关闭 [x]
例如,在使用 S-Box 时,字节 0x9a
被 0xb8
替换。这一步是使用 vcipher 和 vcipherlast 指令在内部完成的。逆向 S-Box 操作是使用 vncipher 和 vncipherlast 指令在内部完成的。
例如,给定单词:
af 7f 67 98
SubBytes(word)operation 将会生成
79 d2 85 46
Rcon 或 Round Counter 步骤是某个用户指定值[3]的 2 的幂。在 AES 中,该值是整数。
所需 AES 轮次的数量取决于密钥的大小。对于 128 位密钥,AES 至多需要 rcon(10);对于 192 位密钥,至多需要 rcon(8);对于 256 位密钥,至多需要 rcon(7)。因此,对于所有 AES 可能性,我们需要保存 rcon 1 至 10:
Rcon(1-10) = 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
为了生成第一个扩展密钥,添加 rcon,然后我们继续处理密钥单词 Xor rcon(1) 或密钥单词 xor 01 00 00 00
。
以下是扩展密钥的工作原理的一个完整示例
Key: 0xac 0x2b 0x3c 0xdd 0xee 0x04 0x11 0x44 0xa1 0x4b 0x5c 0xd1 0x6a 0xb9 0x1c 0xdd Splitting key into words for the first key in key expand buffer: W0 = ac 2b 3c dd W1 = ee 04 11 44 W2 = a1 4b 5c d1 W3 = 6a b9 1c dd Key expand algorithm always uses the last word to execute steps, in our case W3: X1 <- RotWord(w3) X1 = b9 1c dd 6a Y1 <- SubBytes(X1) Y1 = 56 9c c1 02 Rcon(1) = 01 00 00 00 Z1 <- Y1 xor 01 00 00 00 Z1 = 57 9c c1 02 -------------------- Second key in key expand buffer: W4 = W0 xor Z1 = fb b7 fd df W5 = (W4 xor W1) = 15 b3 ec 9b W6 = (W5 xor W2) = b4 f8 b0 4a W7 = (W6 xor W3) = de 41 ac 97 ______________________________ X2 <- RodWord(W7) X2 = 41 ac 97 de Y2 <- SubBytes(X2) Y2 = 83 91 88 1d Rcon(2) = 02 00 00 00 Z2 <- Y2 xor 02 00 00 00 Z2 = 81 91 88 1d ------------------------------ Third key in key expand buffer: W8 = W4 xor z2 = 7a 26 75 c2 W9 = (W8 xor W5) = 6f 95 99 59 W10 = (W9 xor W6) = db 6d 29 13 W11 = (W10 xor W7) = 52 c8 58 40 (...)
现在让我们来了解如何使用 POWER8 向量和 AES 指令来创建扩展密钥。
首先,我们需要看看 AES 指令。如前面所述,P8 随带了 5 条 AES 指令: vcipher
、 vcipherlast
、 vncipher
、 vncipherlast
和 vsbox
。让我们重点关注前两个指令:
vcipher VRT,VRA,VRB State ← VR[VRA] RoundKey ← VR[VRB] vtemp1 ← SubBytes(State) vtemp2 ← ShiftRows(vtemp1) vtemp3 ← MixColumns(vtemp2) VR[VRT] ← vtemp3 ^ RoundKey
State
是本轮中的密码文本,甚至是 AES 的第一步中的纯文本。这两个值都是 16 字节或一个 AES 块大小。 RoundKey
,顾名思义,是本轮中的密钥。因为 VMX 向量是 16 字节,所有它们可以处理完整大小的轮次密钥和密文。
vcipherlast VRT,VRA,VRB State ←VR[VRA] RoundKey ← VR[VRB] vtemp1 ← SubBytes(State) vtemp2 ← ShiftRows(vtemp1) VR[VRT] ← vtemp2 ^ RoundKey
vcipherlast
与 vcipher
相同,除了它少一个步骤,即 MixColumns
。
vncipher
和 vncipherlast
与 vcipher
和 vcipherlast
完全相同,除了它们使用了反向步骤,而且是用于解密的。
Power8 没有用于 Key Expand 的特定指令。但 vcipherlast
,通过一些额外的步骤,可用来实现 Key Expand 操作。
下列步骤显示了一个如何使用 vcipherlast
来执行 Expand Key 操作的示例:
在此示例中,rcon 指针已经加载到一个向量中,您可能想要查看 vmx 加密驱动程序来获得更多信息[5]。此外还要注意的是,在 Power PC Assembly 代码中,寄存器是通过数字来引用的,而不是通过名称来引用的。例如,vperm 3,1,1,5 采用 vr3 作为寄存器结果,并使用 vr1 和 vr5 作为参数。有关的更多详细信息,请参见[4]。
/** * vr1 is the first key = 0xac 0x2b 0x3c 0xdd 0xee 0x04 0x11 0x44 0xa1 0x4b 0x5c 0xd1 0x6a 0xb9 0x1c 0xdd * vr5 is a mask to rotate a word in applied for all four words in our key. * vr5 = 0x0d0e0f0c 0d0e0f0c 0d0e0f0c 0d0e0f0c * vr3 is the key in use destination * vr4 is the first rcon loaded: 01 00 00 00 01 00 00 00 01 00 00 00 * 01 00 00 00 **/ Loop128: 1 vperm 3,1,1,5 2 vsldoi 6,0,1,12 3 vcipherlast 3,3,4 4 vxor 1,1,6 5 vsldoi 6,0,6,12 6 vxor 1,1,6 7 vsldoi 6,0,6,12 8 vxor 1,1,6 9 vadduwm 4,4,4 10 vxor 1,1,3 11 bdnz Loop128
第 1 行对密钥应用了一个掩码。在这里,vperm 指令 vr3 后面将会是:
0xb91cdd6a 0xb91cdd6a 0xb91cdd6a 0xb91cdd6a
第 2 行会导致:
0x0000000ac2b3cddee041144a14b5cd1
第 3 行调用 vcipherlast
来执行 SubBytes、 ShiftRows 和 xor Rcon(n)。通过在 Power ISA 2.07B[4]中定义 ShiftRows 函数,ShiftRows 在应用于此向量中时不起作用。在这个特定的场景中,它只执行 SubBytes 和 xor Rcon(n)。换句话说,它将生成第一个单词 Z 或 Z1。因此,在 vcipherlast
后面,我们有:
Z1: 0x579cc102 579cc102 579cc102 579cc102
第 4 到 8 行执行密钥扩展算法中密钥单词生成后面的公式。
W4 = (W0 xor Z1) W5 = (W1 xor W4) W6 = (W2 xor W5) W7 = (W3 xor W6)
这可以重写为:
W4' = W0 W5' = W1 xor W0 W6' = W2 xor W1 or W0 W7' = W3 xor W2 Xor W1 xor W0
其中的 '
意味着在 Z1 之前应用了一个临时单词。
第 4 至 8 行的详细操作如下:
W0 W1 W2 W3 vr1 0xac2b3cdd 0xee041144 0xa14b5cd1 0x6ab91cdd W0 W1 W2 w3 vr6 0x00000000 0xac2b3cdd 0xee041144 0xa14b5cd1 ------------------------------------------- W4' W5' temp-W6' temp-W7' vr1 0xac2b3cdd 0x422f2d99 0x4f4f4d95 0xcbf2400c W0 W1 vr6 0x00000000 0x00000000 0xac2b3cdd 0xee041144 ------------------------------------------- W4' W5' W6' temp-W7' vr1 0xac2b3cdd 0x422f2d99 0xe3647148 0x25f65148 W0 vr6 0x00000000 0x00000000 0x00000000 0xac2b3cdd ------------------------------------------- W4' W5' W6' W7' vr1 0xac2b3cdd 0x422f2d99 0xe3647148 0x89dd6d95
第 9 行为下一轮添加了 rcon:
vr4 02 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00
最后,第 10 行应用 Z1 单词生成了被扩展的第一个密钥。
W4' W5' W6' W7' vr1 0xac2b3cdd 0x422f2d99 0xe3647148 0x89dd6d95 Z1 Z1 Z1 Z1 vr3 0x579cc102 0x579cc102 0x579cc102 0x579cc102 ------------------------------------------- W4 W5 W6 W7 vr1 0xfbb7fddf 0x15b3ec9b 0xb4f8b04a 0xde41ac97
第 11 行跳回到了循环的开头处,根据所需的轮次数重复前面的所有步骤。
与 Key Expand 相比,AES 轮次非常简单,因为它们只需要扩展密钥以及加密或解密数据。
以下是一个演示了如何使用核心指令的简单示例。要获得更准确的代码示例,请参阅附录 A。
/** * vr0 is our state or the vector register where our * plaintext/point address resides. * vr1 is the key0 provided by the user or first key * vr2 is the second generated by expand key * vr3 is the third and so on till vr11 **/ 1 vxor 0,0,1 2 vcipher 0,0,2 3 vcipher 0,0,3 4 vcipher 0,0,4 5 vcipher 0,0,5 ... 11 vcipherlast 0,0,11
在第 1 行,key0 被添加到 AES 的初始状态。
第 2 行是具有 key1 的 AES 的第一轮。
第 3 行是 AES 的第二轮,依此类推。
第 11 是具有 last key10 的 AES 的最后一轮。
vmx 加密是支持针对 POWER8 的 AES 核心的内核驱动程序。最初,该驱动程序支持 CBC 和 CTR 模式下的 AES。它还支持 GHASH 算法。可以在 Kernel 4.1 及其更高版本中获得它。它同时提供了高位优先和低位优先功能。
要验证您的内核是否使用了 vmx 加密,可以运行: lsmod | grep vmx
。如果您的机器尚未使用它,您可以运行 modprobe vmx-crypto
,然后使用 lsmod
或者甚至 cat /proc/crypto | less
再次验证它,并寻找 p8 前缀。受驱动程序支持的算法/模式是:
名称:ghash
驱动程序:p8_ghash
模式:vmx_crypto
名称:aes
驱动程序:p8_aes
模式:vmx_crypto
名称:cbc(aes)
驱动程序:p8_aes_cbc
模式:vmx_crypto
名称:ctr(aes)
驱动程序:p8_aes_ctr
模式:vmx_crypto
很多项目使用 OpenSSL 作为其加密提供程序。从 OpenSSL 1.0.2 版开始,该代码通过使用核心 P8 指令实现了 SSL 加密。如果在正在运行的系统上启用此版本的 OpenSSL(及其更高版本),它会通过使用 VMX POWER8 汇编代码和硬件优化提供更高的性能。因为如此多的应用程序都在使用 Open SSL 实现加密,所以这个增强的 OpenSSL 支持各种应用,以便充分利用 POWER8 AES 指令。
POWER8 系统上的核心指令为您提供了实现加密堆栈的能力,它直接使用 POWER8 硬件的强大功能,帮助您的代码在密码基准测试上获得良好表现。
[1] Brian Hall; Ryan Arnold; Peter Bergner; Wainer dos Santos Moschetta; Robert Enenkel; Pat Haugen; Michael R. Meissner; Alex Mericas; Philipp Oehler; Berni Shiefer; Brian F. Veale; Suresh Warrier; Daniel Zabawa; Adhemerval Zanella. 针对 IBM Processors(包括 IBM POWER8)的性能优化和调优技术, 一本 IBM Redbooks 出版物,2014 年。
[2] G. David Forney,数字通信基本原理 II - 2005 年 3 月。有限域简介,2005 年。
[3] 联邦信息处理标准发布 – 宣布高级加密标准 – AES,2001 年。
[4] IBM. Power ISA 2.07B。矢量工具,2015. p.217. 可从以下网址获得: https://www.power.org/documentation/power-isa-v-2-07b/
[5] Cerri, M. VMX 加密驱动程序。可从以下网址获得: http://lxr.free-electrons.com/source/drivers/crypto/vmx/.
/** * vmx-crypto AES encrypt/OpenSSL aes encryption * At kernel: /drivers/crypto/vmx/aesp8-ppc.S * At OpenSSL: /crypto/aes/aesp8-ppc.s **/ .aes_p8_encrypt: lwz 6,240(5) lis 0,0xfc00 mfspr 12,256 li 7,15 mtspr 256,0 lvx 0,0,3 neg 11,4 lvx 1,7,3 lvsl 2,0,3 lvsl 3,0,11 li 7,16 vperm 0,0,1,2 lvx 1,0,5 lvsl 5,0,5 srwi 6,6,1 lvx 2,7,5 addi 7,7,16 subi 6,6,1 vperm 1,1,2,5 vxor 0,0,1 lvx 1,7,5 addi 7,7,16 mtctr 6 .Loop_enc: vperm 2,2,1,5 vcipher 0,0,2 lvx 2,7,5 addi 7,7,16 vperm 1,1,2,5 vcipher 0,0,1 lvx 1,7,5 addi 7,7,16 bdnz .Loop_enc vperm 2,2,1,5 vcipher 0,0,2 lvx 2,7,5 vperm 1,1,2,5 vcipherlast 0,0,1 vspltisb 2,-1 vxor 1,1,1 li 7,15 vperm 2,1,2,3 lvx 1,0,4 vperm 0,0,0,3 vsel 1,1,0,2 lvx 4,7,4 stvx 1,0,4 vsel 0,0,4,2 stvx 0,7,4 mtspr 256,12 blr /** * vmx-crypto AES decrypt * At kernel: /drivers/crypto/vmx/aesp8-ppc.S * At OpenSSL: /crypto/aes/aesp8-ppc.s **/ .aes_p8_decrypt: lwz 6,240(5) lis 0,0xfc00 mfspr 12,256 li 7,15 mtspr 256,0 lvx 0,0,3 neg 11,4 lvx 1,7,3 lvsl 2,0,3 lvsl 3,0,11 li 7,16 vperm 0,0,1,2 lvx 1,0,5 lvsl 5,0,5 srwi 6,6,1 lvx 2,7,5 addi 7,7,16 subi 6,6,1 vperm 1,1,2,5 vxor 0,0,1 lvx 1,7,5 addi 7,7,16 mtctr 6 .Loop_dec: vperm 2,2,1,5 vncipher 0,0,2 lvx 2,7,5 addi 7,7,16 vperm 1,1,2,5 vncipher 0,0,1 lvx 1,7,5 addi 7,7,16 bdnz .Loop_dec vperm 2,2,1,5 vncipher 0,0,2 lvx 2,7,5 vperm 1,1,2,5 vncipherlast 0,0,1 vspltisb 2,-1 vxor 1,1,1 li 7,15 vperm 2,1,2,3 lvx 1,0,4 vperm 0,0,0,3 vsel 1,1,0,2 lvx 4,7,4 stvx 1,0,4 vsel 0,0,4,2 stvx 0,7,4 mtspr 256,12 blr