qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cipher-afalg.c (6742B)


      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 };