2 * QEMU Crypto af_alg-backend cipher support
4 * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
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"
22 qcrypto_afalg_cipher_format_name(QCryptoCipherAlgorithm alg
,
23 QCryptoCipherMode mode
,
28 const char *mode_name
;
31 case QCRYPTO_CIPHER_ALG_AES_128
:
32 case QCRYPTO_CIPHER_ALG_AES_192
:
33 case QCRYPTO_CIPHER_ALG_AES_256
:
36 case QCRYPTO_CIPHER_ALG_CAST5_128
:
39 case QCRYPTO_CIPHER_ALG_SERPENT_128
:
40 case QCRYPTO_CIPHER_ALG_SERPENT_192
:
41 case QCRYPTO_CIPHER_ALG_SERPENT_256
:
44 case QCRYPTO_CIPHER_ALG_TWOFISH_128
:
45 case QCRYPTO_CIPHER_ALG_TWOFISH_192
:
46 case QCRYPTO_CIPHER_ALG_TWOFISH_256
:
51 error_setg(errp
, "Unsupported cipher algorithm %d", alg
);
55 mode_name
= QCryptoCipherMode_str(mode
);
56 name
= g_strdup_printf("%s(%s)", mode_name
, alg_name
);
61 static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver
;
64 qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg
,
65 QCryptoCipherMode mode
,
67 size_t nkey
, Error
**errp
)
73 name
= qcrypto_afalg_cipher_format_name(alg
, mode
, errp
);
78 afalg
= qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER
, name
, errp
);
87 if (setsockopt(afalg
->tfmfd
, SOL_ALG
, ALG_SET_KEY
, key
,
89 error_setg_errno(errp
, errno
, "Set key failed");
90 qcrypto_afalg_comm_free(afalg
);
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
);
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
);
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
;
119 qcrypto_afalg_cipher_setiv(QCryptoCipher
*cipher
,
121 size_t niv
, Error
**errp
)
123 QCryptoAFAlg
*afalg
= container_of(cipher
, QCryptoAFAlg
, base
);
124 struct af_alg_iv
*alg_iv
;
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)",
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
);
141 memcpy(alg_iv
->iv
, iv
, niv
);
147 qcrypto_afalg_cipher_op(QCryptoAFAlg
*afalg
,
148 const void *in
, void *out
,
149 size_t len
, bool do_encrypt
,
152 uint32_t *type
= NULL
;
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
);
167 *type
= ALG_OP_ENCRYPT
;
169 *type
= ALG_OP_DECRYPT
;
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);
179 error_setg_errno(errp
, errno
, "Send data to AF_ALG core failed");
183 /* encrypto && get result */
184 rlen
= read(afalg
->opfd
, out
, ret
);
186 error_setg_errno(errp
, errno
, "Get result from AF_ALG core failed");
191 /* do not update IV for following chunks */
192 afalg
->msg
->msg_controllen
= 0;
194 } while (done
< len
);
196 afalg
->msg
->msg_controllen
= origin_controllen
;
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
);
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
,