125c60df3SLongpeng(Mike) /*
225c60df3SLongpeng(Mike) * QEMU Crypto af_alg-backend cipher support
325c60df3SLongpeng(Mike) *
425c60df3SLongpeng(Mike) * Copyright (c) 2017 HUAWEI TECHNOLOGIES CO., LTD.
525c60df3SLongpeng(Mike) *
625c60df3SLongpeng(Mike) * Authors:
725c60df3SLongpeng(Mike) * Longpeng(Mike) <longpeng2@huawei.com>
825c60df3SLongpeng(Mike) *
925c60df3SLongpeng(Mike) * This work is licensed under the terms of the GNU GPL, version 2 or
1025c60df3SLongpeng(Mike) * (at your option) any later version. See the COPYING file in the
1125c60df3SLongpeng(Mike) * top-level directory.
1225c60df3SLongpeng(Mike) */
1325c60df3SLongpeng(Mike) #include "qemu/osdep.h"
1425c60df3SLongpeng(Mike) #include "qemu/sockets.h"
1525c60df3SLongpeng(Mike) #include "qapi/error.h"
1625c60df3SLongpeng(Mike) #include "crypto/cipher.h"
1725c60df3SLongpeng(Mike) #include "cipherpriv.h"
1825c60df3SLongpeng(Mike)
1925c60df3SLongpeng(Mike)
2025c60df3SLongpeng(Mike) static char *
qcrypto_afalg_cipher_format_name(QCryptoCipherAlgo alg,QCryptoCipherMode mode,Error ** errp)21a092c513SMarkus Armbruster qcrypto_afalg_cipher_format_name(QCryptoCipherAlgo alg,
2225c60df3SLongpeng(Mike) QCryptoCipherMode mode,
2325c60df3SLongpeng(Mike) Error **errp)
2425c60df3SLongpeng(Mike) {
2525c60df3SLongpeng(Mike) char *name;
2625c60df3SLongpeng(Mike) const char *alg_name;
2725c60df3SLongpeng(Mike) const char *mode_name;
2825c60df3SLongpeng(Mike)
2925c60df3SLongpeng(Mike) switch (alg) {
30a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_128:
31a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_192:
32a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_AES_256:
3325c60df3SLongpeng(Mike) alg_name = "aes";
3425c60df3SLongpeng(Mike) break;
35a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_CAST5_128:
3625c60df3SLongpeng(Mike) alg_name = "cast5";
3725c60df3SLongpeng(Mike) break;
38a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_SERPENT_128:
39a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_SERPENT_192:
40a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_SERPENT_256:
4125c60df3SLongpeng(Mike) alg_name = "serpent";
4225c60df3SLongpeng(Mike) break;
43a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_TWOFISH_128:
44a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_TWOFISH_192:
45a092c513SMarkus Armbruster case QCRYPTO_CIPHER_ALGO_TWOFISH_256:
4625c60df3SLongpeng(Mike) alg_name = "twofish";
4725c60df3SLongpeng(Mike) break;
4825c60df3SLongpeng(Mike)
4925c60df3SLongpeng(Mike) default:
5025c60df3SLongpeng(Mike) error_setg(errp, "Unsupported cipher algorithm %d", alg);
5125c60df3SLongpeng(Mike) return NULL;
5225c60df3SLongpeng(Mike) }
5325c60df3SLongpeng(Mike)
54977c736fSMarkus Armbruster mode_name = QCryptoCipherMode_str(mode);
5525c60df3SLongpeng(Mike) name = g_strdup_printf("%s(%s)", mode_name, alg_name);
5625c60df3SLongpeng(Mike)
5725c60df3SLongpeng(Mike) return name;
5825c60df3SLongpeng(Mike) }
5925c60df3SLongpeng(Mike)
60da30cd77SRichard Henderson static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver;
61da30cd77SRichard Henderson
623eedf5ccSRichard Henderson QCryptoCipher *
qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgo alg,QCryptoCipherMode mode,const uint8_t * key,size_t nkey,Error ** errp)63a092c513SMarkus Armbruster qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgo alg,
6425c60df3SLongpeng(Mike) QCryptoCipherMode mode,
6525c60df3SLongpeng(Mike) const uint8_t *key,
6625c60df3SLongpeng(Mike) size_t nkey, Error **errp)
6725c60df3SLongpeng(Mike) {
68*8f525028SMarkus Armbruster QCryptoAFAlgo *afalg;
6925c60df3SLongpeng(Mike) size_t expect_niv;
7025c60df3SLongpeng(Mike) char *name;
7125c60df3SLongpeng(Mike)
7225c60df3SLongpeng(Mike) name = qcrypto_afalg_cipher_format_name(alg, mode, errp);
7325c60df3SLongpeng(Mike) if (!name) {
7425c60df3SLongpeng(Mike) return NULL;
7525c60df3SLongpeng(Mike) }
7625c60df3SLongpeng(Mike)
7725c60df3SLongpeng(Mike) afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp);
7825c60df3SLongpeng(Mike) if (!afalg) {
7925c60df3SLongpeng(Mike) g_free(name);
8025c60df3SLongpeng(Mike) return NULL;
8125c60df3SLongpeng(Mike) }
8225c60df3SLongpeng(Mike)
8325c60df3SLongpeng(Mike) g_free(name);
8425c60df3SLongpeng(Mike)
8525c60df3SLongpeng(Mike) /* setkey */
86e7b79428SMarc-André Lureau if (setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key,
8725c60df3SLongpeng(Mike) nkey) != 0) {
8825c60df3SLongpeng(Mike) error_setg_errno(errp, errno, "Set key failed");
8925c60df3SLongpeng(Mike) qcrypto_afalg_comm_free(afalg);
9025c60df3SLongpeng(Mike) return NULL;
9125c60df3SLongpeng(Mike) }
9225c60df3SLongpeng(Mike)
9325c60df3SLongpeng(Mike) /* prepare msg header */
9425c60df3SLongpeng(Mike) afalg->msg = g_new0(struct msghdr, 1);
9525c60df3SLongpeng(Mike) afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN);
9625c60df3SLongpeng(Mike) expect_niv = qcrypto_cipher_get_iv_len(alg, mode);
9725c60df3SLongpeng(Mike) if (expect_niv) {
9825c60df3SLongpeng(Mike) afalg->msg->msg_controllen += CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
9925c60df3SLongpeng(Mike) }
10025c60df3SLongpeng(Mike) afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen);
10125c60df3SLongpeng(Mike)
10225c60df3SLongpeng(Mike) /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */
10325c60df3SLongpeng(Mike) afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
10425c60df3SLongpeng(Mike) afalg->cmsg->cmsg_type = ALG_SET_OP;
10525c60df3SLongpeng(Mike) afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN);
10625c60df3SLongpeng(Mike) if (expect_niv) {
10725c60df3SLongpeng(Mike) afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
10825c60df3SLongpeng(Mike) afalg->cmsg->cmsg_type = ALG_SET_IV;
10925c60df3SLongpeng(Mike) afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(expect_niv));
11025c60df3SLongpeng(Mike) }
11125c60df3SLongpeng(Mike) afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
11225c60df3SLongpeng(Mike)
113da30cd77SRichard Henderson afalg->base.driver = &qcrypto_cipher_afalg_driver;
1143eedf5ccSRichard Henderson return &afalg->base;
11525c60df3SLongpeng(Mike) }
11625c60df3SLongpeng(Mike)
11725c60df3SLongpeng(Mike) static int
qcrypto_afalg_cipher_setiv(QCryptoCipher * cipher,const uint8_t * iv,size_t niv,Error ** errp)11825c60df3SLongpeng(Mike) qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher,
11925c60df3SLongpeng(Mike) const uint8_t *iv,
12025c60df3SLongpeng(Mike) size_t niv, Error **errp)
12125c60df3SLongpeng(Mike) {
122*8f525028SMarkus Armbruster QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
12325c60df3SLongpeng(Mike) struct af_alg_iv *alg_iv;
12425c60df3SLongpeng(Mike) size_t expect_niv;
12525c60df3SLongpeng(Mike)
12625c60df3SLongpeng(Mike) expect_niv = qcrypto_cipher_get_iv_len(cipher->alg, cipher->mode);
12725c60df3SLongpeng(Mike) if (niv != expect_niv) {
12825c60df3SLongpeng(Mike) error_setg(errp, "Set IV len(%zu) not match expected(%zu)",
12925c60df3SLongpeng(Mike) niv, expect_niv);
13025c60df3SLongpeng(Mike) return -1;
13125c60df3SLongpeng(Mike) }
13225c60df3SLongpeng(Mike)
13325c60df3SLongpeng(Mike) /* move ->cmsg to next msghdr, for IV-info */
13425c60df3SLongpeng(Mike) afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg);
13525c60df3SLongpeng(Mike)
13625c60df3SLongpeng(Mike) /* build setiv msg */
13725c60df3SLongpeng(Mike) afalg->cmsg->cmsg_level = SOL_ALG;
13825c60df3SLongpeng(Mike) alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg);
13925c60df3SLongpeng(Mike) alg_iv->ivlen = niv;
14025c60df3SLongpeng(Mike) memcpy(alg_iv->iv, iv, niv);
14125c60df3SLongpeng(Mike)
14225c60df3SLongpeng(Mike) return 0;
14325c60df3SLongpeng(Mike) }
14425c60df3SLongpeng(Mike)
14525c60df3SLongpeng(Mike) static int
qcrypto_afalg_cipher_op(QCryptoAFAlgo * afalg,const void * in,void * out,size_t len,bool do_encrypt,Error ** errp)146*8f525028SMarkus Armbruster qcrypto_afalg_cipher_op(QCryptoAFAlgo *afalg,
14725c60df3SLongpeng(Mike) const void *in, void *out,
14825c60df3SLongpeng(Mike) size_t len, bool do_encrypt,
14925c60df3SLongpeng(Mike) Error **errp)
15025c60df3SLongpeng(Mike) {
15125c60df3SLongpeng(Mike) uint32_t *type = NULL;
15225c60df3SLongpeng(Mike) struct iovec iov;
15325c60df3SLongpeng(Mike) size_t ret, rlen, done = 0;
15425c60df3SLongpeng(Mike) uint32_t origin_controllen;
15525c60df3SLongpeng(Mike)
15625c60df3SLongpeng(Mike) origin_controllen = afalg->msg->msg_controllen;
15725c60df3SLongpeng(Mike) /* movev ->cmsg to first header, for crypto-info */
15825c60df3SLongpeng(Mike) afalg->cmsg = CMSG_FIRSTHDR(afalg->msg);
15925c60df3SLongpeng(Mike)
16025c60df3SLongpeng(Mike) /* build encrypt msg */
16125c60df3SLongpeng(Mike) afalg->cmsg->cmsg_level = SOL_ALG;
16225c60df3SLongpeng(Mike) afalg->msg->msg_iov = &iov;
16325c60df3SLongpeng(Mike) afalg->msg->msg_iovlen = 1;
16425c60df3SLongpeng(Mike) type = (uint32_t *)CMSG_DATA(afalg->cmsg);
16525c60df3SLongpeng(Mike) if (do_encrypt) {
16625c60df3SLongpeng(Mike) *type = ALG_OP_ENCRYPT;
16725c60df3SLongpeng(Mike) } else {
16825c60df3SLongpeng(Mike) *type = ALG_OP_DECRYPT;
16925c60df3SLongpeng(Mike) }
17025c60df3SLongpeng(Mike)
17125c60df3SLongpeng(Mike) do {
17225c60df3SLongpeng(Mike) iov.iov_base = (void *)in + done;
17325c60df3SLongpeng(Mike) iov.iov_len = len - done;
17425c60df3SLongpeng(Mike)
17525c60df3SLongpeng(Mike) /* send info to AF_ALG core */
17625c60df3SLongpeng(Mike) ret = sendmsg(afalg->opfd, afalg->msg, 0);
17725c60df3SLongpeng(Mike) if (ret == -1) {
17825c60df3SLongpeng(Mike) error_setg_errno(errp, errno, "Send data to AF_ALG core failed");
17925c60df3SLongpeng(Mike) return -1;
18025c60df3SLongpeng(Mike) }
18125c60df3SLongpeng(Mike)
18225c60df3SLongpeng(Mike) /* encrypto && get result */
18325c60df3SLongpeng(Mike) rlen = read(afalg->opfd, out, ret);
18425c60df3SLongpeng(Mike) if (rlen == -1) {
18525c60df3SLongpeng(Mike) error_setg_errno(errp, errno, "Get result from AF_ALG core failed");
18625c60df3SLongpeng(Mike) return -1;
18725c60df3SLongpeng(Mike) }
18825c60df3SLongpeng(Mike) assert(rlen == ret);
18925c60df3SLongpeng(Mike)
19025c60df3SLongpeng(Mike) /* do not update IV for following chunks */
19125c60df3SLongpeng(Mike) afalg->msg->msg_controllen = 0;
19225c60df3SLongpeng(Mike) done += ret;
19325c60df3SLongpeng(Mike) } while (done < len);
19425c60df3SLongpeng(Mike)
19525c60df3SLongpeng(Mike) afalg->msg->msg_controllen = origin_controllen;
19625c60df3SLongpeng(Mike)
19725c60df3SLongpeng(Mike) return 0;
19825c60df3SLongpeng(Mike) }
19925c60df3SLongpeng(Mike)
20025c60df3SLongpeng(Mike) static int
qcrypto_afalg_cipher_encrypt(QCryptoCipher * cipher,const void * in,void * out,size_t len,Error ** errp)20125c60df3SLongpeng(Mike) qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher,
20225c60df3SLongpeng(Mike) const void *in, void *out,
20325c60df3SLongpeng(Mike) size_t len, Error **errp)
20425c60df3SLongpeng(Mike) {
205*8f525028SMarkus Armbruster QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
2063eedf5ccSRichard Henderson
2073eedf5ccSRichard Henderson return qcrypto_afalg_cipher_op(afalg, in, out, len, true, errp);
20825c60df3SLongpeng(Mike) }
20925c60df3SLongpeng(Mike)
21025c60df3SLongpeng(Mike) static int
qcrypto_afalg_cipher_decrypt(QCryptoCipher * cipher,const void * in,void * out,size_t len,Error ** errp)21125c60df3SLongpeng(Mike) qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher,
21225c60df3SLongpeng(Mike) const void *in, void *out,
21325c60df3SLongpeng(Mike) size_t len, Error **errp)
21425c60df3SLongpeng(Mike) {
215*8f525028SMarkus Armbruster QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
2163eedf5ccSRichard Henderson
2173eedf5ccSRichard Henderson return qcrypto_afalg_cipher_op(afalg, in, out, len, false, errp);
21825c60df3SLongpeng(Mike) }
21925c60df3SLongpeng(Mike)
qcrypto_afalg_comm_ctx_free(QCryptoCipher * cipher)22025c60df3SLongpeng(Mike) static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher)
22125c60df3SLongpeng(Mike) {
222*8f525028SMarkus Armbruster QCryptoAFAlgo *afalg = container_of(cipher, QCryptoAFAlgo, base);
2233eedf5ccSRichard Henderson
2243eedf5ccSRichard Henderson qcrypto_afalg_comm_free(afalg);
22525c60df3SLongpeng(Mike) }
22625c60df3SLongpeng(Mike)
227da30cd77SRichard Henderson static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = {
22825c60df3SLongpeng(Mike) .cipher_encrypt = qcrypto_afalg_cipher_encrypt,
22925c60df3SLongpeng(Mike) .cipher_decrypt = qcrypto_afalg_cipher_decrypt,
23025c60df3SLongpeng(Mike) .cipher_setiv = qcrypto_afalg_cipher_setiv,
23125c60df3SLongpeng(Mike) .cipher_free = qcrypto_afalg_comm_ctx_free,
23225c60df3SLongpeng(Mike) };
233