Re: [PATCH] crypto: doc - improve the skcipher API example code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 3 Jun 2019 at 07:44, Eric Biggers <ebiggers@xxxxxxxxxx> wrote:
>
> From: Eric Biggers <ebiggers@xxxxxxxxxx>
>
> Rewrite the skcipher API example, changing it to encrypt a buffer with
> AES-256-XTS.  This addresses various problems with the previous example:
>
> - It requests a specific driver "cbc-aes-aesni", which is unusual.
>   Normally users ask for "cbc(aes)", not a specific driver.
>
> - It encrypts only a single AES block.  For the reader, that doesn't
>   clearly distinguish the "skcipher" API from the "cipher" API.
>
> - Showing how to encrypt something with bare CBC is arguably a poor
>   choice of example, as it doesn't follow modern crypto trends.  Now,
>   usually authenticated encryption is recommended, in which case the
>   user would use the AEAD API, not skcipher.  Disk encryption is still a
>   legitimate use for skcipher, but for that usually XTS is recommended.
>
> - Many other bugs and poor coding practices, such as not setting
>   CRYPTO_TFM_REQ_MAY_SLEEP, unnecessarily allocating a heap buffer for
>   the IV, unnecessary NULL checks, using a pointless wrapper struct, and
>   forgetting to set an error code in one case.
>
> Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx>

Acked-by: Ard Biesheuvel <ard.biesheuvel@xxxxxxxxxx>

