qxl: check release info object
[qemu.git] / crypto / cipher-afalg.c
1 /*
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"
15 #include "qemu-common.h"
16 #include "qapi/error.h"
17 #include "crypto/cipher.h"
18 #include "cipherpriv.h"
19
20
21 static char *
22 qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
23 QCryptoCipherMode mode,
24 Error **errp)
25 {
26 char *name;
27 const char *alg_name;
28 const char *mode_name;
29
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;
49
50 default:
51 error_setg(errp, "Unsupported cipher algorithm %d", alg);
52 return NULL;
53 }
54
55 mode_name = QCryptoCipherMode_str(mode);
56 name = g_strdup_printf("%s(%s)", mode_name, alg_name);
57
58 return name;
59 }
60
61 QCryptoAFAlg *
62 qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
63 QCryptoCipherMode mode,
64 const uint8_t *key,
65 size_t nkey, Error **errp)
66 {
67 QCryptoAFAlg *afalg;
68 size_t expect_niv;
69 char *name;
70
71 name = qcrypto_afalg_cipher_format_name(alg, mode, errp);
72 if (!name) {
73 return NULL;
74 }
75
76 afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp);
77 if (!afalg) {
78 g_free(name);
79 return NULL;
80 }
81
82 g_free(name);
83
84 /* setkey */
85 if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key,
86 nkey) != 0) {
87 error_setg_errno(errp, errno, "Set key failed");
88 qcrypto_afalg_comm_free(afalg);
89 return NULL;
90 }
91
92 /* prepare msg header */
93 afalg->msg = g_new0(struct msghdr, 1);
94 afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN);
95 expect_niv = qcrypto_cipher_get_iv_len(alg, mode);
96 if (expect_niv) {
97 afalg->msg->msg_controllen += CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
98 }
99 afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen);
100
101 /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */
102 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
103 afalg->cmsg->cmsg_type = ALG_SET_OP;
104 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN);
105 if (expect_niv) {
106 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
107 afalg->cmsg->cmsg_type = ALG_SET_IV;
108 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
109 }
110 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
111
112 return afalg;
113 }
114
115 static int
116 qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
117 const uint8_t *iv,
118 size_t niv, Error **errp)
119 {
120 struct af_alg_iv *alg_iv;
121 size_t expect_niv;
122 QCryptoAFAlg *afalg = cipher->opaque;
123
124 expect_niv = qcrypto_cipher_get_iv_len(cipher->alg, cipher->mode);
125 if (niv != expect_niv) {
126 error_setg(errp, "Set IV len(%zu) not match expected(%zu)",
127 niv, expect_niv);
128 return -1;
129 }
130
131 /* move ->cmsg to next msghdr, for IV-info */
132 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
133
134 /* build setiv msg */
135 afalg->cmsg->cmsg_level = SOL_ALG;
136 alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg);
137 alg_iv->ivlen = niv;
138 memcpy(alg_iv->iv, iv, niv);
139
140 return 0;
141 }
142
143 static int
144 qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg,
145 const void *in, void *out,
146 size_t len, bool do_encrypt,
147 Error **errp)
148 {
149 uint32_t *type = NULL;
150 struct iovec iov;
151 size_t ret, rlen, done = 0;
152 uint32_t origin_controllen;
153
154 origin_controllen = afalg->msg->msg_controllen;
155 /* movev ->cmsg to first header, for crypto-info */
156 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
157
158 /* build encrypt msg */
159 afalg->cmsg->cmsg_level = SOL_ALG;
160 afalg->msg->msg_iov = &iov;
161 afalg->msg->msg_iovlen = 1;
162 type = (uint32_t *)CMSG_DATA(afalg->cmsg);
163 if (do_encrypt) {
164 *type = ALG_OP_ENCRYPT;
165 } else {
166 *type = ALG_OP_DECRYPT;
167 }
168
169 do {
170 iov.iov_base = (void *)in + done;
171 iov.iov_len = len - done;
172
173 /* send info to AF_ALG core */
174 ret = sendmsg(afalg->opfd, afalg->msg, 0);
175 if (ret == -1) {
176 error_setg_errno(errp, errno, "Send data to AF_ALG core failed");
177 return -1;
178 }
179
180 /* encrypto && get result */
181 rlen = read(afalg->opfd, out, ret);
182 if (rlen == -1) {
183 error_setg_errno(errp, errno, "Get result from AF_ALG core failed");
184 return -1;
185 }
186 assert(rlen == ret);
187
188 /* do not update IV for following chunks */
189 afalg->msg->msg_controllen = 0;
190 done += ret;
191 } while (done < len);
192
193 afalg->msg->msg_controllen = origin_controllen;
194
195 return 0;
196 }
197
198 static int
199 qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
200 const void *in, void *out,
201 size_t len, Error **errp)
202 {
203 return qcrypto_afalg_cipher_op(cipher->opaque, in, out,
204 len, true, errp);
205 }
206
207 static int
208 qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
209 const void *in, void *out,
210 size_t len, Error **errp)
211 {
212 return qcrypto_afalg_cipher_op(cipher->opaque, in, out,
213 len, false, errp);
214 }
215
216 static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
217 {
218 qcrypto_afalg_comm_free(cipher->opaque);
219 }
220
221 struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
222 .cipher_encrypt = qcrypto_afalg_cipher_encrypt,
223 .cipher_decrypt = qcrypto_afalg_cipher_decrypt,
224 .cipher_setiv = qcrypto_afalg_cipher_setiv,
225 .cipher_free = qcrypto_afalg_comm_ctx_free,
226 };