1
2
3
4
5
6
7
8
9
10
11
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
21static char *
22qcrypto_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
61QCryptoAFAlg *
62qcrypto_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
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
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
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
115static int
116qcrypto_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
132 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
133
134
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
143static int
144qcrypto_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
156 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
157
158
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
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
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
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
198static int
199qcrypto_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
207static int
208qcrypto_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
216static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
217{
218 qcrypto_afalg_comm_free(cipher->opaque);
219}
220
221struct 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};
227