1/*
2 * Copyright 2001-2024 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 * IBM S390X support for AES modes ecb, cbc, ofb, cfb, ctr.
12 * This file is included by cipher_aes_hw.c
13 */
14
15#include "s390x_arch.h"
16
17#include <stdio.h>
18
19#define s390x_aes_cbc_initkey    cipher_hw_aes_initkey
20#define s390x_aes_cfb1_initkey   cipher_hw_aes_initkey
21#define s390x_aes_ctr_initkey    cipher_hw_aes_initkey
22#define s390x_aes_cbc_cipher_hw  ossl_cipher_hw_generic_cbc
23#define s390x_aes_cfb1_cipher_hw ossl_cipher_hw_generic_cfb1
24#define s390x_aes_ctr_cipher_hw  ossl_cipher_hw_generic_ctr
25
26#define S390X_aes_128_ofb128_CAPABLE S390X_aes_128_ofb_CAPABLE
27#define S390X_aes_192_ofb128_CAPABLE S390X_aes_192_ofb_CAPABLE
28#define S390X_aes_256_ofb128_CAPABLE S390X_aes_256_ofb_CAPABLE
29#define S390X_aes_128_cfb128_CAPABLE S390X_aes_128_cfb_CAPABLE
30#define S390X_aes_192_cfb128_CAPABLE S390X_aes_192_cfb_CAPABLE
31#define S390X_aes_256_cfb128_CAPABLE S390X_aes_256_cfb_CAPABLE
32
33static int s390x_aes_ecb_initkey(PROV_CIPHER_CTX *dat,
34                                 const unsigned char *key, size_t keylen)
35{
36    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
37
38    adat->plat.s390x.fc = S390X_AES_FC(keylen);
39    memcpy(adat->plat.s390x.param.km.k, key, keylen);
40    return 1;
41}
42
43static int s390x_aes_ecb_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
44                                   const unsigned char *in, size_t len)
45{
46    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
47    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
48
49    s390x_km(in, len, out, adat->plat.s390x.fc | modifier,
50             &adat->plat.s390x.param.km);
51    return 1;
52}
53
54static int s390x_aes_ofb128_initkey(PROV_CIPHER_CTX *dat,
55                                    const unsigned char *key, size_t keylen)
56{
57    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
58
59    memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
60    adat->plat.s390x.fc = S390X_AES_FC(keylen);
61    return 1;
62}
63
64static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
65                                      const unsigned char *in, size_t len)
66{
67    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
68    int n = dat->num;
69    int rem;
70
71    memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
72    while (n && len) {
73        *out = *in ^ adat->plat.s390x.param.kmo_kmf.cv[n];
74        n = (n + 1) & 0xf;
75        --len;
76        ++in;
77        ++out;
78    }
79
80    rem = len & 0xf;
81
82    len &= ~(size_t)0xf;
83    if (len) {
84        s390x_kmo(in, len, out, adat->plat.s390x.fc,
85                  &adat->plat.s390x.param.kmo_kmf);
86
87        out += len;
88        in += len;
89    }
90
91    if (rem) {
92        s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
93                 adat->plat.s390x.param.kmo_kmf.cv,
94                 adat->plat.s390x.fc,
95                 adat->plat.s390x.param.kmo_kmf.k);
96
97        while (rem--) {
98            out[n] = in[n] ^ adat->plat.s390x.param.kmo_kmf.cv[n];
99            ++n;
100        }
101    }
102
103    memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
104    dat->num = n;
105    return 1;
106}
107
108static int s390x_aes_cfb128_initkey(PROV_CIPHER_CTX *dat,
109                                    const unsigned char *key, size_t keylen)
110{
111    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
112
113    adat->plat.s390x.fc = S390X_AES_FC(keylen);
114    adat->plat.s390x.fc |= 16 << 24;   /* 16 bytes cipher feedback */
115    memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
116    return 1;
117}
118
119static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
120                                      const unsigned char *in, size_t len)
121{
122    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
123    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
124    int n = dat->num;
125    int rem;
126    unsigned char tmp;
127
128    memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
129    while (n && len) {
130        tmp = *in;
131        *out = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp;
132        adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? *out : tmp;
133        n = (n + 1) & 0xf;
134        --len;
135        ++in;
136        ++out;
137    }
138
139    rem = len & 0xf;
140
141    len &= ~(size_t)0xf;
142    if (len) {
143        s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier,
144                  &adat->plat.s390x.param.kmo_kmf);
145
146        out += len;
147        in += len;
148    }
149
150    if (rem) {
151        s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
152                 adat->plat.s390x.param.kmo_kmf.cv,
153                 S390X_AES_FC(dat->keylen),
154                 adat->plat.s390x.param.kmo_kmf.k);
155
156        while (rem--) {
157            tmp = in[n];
158            out[n] = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp;
159            adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? out[n] : tmp;
160            ++n;
161        }
162    }
163
164    memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
165    dat->num = n;
166    return 1;
167}
168
169static int s390x_aes_cfb8_initkey(PROV_CIPHER_CTX *dat,
170                                  const unsigned char *key, size_t keylen)
171{
172    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
173
174    adat->plat.s390x.fc = S390X_AES_FC(keylen);
175    adat->plat.s390x.fc |= 1 << 24;   /* 1 byte cipher feedback */
176    memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
177    return 1;
178}
179
180static int s390x_aes_cfb8_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
181                                    const unsigned char *in, size_t len)
182{
183    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
184    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
185
186    memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
187    s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier,
188              &adat->plat.s390x.param.kmo_kmf);
189    memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
190    return 1;
191}
192
193#define PROV_CIPHER_HW_declare(mode)                                           \
194static const PROV_CIPHER_HW s390x_aes_##mode = {                               \
195    s390x_aes_##mode##_initkey,                                                \
196    s390x_aes_##mode##_cipher_hw,                                              \
197    cipher_hw_aes_copyctx                                                      \
198};
199#define PROV_CIPHER_HW_select(mode)                                            \
200if ((keybits == 128 && S390X_aes_128_##mode##_CAPABLE)                         \
201     || (keybits == 192 && S390X_aes_192_##mode##_CAPABLE)                     \
202     || (keybits == 256 && S390X_aes_256_##mode##_CAPABLE))                    \
203    return &s390x_aes_##mode;
204
205