cipher-afalg.c (6777B)
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 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 61static const struct QCryptoCipherDriver qcrypto_cipher_afalg_driver; 62 63QCryptoCipher * 64qcrypto_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 (qemu_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 118static int 119qcrypto_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 146static int 147qcrypto_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 201static int 202qcrypto_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 211static int 212qcrypto_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 221static 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 228static 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};