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 QCryptoAFAlg * 62 qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg, 63 QCryptoCipherMode mode, 64 const uint8_t *key, 65 size_t nkey, Error **errp) 66 { 67 QCryptoAFAlg *afalg; 68 size_t expect_niv; 69 char *name; 70 71 name = qcrypto_afalg_cipher_format_name(alg, mode, errp); 72 if (!name) { 73 return NULL; 74 } 75 76 afalg = qcrypto_afalg_comm_alloc(AFALG_TYPE_CIPHER, name, errp); 77 if (!afalg) { 78 g_free(name); 79 return NULL; 80 } 81 82 g_free(name); 83 84 /* setkey */ 85 if (qemu_setsockopt(afalg->tfmfd, SOL_ALG, ALG_SET_KEY, key, 86 nkey) != 0) { 87 error_setg_errno(errp, errno, "Set key failed"); 88 qcrypto_afalg_comm_free(afalg); 89 return NULL; 90 } 91 92 /* prepare msg header */ 93 afalg->msg = g_new0(struct msghdr, 1); 94 afalg->msg->msg_controllen += CMSG_SPACE(ALG_OPTYPE_LEN); 95 expect_niv = qcrypto_cipher_get_iv_len(alg, mode); 96 if (expect_niv) { 97 afalg->msg->msg_controllen += CMSG_SPACE(ALG_MSGIV_LEN(expect_niv)); 98 } 99 afalg->msg->msg_control = g_new0(uint8_t, afalg->msg->msg_controllen); 100 101 /* We use 1st msghdr for crypto-info and 2nd msghdr for IV-info */ 102 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); 103 afalg->cmsg->cmsg_type = ALG_SET_OP; 104 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_OPTYPE_LEN); 105 if (expect_niv) { 106 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg); 107 afalg->cmsg->cmsg_type = ALG_SET_IV; 108 afalg->cmsg->cmsg_len = CMSG_SPACE(ALG_MSGIV_LEN(expect_niv)); 109 } 110 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); 111 112 return afalg; 113 } 114 115 static int 116 qcrypto_afalg_cipher_setiv(QCryptoCipher *cipher, 117 const uint8_t *iv, 118 size_t niv, Error **errp) 119 { 120 struct af_alg_iv *alg_iv; 121 size_t expect_niv; 122 QCryptoAFAlg *afalg = cipher->opaque; 123 124 expect_niv = qcrypto_cipher_get_iv_len(cipher->alg, cipher->mode); 125 if (niv != expect_niv) { 126 error_setg(errp, "Set IV len(%zu) not match expected(%zu)", 127 niv, expect_niv); 128 return -1; 129 } 130 131 /* move ->cmsg to next msghdr, for IV-info */ 132 afalg->cmsg = CMSG_NXTHDR(afalg->msg, afalg->cmsg); 133 134 /* build setiv msg */ 135 afalg->cmsg->cmsg_level = SOL_ALG; 136 alg_iv = (struct af_alg_iv *)CMSG_DATA(afalg->cmsg); 137 alg_iv->ivlen = niv; 138 memcpy(alg_iv->iv, iv, niv); 139 140 return 0; 141 } 142 143 static int 144 qcrypto_afalg_cipher_op(QCryptoAFAlg *afalg, 145 const void *in, void *out, 146 size_t len, bool do_encrypt, 147 Error **errp) 148 { 149 uint32_t *type = NULL; 150 struct iovec iov; 151 size_t ret, rlen, done = 0; 152 uint32_t origin_controllen; 153 154 origin_controllen = afalg->msg->msg_controllen; 155 /* movev ->cmsg to first header, for crypto-info */ 156 afalg->cmsg = CMSG_FIRSTHDR(afalg->msg); 157 158 /* build encrypt msg */ 159 afalg->cmsg->cmsg_level = SOL_ALG; 160 afalg->msg->msg_iov = &iov; 161 afalg->msg->msg_iovlen = 1; 162 type = (uint32_t *)CMSG_DATA(afalg->cmsg); 163 if (do_encrypt) { 164 *type = ALG_OP_ENCRYPT; 165 } else { 166 *type = ALG_OP_DECRYPT; 167 } 168 169 do { 170 iov.iov_base = (void *)in + done; 171 iov.iov_len = len - done; 172 173 /* send info to AF_ALG core */ 174 ret = sendmsg(afalg->opfd, afalg->msg, 0); 175 if (ret == -1) { 176 error_setg_errno(errp, errno, "Send data to AF_ALG core failed"); 177 return -1; 178 } 179 180 /* encrypto && get result */ 181 rlen = read(afalg->opfd, out, ret); 182 if (rlen == -1) { 183 error_setg_errno(errp, errno, "Get result from AF_ALG core failed"); 184 return -1; 185 } 186 assert(rlen == ret); 187 188 /* do not update IV for following chunks */ 189 afalg->msg->msg_controllen = 0; 190 done += ret; 191 } while (done < len); 192 193 afalg->msg->msg_controllen = origin_controllen; 194 195 return 0; 196 } 197 198 static int 199 qcrypto_afalg_cipher_encrypt(QCryptoCipher *cipher, 200 const void *in, void *out, 201 size_t len, Error **errp) 202 { 203 return qcrypto_afalg_cipher_op(cipher->opaque, in, out, 204 len, true, errp); 205 } 206 207 static int 208 qcrypto_afalg_cipher_decrypt(QCryptoCipher *cipher, 209 const void *in, void *out, 210 size_t len, Error **errp) 211 { 212 return qcrypto_afalg_cipher_op(cipher->opaque, in, out, 213 len, false, errp); 214 } 215 216 static void qcrypto_afalg_comm_ctx_free(QCryptoCipher *cipher) 217 { 218 qcrypto_afalg_comm_free(cipher->opaque); 219 } 220 221 struct QCryptoCipherDriver qcrypto_cipher_afalg_driver = { 222 .cipher_encrypt = qcrypto_afalg_cipher_encrypt, 223 .cipher_decrypt = qcrypto_afalg_cipher_decrypt, 224 .cipher_setiv = qcrypto_afalg_cipher_setiv, 225 .cipher_free = qcrypto_afalg_comm_ctx_free, 226 }; 227