xref: /openbmc/qemu/crypto/cipher-afalg.c (revision 5242ef88)
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 static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
62 
63 QCryptoCipher *
64 qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
65                              QCryptoCipherMode mode,
66                              const uint8_t *key,
67                              size_t nkey, Error **errp)
68 {
69     QCryptoAFAlg *afalg;
70     size_t expect_niv;
71     char *name;
72 
73     name = qcrypto_afalg_cipher_format_name(alg, mode, errp);
74     if (!name) {
75         return NULL;
76     }
77 
78     afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp);
79     if (!afalg) {
80         g_free(name);
81         return NULL;
82     }
83 
84     g_free(name);
85 
86     /* setkey */
87     if (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;
92     }
93 
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));
100     }
101     afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen);
102 
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));
111     }
112     afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
113 
114     afalg->base.driver = &qcrypto_cipher_afalg_driver;
115     return &afalg->base;
116 }
117 
118 static int
119 qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
120                            const uint8_t *iv,
121                            size_t niv, Error **errp)
122 {
123     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
124     struct af_alg_iv *alg_iv;
125     size_t expect_niv;
126 
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;
132     }
133 
134     /* move ->cmsg to next msghdr, for IV-info */
135     afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
136 
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);
142 
143     return 0;
144 }
145 
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)
151 {
152     uint32_t *type = NULL;
153     struct iovec iov;
154     size_t ret, rlen, done = 0;
155     uint32_t origin_controllen;
156 
157     origin_controllen = afalg->msg->msg_controllen;
158     /* movev ->cmsg to first header, for crypto-info */
159     afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
160 
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;
170     }
171 
172     do {
173         iov.iov_base = (void *)in + done;
174         iov.iov_len = len - done;
175 
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;
181         }
182 
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;
188         }
189         assert(rlen == ret);
190 
191         /* do not update IV for following chunks */
192         afalg->msg->msg_controllen = 0;
193         done += ret;
194     } while (done < len);
195 
196     afalg->msg->msg_controllen = origin_controllen;
197 
198     return 0;
199 }
200 
201 static int
202 qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
203                              const void *in, void *out,
204                              size_t len, Error **errp)
205 {
206     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
207 
208     return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
209 }
210 
211 static int
212 qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
213                              const void *in, void *out,
214                              size_t len, Error **errp)
215 {
216     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
217 
218     return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
219 }
220 
221 static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
222 {
223     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
224 
225     qcrypto_afalg_comm_free(afalg);
226 }
227 
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,
233 };
234