Linux kernel crypto subsystem study notes

crypto note

v0.1 2017/12/19 Sherlock init
v0.2 2017/3/25 Sherlock add sync/asyns code analysis in airplane from Boston to HK

This article analyzes the approximate implementation of the crypto subsystem in the Linux kernel.
You can . The crypto subsystem supports functions such as encryption and decryption, compression and decompression.

Analysis will start from crypto test cases in crypto/testmgr.c, eg deflate.
The above path is a test program for this pair of crypto subsystems in the kernel. By analyzing this program, we can roughly
see the API provided by the crypto subsystem. The situation of the whole system is probably as follows:

crypto API <—> crypto core <—> crypto_register_alg

A device driver registers an algorithm supported by a device with the crypto system through crypto_register_alg.
When registering, the relevant information will be passed to the crypto core through struct crypto_alg.

The structure of struct crypto_alg is like this:

struct crypto_alg {
    struct list_head cra_list;
    struct list_head cra_users;

    u32 cra_flags;
    unsigned int cra_blocksize;
    unsigned int cra_ctxsize;
    unsigned int cra_alignmask;

    int cra_priority;
    atomic_t cra_refcnt;

    char cra_name[CRYPTO_MAX_ALG_NAME];
    char cra_driver_name[CRYPTO_MAX_ALG_NAME];

    const struct crypto_type *cra_type;

    union {
        struct ablkcipher_alg ablkcipher;
        struct blkcipher_alg blkcipher;
        struct cipher_alg cipher;
        struct compress_alg compress;
    } cra_u;

    int (*cra_init)(struct crypto_tfm *tfm);
    void (*cra_exit)(struct crypto_tfm *tfm);
    void (*cra_destroy)(struct crypto_alg *alg);

    struct module *cra_module;
} CRYPTO_MINALIGN_ATTR;

Several key pieces of information in this structure are: cra_ctxsize, cra_u (indicated by compress_alg below), cra_init,
cra_exit.
This structure describes the algorithm-related system, but when executing a request, there is also information to maintain a set of contexts ,
this information is recorded in the structure: struct crypto_tfm.

struct crypto_tfm {

    u32 crt_flags;

    union {
        struct ablkcipher_tfm ablkcipher;
        struct blkcipher_tfm blkcipher;
        struct cipher_tfm cipher;
        struct compress_tfm compress;
                    --> cot_compress
                    --> cot_decompress
    } crt_u;

    void (*exit)(struct crypto_tfm *tfm);

    struct crypto_alg *__crt_alg;

    void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
};

The last __crt_ctx is private data for this context. The above cra_ctxsize is the
size of the private data. cra_init is the function for preparing the context. For example, if you use a hardware device to compress data, and the actual physical operation
occurs on a queue of this hardware, then you need to prepare the queue and prepare the necessary cache, etc. cra_exit
is to exit the context. In cra_u are functions that perform specific algorithms, such as functions that can compress and decompress.

From the device driver's point of view, the device driver just sees the crypto_alg structure. Where does crypt_tfm in this structure
know the context of an operation execution? After all,
.cra_init, .cra_exit, .coa_compress and .coa_decompress in .cra_u in the structure of crypto_alg all need this execution context.
Let's take a closer look below.

Knowing these internal data structures helps us understand the external API. Now assuming that the device driver for crypto already exists,
how can other kernel modules be used? In fact, we have already talked about the crypto/testmgr.c test program at the beginning.

There are asynchronous tests and synchronous test processes in the test code. Let's look at the synchronous tests first:

The main logic is three functions. First, a compression context needs to be allocated (the compression example is used in this article). In fact, it
is the wrapper of crypto_tfm, which is the same as cryto_tfm:

struct crypto_comp {
    struct crypto_tfm base;
};

struct crypto_comp = crypto_alloc_comp(driver, type, mask), the cra_init function will be called during this process
. This function is implemented by the device driver and completes the hardware-related configuration, as mentioned above.
The calling relationship is as follows:

/* 分配一个压缩解压缩的上下文, 可以看到这里的压缩解压缩的上下文完全就是crypto_tfm */
struct crypto_comp = crypto_alloc_comp(driver, type, mask);
    --> crypto_alloc_base(alg_name, type, mask)
            /* find algrithm: use alg_name, driver name */
        --> alg = crypto_alg_mod_lookup(alg_name, type, mask);
            /* 上下文是依据具体的算法去分配的 */
        --> tfm = __crypto_alloc_tfm(alg, type, mask);
            /* 上下文中指定相关的算法 */
            --> tfm->__crt_alg = alg;
            --> crypto_init_ops
                /* 把相应的算法中的压缩解压缩函数传递给上下文 */
                --> crypto_init_compress_ops(tfm)
                        /* ops is struct compress_tfm */
                --> ops->cot_compress = crypto_compress;
                            /* tfm->__crt_alg->cra_u.compress.coa_compress */ 
                            /*
                             * e.g. drivers/crypto/cavium/zip/zip_main.c
                             *      struct crypto_alg zip_comp_deflate.
                             * will finally call zip_comp_compress!
                             */
                        --> tfm->__crt_alg->cra_compress.coa_compress

                --> ops->cot_decompress = crypto_decompress;
        /*
         * 在创建上下文的最后调用下,算法里的初始化函数,如果是和一个硬件
         * 的驱动适配,那么这里就可以执行相应硬件初始化的内容。
         */
            --> if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))

The second is to perform the compression operation:
crypto_comp_compress(tfm, input, ilen, result, &dlen)

crypto_comp_compress(crypto_comp, src, slen, dst, dlen)
        /* so hardware can do compress here! */
    --> compress_tfm->cot_compress;

The third is to release the compressed context
crypto_free_comp(comp)

Although the kernel now provides a compressed asynchronous interface, it seems that no driver will use it. Using asynchronous interfaces is a bit more complicated than using synchronous
interfaces . See below for details.

In alg_test_comp, async branch:
/* Like synchronization, an asynchronous context is also created here*/
acomp = crypto_alloc_acomp(driver, type, mask);
/*
* But unlike the synchronous interface, another acomp_req is created here Context, and subsequent operations revolve around
this req structure. You can see that req contains the callback functions required by the asynchronous interface.
*/ It should be noted here that the relevant content . This should be added for the convenience of testing. In the general asynchronous interface, when the hardware completes the operation, the callback function of the asynchronous interface can be called directly in the interrupt function.

req = acomp_request_alloc(tfm);
acomp_request_set_params(req, &src, &dst, ilen, dlen);
acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);
crypto_acomp_compress(req)



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324607690&siteId=291194637