Crypto is an important part of the Linux kernel source code. One can tell from the standalone crypto directory under the kernel source tree. Device drivers, file system and security all need crypto. This post does not help understand the implementation of Linux kernel crypto API. Instead, a working kernel module is provided to show how to use the kernel crypto API.
0. R.t.D.C.
/* * sha1_mod.c * A kernel module using SHA1 and Linux kernel crypto API * Reference: http://stackoverflow.com/questions/3869028/how-to-use-cryptoapi-in-the-linux-kernel-2-6 * Jun 9, 2014 * root@davejingtian.org * http://davejingtian.org */ #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, j; 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); if (IS_ERR(tfm)) { printk(KERN_ERR "daveti: tfm allocation failed\n"); return 0; } desc.tfm = tfm; desc.flags = 0; //crypto_hash_init(&desc); //daveti: NOTE, crypto_hash_init is needed //for every new hasing! for (j = 0; j < 3; j++) { crypto_hash_init(&desc); sg_init_one(&sg, buf, 10); crypto_hash_update(&desc, &sg, 10); crypto_hash_final(&desc, output); for (i = 0; i < 20; i++) { printk(KERN_ERR "%02x", output[i]); } printk(KERN_INFO "\n---------------\n"); memset(output, 0x00, SHA1_LENGTH); } 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("GPL"); MODULE_AUTHOR("daveti");
1. Pitfalls
As one might have known already, when we are trying to call crypto API for SHA1, we are querying the crypto manager (cryptomgr) eventually – a kernel thread maintains different algorithm instances and handles crypto operation requests all over the kernel. The truth is if crypto API is called, like crypto_alloc_hash(), before the cryptomgr is initialized during the kernel booting process, then NULL would be return. Make sure the crypto API is called after cryptomgr. Otherwise, you have to provide your own implementation.
If you are working in an IRQ context, be aware that some older crypto APIs may cause trouble. Based on my experience working on CentOS 6 with kernel 2.6.32, crypto_hash_digest() does not work. Instead, crypto_hash_final() works well.
Pingback: Kernel Hacking – use crypto API in the IRQ context | davejingtian.org
Hey very cool web site!! Guuy .. Beautiful .. Amazing ..
I’ll bookmark your bllg and take the feeds also? I’m satisfied too seek out numerous useful
info here in the post, we need work outt more techniques
in this regard, thanks for sharing. . . . . .
#include
#include
#include
#include
#include
#include
#define SHA1_LENGTH 20
int sha1_test_in_kernel_4_9(void) {
struct scatterlist sg;
struct crypto_ahash *tfm;
struct ahash_request *req;
unsigned char buf[SHA1_LENGTH];
unsigned char result[SHA1_LENGTH];
printk(KERN_INFO “sha1: %s\n”, __FUNCTION__);
memset(buf, ‘A’, SHA1_LENGTH);
memset(result, 0x00, sizeof(result));
print_hex_dump(KERN_INFO, “buf: “, DUMP_PREFIX_NONE, 16, 1, buf, sizeof(buf), true);
tfm = crypto_alloc_ahash(“sha1”, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm)) {
printk(KERN_ERR “tfm allocation failed\n”);
return -1;
}
/* … set up the scatterlists … */
sg_init_one(&sg, buf, SHA1_LENGTH);
req = ahash_request_alloc(tfm, GFP_ATOMIC);
if (!req) {
printk(KERN_ERR “ahash_request_alloc() failed\n”);
return -2;
}
ahash_request_set_callback(req, 0, NULL, NULL);
ahash_request_set_crypt(req, &sg, result, SHA1_LENGTH);
if (crypto_ahash_digest(req)) {
printk(KERN_ERR “crypto_ahash_digest() failed\n”);
return -3;
}
ahash_request_free(req);
crypto_free_ahash(tfm);
print_hex_dump(KERN_INFO, “result: “, DUMP_PREFIX_OFFSET, 16, 1, result, sizeof(result), true);
// check result with cmd:
// $ echo -n AAAAAAAAAAAAAAAAAAAA | sha1sum –
// ebd3d4adf97066c84b8ed17d6bd1e270818763e0 –
return 0;
}