Merge remote-tracking branch 'remotes/dgilbert-gitlab/tags/pull-migration-20210726a...
[qemu/armbru.git] / crypto / cipher-afalg.c
blob052355a8a9219be6bca07ce10ee5b282af7665a6
1 /*
2 * QEMU Crypto af_alg-backend cipher support
4 * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
6 * Authors:
7 * Longpeng(Mike) <longpeng2@huawei.com>
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.
13 #include "qemu/osdep.h"
14 #include "qemu/sockets.h"
15 #include "qemu-common.h"
16 #include "qapi/error.h"
17 #include "crypto/cipher.h"
18 #include "cipherpriv.h"
21 static char *
22 qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
23 QCryptoCipherMode mode,
24 Error **errp)
26 char *name;
27 const char *alg_name;
28 const char *mode_name;
30 switch (alg) {
31 case QCRYPTO_CIPHER_ALG_AES_128:
32 case QCRYPTO_CIPHER_ALG_AES_192:
33 case QCRYPTO_CIPHER_ALG_AES_256:
34 alg_name = "aes";
35 break;
36 case QCRYPTO_CIPHER_ALG_CAST5_128:
37 alg_name = "cast5";
38 break;
39 case QCRYPTO_CIPHER_ALG_SERPENT_128:
40 case QCRYPTO_CIPHER_ALG_SERPENT_192:
41 case QCRYPTO_CIPHER_ALG_SERPENT_256:
42 alg_name = "serpent";
43 break;
44 case QCRYPTO_CIPHER_ALG_TWOFISH_128:
45 case QCRYPTO_CIPHER_ALG_TWOFISH_192:
46 case QCRYPTO_CIPHER_ALG_TWOFISH_256:
47 alg_name = "twofish";
48 break;
50 default:
51 error_setg(errp, "Unsupported cipher algorithm %d", alg);
52 return NULL;
55 mode_name = QCryptoCipherMode_str(mode);
56 name = g_strdup_printf("%s(%s)", mode_name, alg_name);
58 return name;
61 static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
63 QCryptoCipher *
64 qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
65 QCryptoCipherMode mode,
66 const uint8_t *key,
67 size_t nkey, Error **errp)
69 QCryptoAFAlg *afalg;
70 size_t expect_niv;
71 char *name;
73 name = qcrypto_afalg_cipher_format_name(alg, mode, errp);
74 if (!name) {
75 return NULL;
78 afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp);
79 if (!afalg) {
80 g_free(name);
81 return NULL;
84 g_free(name);
86 /* setkey */
87 if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key,
88 nkey) != 0) {
89 error_setg_errno(errp, errno, "Set key failed");
90 qcrypto_afalg_comm_free(afalg);
91 return NULL;
94 /* prepare msg header */
95 afalg->msg = g_new0(struct msghdr, 1);
96 afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN);
97 expect_niv = qcrypto_cipher_get_iv_len(alg, mode);
98 if (expect_niv) {
99 afalg->msg->msg_controllen += CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
101 afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen);
103 /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */
104 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
105 afalg->cmsg->cmsg_type = ALG_SET_OP;
106 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN);
107 if (expect_niv) {
108 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
109 afalg->cmsg->cmsg_type = ALG_SET_IV;
110 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
112 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
114 afalg->base.driver = &qcrypto_cipher_afalg_driver;
115 return &afalg->base;
118 static int
119 qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
120 const uint8_t *iv,
121 size_t niv, Error **errp)
123 QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
124 struct af_alg_iv *alg_iv;
125 size_t expect_niv;
127 expect_niv = qcrypto_cipher_get_iv_len(cipher->alg, cipher->mode);
128 if (niv != expect_niv) {
129 error_setg(errp, "Set IV len(%zu) not match expected(%zu)",
130 niv, expect_niv);
131 return -1;
134 /* move ->cmsg to next msghdr, for IV-info */
135 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
137 /* build setiv msg */
138 afalg->cmsg->cmsg_level = SOL_ALG;
139 alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg);
140 alg_iv->ivlen = niv;
141 memcpy(alg_iv->iv, iv, niv);
143 return 0;
146 static int
147 qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg,
148 const void *in, void *out,
149 size_t len, bool do_encrypt,
150 Error **errp)
152 uint32_t *type = NULL;
153 struct iovec iov;
154 size_t ret, rlen, done = 0;
155 uint32_t origin_controllen;
157 origin_controllen = afalg->msg->msg_controllen;
158 /* movev ->cmsg to first header, for crypto-info */
159 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
161 /* build encrypt msg */
162 afalg->cmsg->cmsg_level = SOL_ALG;
163 afalg->msg->msg_iov = &iov;
164 afalg->msg->msg_iovlen = 1;
165 type = (uint32_t *)CMSG_DATA(afalg->cmsg);
166 if (do_encrypt) {
167 *type = ALG_OP_ENCRYPT;
168 } else {
169 *type = ALG_OP_DECRYPT;
172 do {
173 iov.iov_base = (void *)in + done;
174 iov.iov_len = len - done;
176 /* send info to AF_ALG core */
177 ret = sendmsg(afalg->opfd, afalg->msg, 0);
178 if (ret == -1) {
179 error_setg_errno(errp, errno, "Send data to AF_ALG core failed");
180 return -1;
183 /* encrypto && get result */
184 rlen = read(afalg->opfd, out, ret);
185 if (rlen == -1) {
186 error_setg_errno(errp, errno, "Get result from AF_ALG core failed");
187 return -1;
189 assert(rlen == ret);
191 /* do not update IV for following chunks */
192 afalg->msg->msg_controllen = 0;
193 done += ret;
194 } while (done < len);
196 afalg->msg->msg_controllen = origin_controllen;
198 return 0;
201 static int
202 qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
203 const void *in, void *out,
204 size_t len, Error **errp)
206 QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
208 return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
211 static int
212 qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
213 const void *in, void *out,
214 size_t len, Error **errp)
216 QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
218 return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
221 static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
223 QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
225 qcrypto_afalg_comm_free(afalg);
228 static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
229 .cipher_encrypt = qcrypto_afalg_cipher_encrypt,
230 .cipher_decrypt = qcrypto_afalg_cipher_decrypt,
231 .cipher_setiv = qcrypto_afalg_cipher_setiv,
232 .cipher_free = qcrypto_afalg_comm_ctx_free,