> ---
>  Documentation/crypto/api-samples.rst | 176 ++++++++++++---------------
>  1 file changed, 77 insertions(+), 99 deletions(-)
>
> diff --git a/Documentation/crypto/api-samples.rst b/Documentation/crypto/api-samples.rst
> index f14afaaf2f324..e923f17bc2bd5 100644
> --- a/Documentation/crypto/api-samples.rst
> +++ b/Documentation/crypto/api-samples.rst
> @@ -4,111 +4,89 @@ Code Examples
>  Code Example For Symmetric Key Cipher Operation
>  -----------------------------------------------
>
> -::
> -
> -
> -    /* tie all data structures together */
> -    struct skcipher_def {
> -        struct scatterlist sg;
> -        struct crypto_skcipher *tfm;
> -        struct skcipher_request *req;
> -        struct crypto_wait wait;
> -    };
> -
> -    /* Perform cipher operation */
> -    static unsigned int test_skcipher_encdec(struct skcipher_def *sk,
> -                         int enc)
> -    {
> -        int rc;
> -
> -        if (enc)
> -            rc = crypto_wait_req(crypto_skcipher_encrypt(sk->req), &sk->wait);
> -        else
> -            rc = crypto_wait_req(crypto_skcipher_decrypt(sk->req), &sk->wait);
> -
> -       if (rc)
> -               pr_info("skcipher encrypt returned with result %d\n", rc);
> +This code encrypts some data with AES-256-XTS.  For sake of example,
> +all inputs are random bytes, the encryption is done in-place, and it's
> +assumed the code is running in a context where it can sleep.
>
> -        return rc;
> -    }
> +::
>
> -    /* Initialize and trigger cipher operation */
>      static int test_skcipher(void)
>      {
> -        struct skcipher_def sk;
> -        struct crypto_skcipher *skcipher = NULL;
> -        struct skcipher_request *req = NULL;
> -        char *scratchpad = NULL;
> -        char *ivdata = NULL;
> -        unsigned char key[32];
> -        int ret = -EFAULT;
> -
> -        skcipher = crypto_alloc_skcipher("cbc-aes-aesni", 0, 0);
> -        if (IS_ERR(skcipher)) {
> -            pr_info("could not allocate skcipher handle\n");
> -            return PTR_ERR(skcipher);
> -        }
> -
> -        req = skcipher_request_alloc(skcipher, GFP_KERNEL);
> -        if (!req) {
> -            pr_info("could not allocate skcipher request\n");
> -            ret = -ENOMEM;
> -            goto out;
> -        }
> -
> -        skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
> -                          crypto_req_done,
> -                          &sk.wait);
> -
> -        /* AES 256 with random key */
> -        get_random_bytes(&key, 32);
> -        if (crypto_skcipher_setkey(skcipher, key, 32)) {
> -            pr_info("key could not be set\n");
> -            ret = -EAGAIN;
> -            goto out;
> -        }
> -
> -        /* IV will be random */
> -        ivdata = kmalloc(16, GFP_KERNEL);
> -        if (!ivdata) {
> -            pr_info("could not allocate ivdata\n");
> -            goto out;
> -        }
> -        get_random_bytes(ivdata, 16);
> -
> -        /* Input data will be random */
> -        scratchpad = kmalloc(16, GFP_KERNEL);
> -        if (!scratchpad) {
> -            pr_info("could not allocate scratchpad\n");
> -            goto out;
> -        }
> -        get_random_bytes(scratchpad, 16);
> -
> -        sk.tfm = skcipher;
> -        sk.req = req;
> -
> -        /* We encrypt one block */
> -        sg_init_one(&sk.sg, scratchpad, 16);
> -        skcipher_request_set_crypt(req, &sk.sg, &sk.sg, 16, ivdata);
> -        crypto_init_wait(&sk.wait);
> -
> -        /* encrypt data */
> -        ret = test_skcipher_encdec(&sk, 1);
> -        if (ret)
> -            goto out;
> -
> -        pr_info("Encryption triggered successfully\n");
> -
> +            struct crypto_skcipher *tfm = NULL;
> +            struct skcipher_request *req = NULL;
> +            u8 *data = NULL;
> +            const size_t datasize = 512; /* data size in bytes */
> +            struct scatterlist sg;
> +            DECLARE_CRYPTO_WAIT(wait);
> +            u8 iv[16];  /* AES-256-XTS takes a 16-byte IV */
> +            u8 key[64]; /* AES-256-XTS takes a 64-byte key */
> +            int err;
> +
> +            /*
> +             * Allocate a tfm (a transformation object) and set the key.
> +             *
> +             * In real-world use, a tfm and key are typically used for many
> +             * encryption/decryption operations.  But in this example, we'll just do a
> +             * single encryption operation with it (which is not very efficient).
> +             */
> +
> +            tfm = crypto_alloc_skcipher("xts(aes)", 0, 0);
> +            if (IS_ERR(tfm)) {
> +                    pr_err("Error allocating xts(aes) handle: %ld\n", PTR_ERR(tfm));
> +                    return PTR_ERR(tfm);
> +            }
> +
> +            get_random_bytes(key, sizeof(key));
> +            err = crypto_skcipher_setkey(tfm, key, sizeof(key));
> +            if (err) {
> +                    pr_err("Error setting key: %d\n", err);
> +                    goto out;
> +            }
> +
> +            /* Allocate a request object */
> +            req = skcipher_request_alloc(tfm, GFP_KERNEL);
> +            if (!req) {
> +                    err = -ENOMEM;
> +                    goto out;
> +            }
> +
> +            /* Prepare the input data */
> +            data = kmalloc(datasize, GFP_KERNEL);
> +            if (!data) {
> +                    err = -ENOMEM;
> +                    goto out;
> +            }
> +            get_random_bytes(data, datasize);
> +
> +            /* Initialize the IV */
> +            get_random_bytes(iv, sizeof(iv));
> +
> +            /*
> +             * Encrypt the data in-place.
> +             *
> +             * For simplicity, in this example we wait for the request to complete
> +             * before proceeding, even if the underlying implementation is asynchronous.
> +             *
> +             * To decrypt instead of encrypt, just change crypto_skcipher_encrypt() to
> +             * crypto_skcipher_decrypt().
> +             */
> +            sg_init_one(&sg, data, datasize);
> +            skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
> +                                               CRYPTO_TFM_REQ_MAY_SLEEP,
> +                                          crypto_req_done, &wait);
> +            skcipher_request_set_crypt(req, &sg, &sg, datasize, iv);
> +            err = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
> +            if (err) {
> +                    pr_err("Error encrypting data: %d\n", err);
> +                    goto out;
> +            }
> +
> +            pr_debug("Encryption was successful\n");
>      out:
> -        if (skcipher)
> -            crypto_free_skcipher(skcipher);
> -        if (req)
> +            crypto_free_skcipher(tfm);
>              skcipher_request_free(req);
> -        if (ivdata)
> -            kfree(ivdata);
> -        if (scratchpad)
> -            kfree(scratchpad);
> -        return ret;
> +            kfree(data);
> +            return err;
>      }
>
>
> --
> 2.21.0
>



[Index of Archives]     [Kernel]     [Gnu Classpath]     [Gnu Crypto]     [DM Crypt]     [Netfilter]     [Bugtraq]

  Powered by Linux