如何在Linux内核2.6中使用CryptoAPI

13

我已经寻找了一段时间,但是没有找到足够的文档/示例,说明如何在内核空间中使用linux附带的CryptoAPI来创建系统调用。

如果有人知道一个好的来源,请告诉我,我想知道如何仅在内核空间中执行SHA1 / MD5和Blowfish / AES。

7个回答

11
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/scatterlist.h>

#define SHA1_LENGTH     20

static int __init sha1_init(void)
{
    struct scatterlist sg;
    struct crypto_hash *tfm;
    struct hash_desc desc;
    unsigned char output[SHA1_LENGTH];
    unsigned char buf[10];
    int i;

    printk(KERN_INFO "sha1: %s\n", __FUNCTION__);

    memset(buf, 'A', 10);
    memset(output, 0x00, SHA1_LENGTH);

    tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);

    desc.tfm = tfm;
    desc.flags = 0;

    sg_init_one(&sg, buf, 10);
    crypto_hash_init(&desc);

    crypto_hash_update(&desc, &sg, 10);
    crypto_hash_final(&desc, output);

    for (i = 0; i < 20; i++) {
        printk(KERN_ERR "%d-%d\n", output[i], i);
    }

    crypto_free_hash(tfm);

    return 0;
}

static void __exit sha1_exit(void)
{
    printk(KERN_INFO "sha1: %s\n", __FUNCTION__);
}

module_init(sha1_init);
module_exit(sha1_exit);

MODULE_LICENSE("Dual MIT/GPL");
MODULE_AUTHOR("Me");

你怎么编译它?我的意思是哪些依赖库呢? - user907810
这是一个内核模块示例,因此不依赖于库,而是依赖于其他内核模块。depmod 为您计算这些依赖关系,而 modprobe 按正确顺序加载所有内容。 - Przemek

6

另一个很好的例子来自于2.6.18内核源代码中的security/seclvl.c文件。

注意:如果需要,您可以更改CRYPTO_TFM_REQ_MAY_SLEEP。

static int
plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
{
  struct crypto_tfm *tfm;
  struct scatterlist sg;
  if (len > PAGE_SIZE) {
    seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
            "characters).  Largest possible is %lu "
            "bytes.\n", len, PAGE_SIZE);
    return -EINVAL;
  }
  tfm = crypto_alloc_tfm("sha1", CRYPTO_TFM_REQ_MAY_SLEEP);
  if (tfm == NULL) {
    seclvl_printk(0, KERN_ERR,
            "Failed to load transform for SHA1\n");
    return -EINVAL;
  }
  sg_init_one(&sg, (u8 *)plaintext, len);
  crypto_digest_init(tfm);
  crypto_digest_update(tfm, &sg, 1);
  crypto_digest_final(tfm, hash);
  crypto_free_tfm(tfm);
  return 0;
}

6

内核中有几个使用加密模块的地方:eCryptfs文件系统(linux/fs/ecryptfs/)和802.11无线堆栈(linux/drivers/staging/rtl8187se/ieee80211/)。这两者都使用AES,但您可能能够将其推广到MD5。


2

Cryptodev-linux

https://github.com/cryptodev-linux/cryptodev-linux

这是一个内核模块,通过/dev/crypto将内核加密API暴露给用户空间。

SHA计算示例:https://github.com/cryptodev-linux/cryptodev-linux/blob/da730106c2558c8e0c8e1b1b1812d32ef9574ab7/examples/sha.c

正如其他人所提到的,内核似乎没有将加密API直接暴露给用户空间,这很遗憾,因为内核已经可以在内部使用本地硬件加速的加密函数。

cryptodev支持的加密操作:https://github.com/nmav/cryptodev-linux/blob/383922cabeea7dca354415e8c590f8e932f4d7a8/crypto/cryptodev.h

Linux x86支持的加密操作:https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/x86/crypto?id=refs/tags/v4.0


1
如何在内核空间中执行SHA1 / MD5和Blowfish / AES。
使用两个元素的散列列表对数据进行哈希处理的示例:
struct crypto_hash *tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
if (tfm == NULL)
    fail;
char *output_buf = kmalloc(crypto_hash_digestsize(tfm), GFP_KERNEL);
if (output_buf == NULL)
    fail;
struct scatterlist sg[2];
struct hash_desc desc = {.tfm = tfm};
ret = crypto_hash_init(&desc);
if (ret != 0)
    fail;
sg_init_table(sg, ARRAY_SIZE(sg));
sg_set_buf(&sg[0], "Hello", 5);
sg_set_buf(&sg[1], " World", 6);
ret = crypto_hash_digest(&desc, sg, 11, output_buf);
if (ret != 0)
    fail;

1

一个关键的注意事项:

永远不要比较crypto_alloc_hash函数的返回值与NULL来检测失败。

步骤:

始终使用IS_ERR函数进行此操作。与NULL进行比较无法捕获错误,因此您稍后会出现分段错误。

如果IS_ERR返回失败,则可能在内核映像(或作为模块)中缺少加密算法。请确保您已从make menuconfig中选择了适当的加密算法。


1

最好的起点是内核源代码中 Documentation/crytpo 目录。dm-crypt 是使用内核加密 API 的许多组件之一,您可以参考它以了解其用法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接