我已经寻找了一段时间,但还没有找到足够的文档/示例来说明如何使用 linux 附带的 CryptoAPI 创建系统调用/在内核空间中。
如果有人知道好的来源请告诉我,我想知道如何仅在内核空间内执行 SHA1 / MD5 和 Blowfish / AES。
#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");
内核中有几个地方使用了加密模块:eCryptfs 文件系统 (linux/fs/ecryptfs/) 和 802.11 无线堆栈 (linux/drivers/staging/rtl8187se/ieee80211/)。这两者都使用 AES,但您也许可以将您发现的内容推断为 MD5。
另一个很好的例子来自 security/seclvl.c 中的 2.6.18 内核源代码
注意:如果需要,您可以更改 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;
}
Cryptodev-linux
https://github.com/cryptodev-linux/cryptodev-linux
它是一个内核模块,通过
/dev/crypto
向用户空间公开内核加密 API。
正如其他人提到的,内核似乎没有向用户空间本身公开加密 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
最好的起点是内核源代码中的 Documentation/crytpo。 dm-crypt 是可能使用内核加密 API 的众多组件之一,您可以参考它来了解用法。
如何仅在内核空间内执行 SHA1 / MD5 和 Blowfish / AES。
使用二元素分散列表对数据进行哈希处理的示例:
struct crypto_hash *tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC); 如果(tfm == NULL) 失败; char *output_buf = kmalloc(crypto_hash_digestsize(tfm), GFP_KERNEL); 如果(输出缓冲区== NULL) 失败; 结构分散列表 sg[2]; struct hash_desc desc = {.tfm = tfm}; ret = crypto_hash_init(&desc); 如果(ret!= 0) 失败; sg_init_table(sg, ARRAY_SIZE(sg)); sg_set_buf(&sg[0], "你好", 5); sg_set_buf(&sg[1], "世界", 6); ret = crypto_hash_digest(&desc, sg, 11, output_buf); 如果(ret!= 0) 失败;
一个重要说明:
切勿将
crypto_alloc_hash
函数的返回值与 NULL 进行比较来检测失败。
步骤:
始终使用
IS_ERR
功能来实现此目的。与 NULL
相比不会捕获错误,因此稍后会出现分段错误。
如果 IS_ERR 返回失败,则可能缺少编译到内核映像(或作为模块)的加密算法。确保您选择了适当的加密算法。形成
make menuconfig
。