在编写Linux驱动的时候常常需要对内核空间的某些数据进行hash计算,而在编写内核模块的时候很多用户空间的方法不能使用,例如Openssl(理论上可以,但是我没成功过)。但是Linux自身提供了一个Crypto API对数据进行各种加密计算,使用这个API就能够在内核模块中进行一些加密和签名操作,下面以sha1位例子。

在4.15内核下编译加载通过。
头文件需要包含:

#include <crypto/hash.h>
#include <crypto/skcipher.h>
#include <linux/crypto.h>
struct sdesc {
    struct shash_desc shash;
    char ctx[];
};

static struct sdesc *init_sdesc(struct crypto_shash *alg)
{
    struct sdesc *sdesc;
    int size;

    size = sizeof(struct shash_desc) + crypto_shash_descsize(alg);
    sdesc = kmalloc(size, GFP_KERNEL);
    if (!sdesc)
        return ERR_PTR(-ENOMEM);
    sdesc->shash.tfm = alg;
    sdesc->shash.flags = 0x0;
    return sdesc;
}

static int calc_hash(struct crypto_shash *alg,
             const unsigned char *data, unsigned int datalen,
             unsigned char *digest)
{
    struct sdesc *sdesc;
    int ret;

    sdesc = init_sdesc(alg);
    if (IS_ERR(sdesc)) {
        pr_info("can't alloc sdesc\n");
        return PTR_ERR(sdesc);
    }

    ret = crypto_shash_digest(&sdesc->shash, data, datalen, digest);
    kfree(sdesc);
    return ret;
}

/*
测试函数,data是进行hash的数据,datalen为数据长度,digest为sha1结果(是一个 out变量)
*/
static int test_hash(const unsigned char *data, unsigned int datalen,
             unsigned char *digest)
{
    struct crypto_shash *alg;
    char *hash_alg_name = "sha1";
    int ret;

    alg = crypto_alloc_shash(hash_alg_name, 0, 0);
    if (IS_ERR(alg)) {
            pr_info("can't alloc alg %s\n", hash_alg_name);
            return PTR_ERR(alg);
    }
    ret = calc_hash(alg, data, datalen, digest);
    crypto_free_shash(alg);
    return ret;
}

进行测试时,只需要将hash的数据按照对应的参数传入test_hash中即可。

Logo

更多推荐