xref: /openbmc/qemu/crypto/cipher-afalg.c (revision 3d54cbf2)
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 "qapi/error.h"
16 #include "crypto/cipher.h"
17 #include "cipherpriv.h"
18 
19 
20 static char *
21 qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg,
22                                  QCryptoCipherMode mode,
23                                  Error **errp)
24 {
25     char *name;
26     const char *alg_name;
27     const char *mode_name;
28 
29     switch (alg) {
30     case QCRYPTO_CIPHER_ALG_AES_128:
31     case QCRYPTO_CIPHER_ALG_AES_192:
32     case QCRYPTO_CIPHER_ALG_AES_256:
33         alg_name = "aes";
34         break;
35     case QCRYPTO_CIPHER_ALG_CAST5_128:
36         alg_name = "cast5";
37         break;
38     case QCRYPTO_CIPHER_ALG_SERPENT_128:
39     case QCRYPTO_CIPHER_ALG_SERPENT_192:
40     case QCRYPTO_CIPHER_ALG_SERPENT_256:
41         alg_name = "serpent";
42         break;
43     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
44     case QCRYPTO_CIPHER_ALG_TWOFISH_192:
45     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
46         alg_name = "twofish";
47         break;
48 
49     default:
50         error_setg(errp, "Unsupported cipher algorithm %d", alg);
51         return NULL;
52     }
53 
54     mode_name = QCryptoCipherMode_str(mode);
55     name = g_strdup_printf("%s(%s)", mode_name, alg_name);
56 
57     return name;
58 }
59 
60 static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
61 
62 QCryptoCipher *
63 qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
64                              QCryptoCipherMode mode,
65                              const uint8_t *key,
66                              size_t nkey, Error **errp)
67 {
68     QCryptoAFAlg *afalg;
69     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 */
86     if (setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key,
87                    nkey) != 0) {
88         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 
113     afalg->base.driver = &qcrypto_cipher_afalg_driver;
114     return &afalg->base;
115 }
116 
117 static int
118 qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
119                            const uint8_t *iv,
120                            size_t niv, Error **errp)
121 {
122     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
123     struct af_alg_iv *alg_iv;
124     size_t expect_niv;
125 
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 
145 static int
146 qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg,
147                         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 
200 static int
201 qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
202                              const void *in, void *out,
203                              size_t len, Error **errp)
204 {
205     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
206 
207     return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
208 }
209 
210 static int
211 qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
212                              const void *in, void *out,
213                              size_t len, Error **errp)
214 {
215     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
216 
217     return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
218 }
219 
220 static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
221 {
222     QCryptoAFAlg *afalg = container_of(cipher, QCryptoAFAlg, base);
223 
224     qcrypto_afalg_comm_free(afalg);
225 }
226 
227 static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
228     .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 };
233