blob: 4980d419c43906e72fc24f59cbcd0d15dfef1ef6 [file] [log] [blame]
Longpeng(Mike)25c60df2017-07-14 14:04:06 -04001/*
2 * QEMU Crypto af_alg-backend cipher support
3 *
4 * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
5 *
6 * Authors:
7 * Longpeng(Mike) <longpeng2@huawei.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or
10 * (at your option) any later version. See the COPYING file in the
11 * top-level directory.
12 */
13#include "qemu/osdep.h"
14#include "qemu/sockets.h"
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040015#include "qapi/error.h"
16#include "crypto/cipher.h"
17#include "cipherpriv.h"
18
19
20static char *
Markus Armbrustera092c512024-09-04 13:18:29 +020021qcrypto_afalg_cipher_format_name(QCryptoCipherAlgo alg,
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040022 QCryptoCipherMode mode,
23 Error **errp)
24{
25 char *name;
26 const char *alg_name;
27 const char *mode_name;
28
29 switch (alg) {
Markus Armbrustera092c512024-09-04 13:18:29 +020030 case QCRYPTO_CIPHER_ALGO_AES_128:
31 case QCRYPTO_CIPHER_ALGO_AES_192:
32 case QCRYPTO_CIPHER_ALGO_AES_256:
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040033 alg_name = "aes";
34 break;
Markus Armbrustera092c512024-09-04 13:18:29 +020035 case QCRYPTO_CIPHER_ALGO_CAST5_128:
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040036 alg_name = "cast5";
37 break;
Markus Armbrustera092c512024-09-04 13:18:29 +020038 case QCRYPTO_CIPHER_ALGO_SERPENT_128:
39 case QCRYPTO_CIPHER_ALGO_SERPENT_192:
40 case QCRYPTO_CIPHER_ALGO_SERPENT_256:
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040041 alg_name = "serpent";
42 break;
Markus Armbrustera092c512024-09-04 13:18:29 +020043 case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
44 case QCRYPTO_CIPHER_ALGO_TWOFISH_192:
45 case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040046 alg_name = "twofish";
47 break;
48
49 default:
50 error_setg(errp, "Unsupported cipher algorithm %d", alg);
51 return NULL;
52 }
53
Markus Armbruster977c7362017-08-24 10:46:08 +020054 mode_name = QCryptoCipherMode_str(mode);
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040055 name = g_strdup_printf("%s(%s)", mode_name, alg_name);
56
57 return name;
58}
59
Richard Hendersonda30cd72020-08-28 10:05:15 -070060static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
61
Richard Henderson3eedf5c2020-08-28 10:05:14 -070062QCryptoCipher *
Markus Armbrustera092c512024-09-04 13:18:29 +020063qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgo alg,
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040064 QCryptoCipherMode mode,
65 const uint8_t *key,
66 size_t nkey, Error **errp)
67{
Markus Armbruster8f525022024-09-04 13:18:33 +020068 QCryptoAFAlgo *afalg;
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040069 size_t expect_niv;
70 char *name;
71
72 name = qcrypto_afalg_cipher_format_name(alg, mode, errp);
73 if (!name) {
74 return NULL;
75 }
76
77 afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp);
78 if (!afalg) {
79 g_free(name);
80 return NULL;
81 }
82
83 g_free(name);
84
85 /* setkey */
Marc-André Lureaue7b79422022-02-19 01:34:50 +040086 if (setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key,
87 nkey) != 0) {
Longpeng(Mike)25c60df2017-07-14 14:04:06 -040088 error_setg_errno(errp, errno, "Set key failed");
89 qcrypto_afalg_comm_free(afalg);
90 return NULL;
91 }
92
93 /* prepare msg header */
94 afalg->msg = g_new0(struct msghdr, 1);
95 afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN);
96 expect_niv = qcrypto_cipher_get_iv_len(alg, mode);
97 if (expect_niv) {
98 afalg->msg->msg_controllen += CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
99 }
100 afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen);
101
102 /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */
103 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
104 afalg->cmsg->cmsg_type = ALG_SET_OP;
105 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN);
106 if (expect_niv) {
107 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
108 afalg->cmsg->cmsg_type = ALG_SET_IV;
109 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
110 }
111 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
112
Richard Hendersonda30cd72020-08-28 10:05:15 -0700113 afalg->base.driver = &qcrypto_cipher_afalg_driver;
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700114 return &afalg->base;
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400115}
116
117static int
118qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
119 const uint8_t *iv,
120 size_t niv, Error **errp)
121{
Markus Armbruster8f525022024-09-04 13:18:33 +0200122 QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400123 struct af_alg_iv *alg_iv;
124 size_t expect_niv;
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400125
126 expect_niv = qcrypto_cipher_get_iv_len(cipher->alg, cipher->mode);
127 if (niv != expect_niv) {
128 error_setg(errp, "Set IV len(%zu) not match expected(%zu)",
129 niv, expect_niv);
130 return -1;
131 }
132
133 /* move ->cmsg to next msghdr, for IV-info */
134 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
135
136 /* build setiv msg */
137 afalg->cmsg->cmsg_level = SOL_ALG;
138 alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg);
139 alg_iv->ivlen = niv;
140 memcpy(alg_iv->iv, iv, niv);
141
142 return 0;
143}
144
145static int
Markus Armbruster8f525022024-09-04 13:18:33 +0200146qcrypto_afalg_cipher_op(QCryptoAFAlgo *afalg,
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400147 const void *in, void *out,
148 size_t len, bool do_encrypt,
149 Error **errp)
150{
151 uint32_t *type = NULL;
152 struct iovec iov;
153 size_t ret, rlen, done = 0;
154 uint32_t origin_controllen;
155
156 origin_controllen = afalg->msg->msg_controllen;
157 /* movev ->cmsg to first header, for crypto-info */
158 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
159
160 /* build encrypt msg */
161 afalg->cmsg->cmsg_level = SOL_ALG;
162 afalg->msg->msg_iov = &iov;
163 afalg->msg->msg_iovlen = 1;
164 type = (uint32_t *)CMSG_DATA(afalg->cmsg);
165 if (do_encrypt) {
166 *type = ALG_OP_ENCRYPT;
167 } else {
168 *type = ALG_OP_DECRYPT;
169 }
170
171 do {
172 iov.iov_base = (void *)in + done;
173 iov.iov_len = len - done;
174
175 /* send info to AF_ALG core */
176 ret = sendmsg(afalg->opfd, afalg->msg, 0);
177 if (ret == -1) {
178 error_setg_errno(errp, errno, "Send data to AF_ALG core failed");
179 return -1;
180 }
181
182 /* encrypto && get result */
183 rlen = read(afalg->opfd, out, ret);
184 if (rlen == -1) {
185 error_setg_errno(errp, errno, "Get result from AF_ALG core failed");
186 return -1;
187 }
188 assert(rlen == ret);
189
190 /* do not update IV for following chunks */
191 afalg->msg->msg_controllen = 0;
192 done += ret;
193 } while (done < len);
194
195 afalg->msg->msg_controllen = origin_controllen;
196
197 return 0;
198}
199
200static int
201qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
202 const void *in, void *out,
203 size_t len, Error **errp)
204{
Markus Armbruster8f525022024-09-04 13:18:33 +0200205 QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700206
207 return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400208}
209
210static int
211qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
212 const void *in, void *out,
213 size_t len, Error **errp)
214{
Markus Armbruster8f525022024-09-04 13:18:33 +0200215 QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700216
217 return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400218}
219
220static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
221{
Markus Armbruster8f525022024-09-04 13:18:33 +0200222 QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
Richard Henderson3eedf5c2020-08-28 10:05:14 -0700223
224 qcrypto_afalg_comm_free(afalg);
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400225}
226
Richard Hendersonda30cd72020-08-28 10:05:15 -0700227static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
Longpeng(Mike)25c60df2017-07-14 14:04:06 -0400228 .cipher_encrypt = qcrypto_afalg_cipher_encrypt,
229 .cipher_decrypt = qcrypto_afalg_cipher_decrypt,
230 .cipher_setiv = qcrypto_afalg_cipher_setiv,
231 .cipher_free = qcrypto_afalg_comm_ctx_free,
232};