1/*
2 * Copyright 2001-2021 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    adat->plat.s390x.res = 0;
62    return 1;
63}
64
65static int s390x_aes_ofb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
66                                      const unsigned char *in, size_t len)
67{
68    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
69    int n = adat->plat.s390x.res;
70    int rem;
71
72    memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
73    while (n && len) {
74        *out = *in ^ adat->plat.s390x.param.kmo_kmf.cv[n];
75        n = (n + 1) & 0xf;
76        --len;
77        ++in;
78        ++out;
79    }
80
81    rem = len & 0xf;
82
83    len &= ~(size_t)0xf;
84    if (len) {
85        s390x_kmo(in, len, out, adat->plat.s390x.fc,
86                  &adat->plat.s390x.param.kmo_kmf);
87
88        out += len;
89        in += len;
90    }
91
92    if (rem) {
93        s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
94                 adat->plat.s390x.param.kmo_kmf.cv,
95                 adat->plat.s390x.fc,
96                 adat->plat.s390x.param.kmo_kmf.k);
97
98        while (rem--) {
99            out[n] = in[n] ^ adat->plat.s390x.param.kmo_kmf.cv[n];
100            ++n;
101        }
102    }
103
104    memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
105    adat->plat.s390x.res = n;
106    return 1;
107}
108
109static int s390x_aes_cfb128_initkey(PROV_CIPHER_CTX *dat,
110                                    const unsigned char *key, size_t keylen)
111{
112    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
113
114    adat->plat.s390x.fc = S390X_AES_FC(keylen);
115    adat->plat.s390x.fc |= 16 << 24;   /* 16 bytes cipher feedback */
116    adat->plat.s390x.res = 0;
117    memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
118    return 1;
119}
120
121static int s390x_aes_cfb128_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
122                                      const unsigned char *in, size_t len)
123{
124    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
125    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
126    int n = adat->plat.s390x.res;
127    int rem;
128    unsigned char tmp;
129
130    memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
131    while (n && len) {
132        tmp = *in;
133        *out = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp;
134        adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? *out : tmp;
135        n = (n + 1) & 0xf;
136        --len;
137        ++in;
138        ++out;
139    }
140
141    rem = len & 0xf;
142
143    len &= ~(size_t)0xf;
144    if (len) {
145        s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier,
146                  &adat->plat.s390x.param.kmo_kmf);
147
148        out += len;
149        in += len;
150    }
151
152    if (rem) {
153        s390x_km(adat->plat.s390x.param.kmo_kmf.cv, 16,
154                 adat->plat.s390x.param.kmo_kmf.cv,
155                 S390X_AES_FC(dat->keylen),
156                 adat->plat.s390x.param.kmo_kmf.k);
157
158        while (rem--) {
159            tmp = in[n];
160            out[n] = adat->plat.s390x.param.kmo_kmf.cv[n] ^ tmp;
161            adat->plat.s390x.param.kmo_kmf.cv[n] = dat->enc ? out[n] : tmp;
162            ++n;
163        }
164    }
165
166    memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
167    adat->plat.s390x.res = n;
168    return 1;
169}
170
171static int s390x_aes_cfb8_initkey(PROV_CIPHER_CTX *dat,
172                                  const unsigned char *key, size_t keylen)
173{
174    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
175
176    adat->plat.s390x.fc = S390X_AES_FC(keylen);
177    adat->plat.s390x.fc |= 1 << 24;   /* 1 byte cipher feedback */
178    memcpy(adat->plat.s390x.param.kmo_kmf.k, key, keylen);
179    return 1;
180}
181
182static int s390x_aes_cfb8_cipher_hw(PROV_CIPHER_CTX *dat, unsigned char *out,
183                                    const unsigned char *in, size_t len)
184{
185    PROV_AES_CTX *adat = (PROV_AES_CTX *)dat;
186    unsigned int modifier = adat->base.enc ? 0 : S390X_DECRYPT;
187
188    memcpy(adat->plat.s390x.param.kmo_kmf.cv, dat->iv, dat->ivlen);
189    s390x_kmf(in, len, out, adat->plat.s390x.fc | modifier,
190              &adat->plat.s390x.param.kmo_kmf);
191    memcpy(dat->iv, adat->plat.s390x.param.kmo_kmf.cv, dat->ivlen);
192    return 1;
193}
194
195#define PROV_CIPHER_HW_declare(mode)                                           \
196static const PROV_CIPHER_HW s390x_aes_##mode = {                               \
197    s390x_aes_##mode##_initkey,                                                \
198    s390x_aes_##mode##_cipher_hw,                                              \
199    cipher_hw_aes_copyctx                                                      \
200};
201#define PROV_CIPHER_HW_select(mode)                                            \
202if ((keybits == 128 && S390X_aes_128_##mode##_CAPABLE)                         \
203     || (keybits == 192 && S390X_aes_192_##mode##_CAPABLE)                     \
204     || (keybits == 256 && S390X_aes_256_##mode##_CAPABLE))                    \
205    return &s390x_aes_##mode;
206
207