target-arm: crypto: fix BE host support

The crypto emulation code in target-arm/crypto_helper.c never worked
correctly on big endian hosts, due to the fact that it uses a union
of array types to convert between the native VFP register size (64
bits) and the types used in the algorithms (bytes and 32 bit words)

We cannot just swab between LE and BE when reading and writing the
registers, as the SHA code performs word additions, so instead, add
array accessors for the CRYPTO_STATE type whose LE and BE specific
implementations ensure that the correct array elements are referenced.

Backports commit b449ca3c1874418d948878d5417a32fc0dbf9fea from qemu
This commit is contained in:
Ard Biesheuvel 2018-02-12 10:25:22 -05:00 committed by Lioncash
parent 912d271a9b
commit 9b28dc55c8
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7

View file

@ -22,6 +22,14 @@ union CRYPTO_STATE {
uint64_t l[2]; uint64_t l[2];
}; };
#ifdef HOST_WORDS_BIGENDIAN
#define CR_ST_BYTE(state, i) (state.bytes[(15 - (i)) ^ 8])
#define CR_ST_WORD(state, i) (state.words[(3 - (i)) ^ 2])
#else
#define CR_ST_BYTE(state, i) (state.bytes[i])
#define CR_ST_WORD(state, i) (state.words[i])
#endif
void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm, void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
uint32_t decrypt) uint32_t decrypt)
{ {
@ -45,7 +53,7 @@ void HELPER(crypto_aese)(CPUARMState *env, uint32_t rd, uint32_t rm,
/* combine ShiftRows operation and sbox substitution */ /* combine ShiftRows operation and sbox substitution */
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
st.bytes[i] = sbox[decrypt][rk.bytes[shift[decrypt][i]]]; CR_ST_BYTE(st, i) = sbox[decrypt][CR_ST_BYTE(rk, shift[decrypt][i])];
} }
env->vfp.regs[rd] = make_float64(st.l[0]); env->vfp.regs[rd] = make_float64(st.l[0]);
@ -196,11 +204,11 @@ void HELPER(crypto_aesmc)(CPUARMState *env, uint32_t rd, uint32_t rm,
assert(decrypt < 2); assert(decrypt < 2);
for (i = 0; i < 16; i += 4) { for (i = 0; i < 16; i += 4) {
st.words[i >> 2] = cpu_to_le32( CR_ST_WORD(st, i >> 2) =
mc[decrypt][st.bytes[i]] ^ mc[decrypt][CR_ST_BYTE(st, i)] ^
rol32(mc[decrypt][st.bytes[i + 1]], 8) ^ rol32(mc[decrypt][CR_ST_BYTE(st, i + 1)], 8) ^
rol32(mc[decrypt][st.bytes[i + 2]], 16) ^ rol32(mc[decrypt][CR_ST_BYTE(st, i + 2)], 16) ^
rol32(mc[decrypt][st.bytes[i + 3]], 24)); rol32(mc[decrypt][CR_ST_BYTE(st, i + 3)], 24);
} }
env->vfp.regs[rd] = make_float64(st.l[0]); env->vfp.regs[rd] = make_float64(st.l[0]);
@ -250,24 +258,25 @@ void HELPER(crypto_sha1_3reg)(CPUARMState *env, uint32_t rd, uint32_t rn,
switch (op) { switch (op) {
case 0: /* sha1c */ case 0: /* sha1c */
t = cho(d.words[1], d.words[2], d.words[3]); t = cho(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3));
break; break;
case 1: /* sha1p */ case 1: /* sha1p */
t = par(d.words[1], d.words[2], d.words[3]); t = par(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3));
break; break;
case 2: /* sha1m */ case 2: /* sha1m */
t = maj(d.words[1], d.words[2], d.words[3]); t = maj(CR_ST_WORD(d, 1), CR_ST_WORD(d, 2), CR_ST_WORD(d, 3));
break; break;
default: default:
g_assert_not_reached(); g_assert_not_reached();
} }
t += rol32(d.words[0], 5) + n.words[0] + m.words[i]; t += rol32(CR_ST_WORD(d, 0), 5) + CR_ST_WORD(n, 0)
+ CR_ST_WORD(m, i);
n.words[0] = d.words[3]; CR_ST_WORD(n, 0) = CR_ST_WORD(d, 3);
d.words[3] = d.words[2]; CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2);
d.words[2] = ror32(d.words[1], 2); CR_ST_WORD(d, 2) = ror32(CR_ST_WORD(d, 1), 2);
d.words[1] = d.words[0]; CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0);
d.words[0] = t; CR_ST_WORD(d, 0) = t;
} }
} }
env->vfp.regs[rd] = make_float64(d.l[0]); env->vfp.regs[rd] = make_float64(d.l[0]);
@ -280,8 +289,8 @@ void HELPER(crypto_sha1h)(CPUARMState *env, uint32_t rd, uint32_t rm)
m.l[0] = float64_val(env->vfp.regs[rm]); m.l[0] = float64_val(env->vfp.regs[rm]);
m.l[1] = float64_val(env->vfp.regs[rm + 1]); m.l[1] = float64_val(env->vfp.regs[rm + 1]);
m.words[0] = ror32(m.words[0], 2); CR_ST_WORD(m, 0) = ror32(CR_ST_WORD(m, 0), 2);
m.words[1] = m.words[2] = m.words[3] = 0; CR_ST_WORD(m, 1) = CR_ST_WORD(m, 2) = CR_ST_WORD(m, 3) = 0;
env->vfp.regs[rd] = make_float64(m.l[0]); env->vfp.regs[rd] = make_float64(m.l[0]);
env->vfp.regs[rd + 1] = make_float64(m.l[1]); env->vfp.regs[rd + 1] = make_float64(m.l[1]);
@ -296,10 +305,10 @@ void HELPER(crypto_sha1su1)(CPUARMState *env, uint32_t rd, uint32_t rm)
m.l[0] = float64_val(env->vfp.regs[rm]); m.l[0] = float64_val(env->vfp.regs[rm]);
m.l[1] = float64_val(env->vfp.regs[rm + 1]); m.l[1] = float64_val(env->vfp.regs[rm + 1]);
d.words[0] = rol32(d.words[0] ^ m.words[1], 1); CR_ST_WORD(d, 0) = rol32(CR_ST_WORD(d, 0) ^ CR_ST_WORD(m, 1), 1);
d.words[1] = rol32(d.words[1] ^ m.words[2], 1); CR_ST_WORD(d, 1) = rol32(CR_ST_WORD(d, 1) ^ CR_ST_WORD(m, 2), 1);
d.words[2] = rol32(d.words[2] ^ m.words[3], 1); CR_ST_WORD(d, 2) = rol32(CR_ST_WORD(d, 2) ^ CR_ST_WORD(m, 3), 1);
d.words[3] = rol32(d.words[3] ^ d.words[0], 1); CR_ST_WORD(d, 3) = rol32(CR_ST_WORD(d, 3) ^ CR_ST_WORD(d, 0), 1);
env->vfp.regs[rd] = make_float64(d.l[0]); env->vfp.regs[rd] = make_float64(d.l[0]);
env->vfp.regs[rd + 1] = make_float64(d.l[1]); env->vfp.regs[rd + 1] = make_float64(d.l[1]);
@ -345,20 +354,22 @@ void HELPER(crypto_sha256h)(CPUARMState *env, uint32_t rd, uint32_t rn,
m.l[1] = float64_val(env->vfp.regs[rm + 1]); m.l[1] = float64_val(env->vfp.regs[rm + 1]);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
uint32_t t = cho(n.words[0], n.words[1], n.words[2]) + n.words[3] uint32_t t = cho(CR_ST_WORD(n, 0), CR_ST_WORD(n, 1), CR_ST_WORD(n, 2))
+ S1(n.words[0]) + m.words[i]; + CR_ST_WORD(n, 3) + S1(CR_ST_WORD(n, 0))
+ CR_ST_WORD(m, i);
n.words[3] = n.words[2]; CR_ST_WORD(n, 3) = CR_ST_WORD(n, 2);
n.words[2] = n.words[1]; CR_ST_WORD(n, 2) = CR_ST_WORD(n, 1);
n.words[1] = n.words[0]; CR_ST_WORD(n, 1) = CR_ST_WORD(n, 0);
n.words[0] = d.words[3] + t; CR_ST_WORD(n, 0) = CR_ST_WORD(d, 3) + t;
t += maj(d.words[0], d.words[1], d.words[2]) + S0(d.words[0]); t += maj(CR_ST_WORD(d, 0), CR_ST_WORD(d, 1), CR_ST_WORD(d, 2))
+ S0(CR_ST_WORD(d, 0));
d.words[3] = d.words[2]; CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2);
d.words[2] = d.words[1]; CR_ST_WORD(d, 2) = CR_ST_WORD(d, 1);
d.words[1] = d.words[0]; CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0);
d.words[0] = t; CR_ST_WORD(d, 0) = t;
} }
env->vfp.regs[rd] = make_float64(d.l[0]); env->vfp.regs[rd] = make_float64(d.l[0]);
@ -381,13 +392,14 @@ void HELPER(crypto_sha256h2)(CPUARMState *env, uint32_t rd, uint32_t rn,
m.l[1] = float64_val(env->vfp.regs[rm + 1]); m.l[1] = float64_val(env->vfp.regs[rm + 1]);
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
uint32_t t = cho(d.words[0], d.words[1], d.words[2]) + d.words[3] uint32_t t = cho(CR_ST_WORD(d, 0), CR_ST_WORD(d, 1), CR_ST_WORD(d, 2))
+ S1(d.words[0]) + m.words[i]; + CR_ST_WORD(d, 3) + S1(CR_ST_WORD(d, 0))
+ CR_ST_WORD(m, i);
d.words[3] = d.words[2]; CR_ST_WORD(d, 3) = CR_ST_WORD(d, 2);
d.words[2] = d.words[1]; CR_ST_WORD(d, 2) = CR_ST_WORD(d, 1);
d.words[1] = d.words[0]; CR_ST_WORD(d, 1) = CR_ST_WORD(d, 0);
d.words[0] = n.words[3 - i] + t; CR_ST_WORD(d, 0) = CR_ST_WORD(n, 3 - i) + t;
} }
env->vfp.regs[rd] = make_float64(d.l[0]); env->vfp.regs[rd] = make_float64(d.l[0]);
@ -403,10 +415,10 @@ void HELPER(crypto_sha256su0)(CPUARMState *env, uint32_t rd, uint32_t rm)
m.l[0] = float64_val(env->vfp.regs[rm]); m.l[0] = float64_val(env->vfp.regs[rm]);
m.l[1] = float64_val(env->vfp.regs[rm + 1]); m.l[1] = float64_val(env->vfp.regs[rm + 1]);
d.words[0] += s0(d.words[1]); CR_ST_WORD(d, 0) += s0(CR_ST_WORD(d, 1));
d.words[1] += s0(d.words[2]); CR_ST_WORD(d, 1) += s0(CR_ST_WORD(d, 2));
d.words[2] += s0(d.words[3]); CR_ST_WORD(d, 2) += s0(CR_ST_WORD(d, 3));
d.words[3] += s0(m.words[0]); CR_ST_WORD(d, 3) += s0(CR_ST_WORD(m, 0));
env->vfp.regs[rd] = make_float64(d.l[0]); env->vfp.regs[rd] = make_float64(d.l[0]);
env->vfp.regs[rd + 1] = make_float64(d.l[1]); env->vfp.regs[rd + 1] = make_float64(d.l[1]);
@ -425,10 +437,10 @@ void HELPER(crypto_sha256su1)(CPUARMState *env, uint32_t rd, uint32_t rn,
m.l[0] = float64_val(env->vfp.regs[rm]); m.l[0] = float64_val(env->vfp.regs[rm]);
m.l[1] = float64_val(env->vfp.regs[rm + 1]); m.l[1] = float64_val(env->vfp.regs[rm + 1]);
d.words[0] += s1(m.words[2]) + n.words[1]; CR_ST_WORD(d, 0) += s1(CR_ST_WORD(m, 2)) + CR_ST_WORD(n, 1);
d.words[1] += s1(m.words[3]) + n.words[2]; CR_ST_WORD(d, 1) += s1(CR_ST_WORD(m, 3)) + CR_ST_WORD(n, 2);
d.words[2] += s1(d.words[0]) + n.words[3]; CR_ST_WORD(d, 2) += s1(CR_ST_WORD(d, 0)) + CR_ST_WORD(n, 3);
d.words[3] += s1(d.words[1]) + m.words[0]; CR_ST_WORD(d, 3) += s1(CR_ST_WORD(d, 1)) + CR_ST_WORD(m, 0);
env->vfp.regs[rd] = make_float64(d.l[0]); env->vfp.regs[rd] = make_float64(d.l[0]);
env->vfp.regs[rd + 1] = make_float64(d.l[1]); env->vfp.regs[rd + 1] = make_float64(d.l[1]);