1/*
2 * Copyright 2001-2022 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License").  You may not use
5 * this file except in compliance with the License.  You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10/*-
11 * PPC support for AES GCM.
12 * This file is included by cipher_aes_gcm_hw.c
13 */
14
15static int aes_ppc_gcm_initkey(PROV_GCM_CTX *ctx, const unsigned char *key,
16                               size_t keylen)
17{
18    PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx;
19    AES_KEY *ks = &actx->ks.ks;
20
21    GCM_HW_SET_KEY_CTR_FN(ks, aes_p8_set_encrypt_key, aes_p8_encrypt,
22                          aes_p8_ctr32_encrypt_blocks);
23    return 1;
24}
25
26static inline u32 UTO32(unsigned char *buf)
27{
28    return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) | ((u32) buf[2] << 8) | ((u32) buf[3]);
29}
30
31static inline u32 add32TOU(unsigned char buf[4], u32 n)
32{
33    u32 r;
34
35    r = UTO32(buf);
36    r += n;
37    buf[0] = (unsigned char) (r >> 24) & 0xFF;
38    buf[1] = (unsigned char) (r >> 16) & 0xFF;
39    buf[2] = (unsigned char) (r >> 8) & 0xFF;
40    buf[3] = (unsigned char) r & 0xFF;
41    return r;
42}
43
44static size_t ppc_aes_gcm_crypt(const unsigned char *in, unsigned char *out, size_t len,
45                                const void *key, unsigned char ivec[16], u64 *Xi, int encrypt)
46{
47    int s = 0;
48    int ndone = 0;
49    int ctr_reset = 0;
50    u64 blocks_unused;
51    u64 nb = len / 16;
52    u64 next_ctr = 0;
53    unsigned char ctr_saved[12];
54
55    memcpy(ctr_saved, ivec, 12);
56
57    while (nb) {
58        blocks_unused = (u64) 0xffffffffU + 1 - (u64) UTO32 (ivec + 12);
59        if (nb > blocks_unused) {
60            len = blocks_unused * 16;
61            nb -= blocks_unused;
62            next_ctr = blocks_unused;
63            ctr_reset = 1;
64        } else {
65            len = nb * 16;
66            next_ctr = nb;
67            nb = 0;
68        }
69
70        s = encrypt ? ppc_aes_gcm_encrypt(in, out, len, key, ivec, Xi)
71                    : ppc_aes_gcm_decrypt(in, out, len, key, ivec, Xi);
72
73        /* add counter to ivec */
74        add32TOU(ivec + 12, (u32) next_ctr);
75        if (ctr_reset) {
76            ctr_reset = 0;
77            in += len;
78            out += len;
79        }
80        memcpy(ivec, ctr_saved, 12);
81        ndone += s;
82    }
83
84    return ndone;
85}
86
87static int ppc_aes_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in,
88                                     size_t len, unsigned char *out)
89{
90    if (ctx->enc) {
91        if (ctx->ctr != NULL) {
92            size_t bulk = 0;
93
94            if (len >= AES_GCM_ENC_BYTES && AES_GCM_ASM_PPC(ctx)) {
95                size_t res = (16 - ctx->gcm.mres) % 16;
96
97                if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, res))
98                    return 0;
99
100                bulk = ppc_aes_gcm_crypt(in + res, out + res, len - res,
101                                         ctx->gcm.key,
102                                         ctx->gcm.Yi.c, ctx->gcm.Xi.u, 1);
103
104                ctx->gcm.len.u[1] += bulk;
105                bulk += res;
106            }
107            if (CRYPTO_gcm128_encrypt_ctr32(&ctx->gcm, in + bulk, out + bulk,
108                                            len - bulk, ctx->ctr))
109                return 0;
110        } else {
111            if (CRYPTO_gcm128_encrypt(&ctx->gcm, in, out, len))
112                return 0;
113        }
114    } else {
115        if (ctx->ctr != NULL) {
116            size_t bulk = 0;
117
118            if (len >= AES_GCM_DEC_BYTES && AES_GCM_ASM_PPC(ctx)) {
119                size_t res = (16 - ctx->gcm.mres) % 16;
120
121                if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, res))
122                    return -1;
123
124                bulk = ppc_aes_gcm_crypt(in + res, out + res, len - res,
125                                         ctx->gcm.key,
126                                         ctx->gcm.Yi.c, ctx->gcm.Xi.u, 0);
127
128                ctx->gcm.len.u[1] += bulk;
129                bulk += res;
130            }
131            if (CRYPTO_gcm128_decrypt_ctr32(&ctx->gcm, in + bulk, out + bulk,
132                                            len - bulk, ctx->ctr))
133                return 0;
134        } else {
135            if (CRYPTO_gcm128_decrypt(&ctx->gcm, in, out, len))
136                return 0;
137        }
138    }
139    return 1;
140}
141
142static const PROV_GCM_HW aes_ppc_gcm = {
143    aes_ppc_gcm_initkey,
144    ossl_gcm_setiv,
145    ossl_gcm_aad_update,
146    ppc_aes_gcm_cipher_update,
147    ossl_gcm_cipher_final,
148    ossl_gcm_one_shot
149};
150
151const PROV_GCM_HW *ossl_prov_aes_hw_gcm(size_t keybits)
152{
153    return PPC_AES_GCM_CAPABLE ? &aes_ppc_gcm : &aes_gcm;
154}
155
156