我已经寻找了一段时间,但是没有找到足够的文档/示例,说明如何在内核空间中使用linux附带的CryptoAPI来创建系统调用。
如果有人知道一个好的来源,请告诉我,我想知道如何仅在内核空间中执行SHA1 / MD5和Blowfish / AES。
我已经寻找了一段时间,但是没有找到足够的文档/示例,说明如何在内核空间中使用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");
另一个很好的例子来自于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;
}
内核中有几个使用加密模块的地方:eCryptfs文件系统(linux/fs/ecryptfs/)和802.11无线堆栈(linux/drivers/staging/rtl8187se/ieee80211/)。这两者都使用AES,但您可能能够将其推广到MD5。
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
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;
一个关键的注意事项:
永远不要比较crypto_alloc_hash
函数的返回值与NULL来检测失败。
步骤:
始终使用IS_ERR
函数进行此操作。与NULL
进行比较无法捕获错误,因此您稍后会出现分段错误。
如果IS_ERR返回失败,则可能在内核映像(或作为模块)中缺少加密算法。请确保您已从make menuconfig
中选择了适当的加密算法。
最好的起点是内核源代码中 Documentation/crytpo 目录。dm-crypt 是使用内核加密 API 的许多组件之一,您可以参考它以了解其用法。