linux 内核里实现了crypto模块,其用法介绍的很少:
参考:linux-3.18.21/Documentation/crypto/api-intro.txt
Here’s an example of how to use the API:
#include <linux/crypto.h>
#include <linux/err.h>
#include <linux/scatterlist.h>
struct scatterlist sg[2];
char result[128];
struct crypto_hash *tfm;
struct hash_desc desc;tfm = crypto_alloc_hash(“md5”, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm))
fail();/* … set up the scatterlists … */
desc.tfm = tfm;
desc.flags = 0;if (crypto_hash_digest(&desc, sg, 2, result))
fail();
crypto_free_hash(tfm);Many real examples are available in the regression test module (tcrypt.c).
这提到 Many real examples are available in the regression test module (tcrypt.c).
这里就来看一下 linux-3.18.21/crypto/tcrypt.c
tcrypt.c
tcrypt_test("cbc(aes");
alg_test(alg, alg, 0, 0);
i = alg_find_test(alg);
alg_test_descs[i].test(alg_test_descs + i, driver,type, mask);
//alg_test_descs 是一个全局结构体数组,部分数据如下:
{
.alg = "cbc(aes)",
.test = alg_test_skcipher, //测试函数
.fips_allowed = 1,
.suite = {
.cipher = {
.enc = {
.vecs = aes_cbc_enc_tv_template, //测试数据
.count = AES_CBC_ENC_TEST_VECTORS
},
.dec = {
.vecs = aes_cbc_dec_tv_template,
.count = AES_CBC_DEC_TEST_VECTORS
}
}
}
static struct cipher_testvec aes_cbc_enc_tv_template[] = {
{ /* From RFC 3602 */
.key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
"\x51\x2e\x03\xd5\x34\x12\x00\x06",
.klen = 16,
.iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
"\xb4\x22\xda\x80\x2c\x9f\xac\x41",
.input = "Single block msg",
.ilen = 16,
.result = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
"\x27\x08\x94\x2d\xbe\x77\x18\x1a",
.rlen = 16,
},
...
}
static struct cipher_testvec aes_cbc_dec_tv_template[] = {
{ /* From RFC 3602 */
.key = "\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
"\x51\x2e\x03\xd5\x34\x12\x00\x06",
.klen = 16,
.iv = "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
"\xb4\x22\xda\x80\x2c\x9f\xac\x41",
.input = "\xe3\x53\x77\x9c\x10\x79\xae\xb8"
"\x27\x08\x94\x2d\xbe\x77\x18\x1a",
.ilen = 16,
.result = "Single block msg",
.rlen = 16,
},
继续跟踪 alg_test_skcipher
static int alg_test_skcipher(const struct alg_test_desc *desc, const char *driver, u32 type, u32 mask)
struct crypto_ablkcipher *tfm;
tfm = crypto_alloc_ablkcipher(driver, type, mask);
test_skcipher(tfm, ENCRYPT, desc->suite.cipher.enc.vecs,desc->suite.cipher.enc.count);
ret = __test_skcipher(tfm, enc, template, tcount, false, 0);
init_completion(&result.completion);
req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
tcrypt_complete, &result);
for (i = 0; i < tcount; i++) {
memcpy(iv, template[i].iv, MAX_IVLEN);
j++;
ret = -EINVAL;
data = xbuf[0];
data += align_offset;
memcpy(data, template[i].input, template[i].ilen);
crypto_ablkcipher_clear_flags(tfm, ~0);
ret = crypto_ablkcipher_setkey(tfm, template[i].key,
template[i].klen);
sg_init_one(&sg[0], data, template[i].ilen);
if (diff_dst) {
data = xoutbuf[0];
data += align_offset;
sg_init_one(&sgout[0], data, template[i].ilen);
}
ablkcipher_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
template[i].ilen, iv);
ret = enc ? crypto_ablkcipher_encrypt(req) :
crypto_ablkcipher_decrypt(req);
switch (ret) {
case 0:
break;
case -EINPROGRESS:
case -EBUSY:
ret = wait_for_completion_interruptible(
&result.completion);
if (!ret && !((ret = result.err))) {
reinit_completion(&result.completion);
break;
}
/* fall through */
default:
pr_err("alg: skcipher%s: %s failed on test %d for %s: ret=%d\n",
d, e, j, algo, -ret);
goto out;
}
q = data;
if (memcmp(q, template[i].result, template[i].rlen)) {
pr_err("alg: skcipher%s: Test %d failed on %s for %s\n",
d, j, e, algo);
hexdump(q, template[i].rlen);
ret = -EINVAL;
goto out;
}
}
自己写一个测试代码:
#include <crypto/hash.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <crypto/rng.h>
#include <crypto/drbg.h>
#include <linux/init.h>
#include <linux/gfp.h>
#include <linux/scatterlist.h>
#include <linux/moduleparam.h>
#include <linux/jiffies.h>
#include <linux/timex.h>
#include <linux/interrupt.h>
static char *alg = NULL;
struct tcrypt_result {
struct completion completion;
int err;
};
static void hexdump(unsigned char *buf, unsigned int len)
{
print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
16, 1,
buf, len, false);
}
static void tcrypt_complete(struct crypto_async_request *req, int err)
{
struct tcrypt_result *res = req->data;
if (err == -EINPROGRESS)
return;
res->err = err;
complete(&res->completion);
}
/*
static struct cipher_testvec aes_enc_tv_template[] = {
{
.key = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
.klen = 16,
.input = "\x00\x11\x22\x33\x44\x55\x66\x77"
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff",
.ilen = 16,
.result = "\x69\xc4\xe0\xd8\x6a\x7b\x04\x30"
"\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a",
.rlen = 16,
},
*/
int test(void)
{
char *key = "\x00\x01\x02\x03\x04\x05\x06\x07"
"\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
int keylen = 16;
char *str_input = "\x00\x11\x22\x33\x44\x55\x66\x77"
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff";
char *str_iv = "\x00\x11\x22\x33\x44\x55\x66\x77"
"\x88\x99\xaa\xbb\xcc\xdd\xee\xff";
int inputlen = 16;
char iv[32];
struct scatterlist sg[2];
struct scatterlist sg2[2];
char *input;
char *output;
char *denc;
struct ablkcipher_request *req;
struct crypto_ablkcipher *tfm;
struct tcrypt_result result;
int ret ;
input = (void *)__get_free_page(GFP_KERNEL);
//memcpy( iv,"test iv",strlen("test iv"));
memset(iv,0,sizeof(iv));
memcpy(input,str_input,inputlen);
output = (void *)__get_free_page(GFP_KERNEL);
denc = (void *)__get_free_page(GFP_KERNEL);
char *driver = "ecb(aes)";
if(alg)
{
driver = alg;
}
printk("alg : %s\n",driver);
if(strcmp(driver,"ecb(aes)")) // !="ecb(aes)"
{
memcpy(iv,str_iv,16);
}
//1.加密
tfm = crypto_alloc_ablkcipher(driver, 0, 0);
if (IS_ERR(tfm)) {
printk(KERN_ERR "alg: skcipher: Failed to load transform for "
"%s: %ld\n", driver, PTR_ERR(tfm));
return PTR_ERR(tfm);
}
init_completion(&result.completion);
req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
if(!req)
{
printk("error req = null\n");
crypto_free_ablkcipher(tfm);
return -1;
}
ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
tcrypt_complete, &result);
crypto_ablkcipher_clear_flags(tfm, ~0);
//set key
crypto_ablkcipher_setkey(tfm, key,keylen );
//sg init
sg_init_one(&sg[0], input, inputlen);
sg_init_one(&sg[1], output, inputlen);
//set iv
ablkcipher_request_set_crypt(req, &sg[0], &sg[1],inputlen , iv);
//开始加密
ret = crypto_ablkcipher_encrypt(req);
if(ret == -EINPROGRESS || ret == -EBUSY)
{
ret = wait_for_completion_interruptible(
&result.completion);
if (!ret && !((ret = result.err)))
{
reinit_completion(&result.completion);
}
}
else if(ret == 0)
{
printk("succ\n");
}
else
{
printk("error ret = %d\n",ret);
goto _err;
}
hexdump(output,16);
//2.解密
sg_init_one(&sg2[0], output,inputlen);
sg_init_one(&sg2[1], denc,inputlen );
crypto_ablkcipher_clear_flags(tfm, ~0);
if(strcmp(driver,"ecb(aes)")) // !="ecb(aes)"
{
memcpy(iv,str_iv,16);
}
ablkcipher_request_set_crypt(req, &sg2[0], &sg2[1],inputlen , iv);
ret = crypto_ablkcipher_decrypt(req);
if(ret == -EINPROGRESS || ret == -EBUSY)
{
ret = wait_for_completion_interruptible(
&result.completion);
if (!ret && !((ret = result.err)))
{
reinit_completion(&result.completion);
}
}
else if(ret == 0)
{
printk("succ\n");
//printk("%s \n",denc);
}
else
{
printk("error ret = %d\n",ret);
goto _err;
}//*/
hexdump(denc,16);
_err:
ablkcipher_request_free(req);
crypto_free_ablkcipher(tfm);
return -1; //恒定返回-1 ,免得insmod 后每次需要先rmmod
}
static int __init test_init(void)
{
test();
}
static void __exit test_exit(void)
{
}
module_init(test_init);
module_exit(test_exit);
module_param(alg, charp, 0);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("lql@lql.com");
测试
root@100:/lib/modules/3.18.21# insmod /tmp/test_kernal_crypto.ko alg="cbc(aes)"
[ 9332.350000] alg : cbc(aes)
[ 9332.350000] succ
[ 9332.360000] 00000000: c6 a1 3b 37 87 8f 5b 82 6f 4f 81 62 a1 c8 d8 79
[ 9332.370000] succ
[ 9332.370000] retire_capture_urb: 11 callbacks suppressed
[ 9332.390000] 00000000: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
failed to insert /tmp/test_kernal_crypto.ko
root@100:/lib/modules/3.18.21# insmod /tmp/test_kernal_crypto.ko alg="ctr(aes)"
[ 9335.680000] alg : ctr(aes)
[ 9335.680000] succ
[ 9335.690000] 00000000: 69 d5 c2 eb 2e 2e 62 47 50 54 1d 3b bc 69 2b a5
[ 9335.700000] succ
[ 9335.700000] 00000000: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
failed to insert /tmp/test_kernal_crypto.ko
root@100:/lib/modules/3.18.21# insmod /tmp/test_kernal_crypto.ko
[ 9340.790000] alg : ecb(aes)
[ 9340.790000] succ
[ 9340.800000] 00000000: 69 c4 e0 d8 6a 7b 04 30 d8 cd b7 80 70 b4 c5 5a
[ 9340.810000] succ
[ 9340.810000] retire_capture_urb: 20 callbacks suppressed
[ 9340.820000] 00000000: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
failed to insert /tmp/test_kernal_crypto.ko
root@G100:/lib/modules/3.18.21#
总结:
要学习 linux crypto API ,可以直接参考 linux-3.18.21/crypto/tcrypt.c