/* * cryptosk.c */ #include #include #include #include #include #define SYMMETRIC_KEY_LENGTH 32 #define CIPHER_BLOCK_SIZE 16 struct tcrypt_result { struct completion completion; int err; }; struct skcipher_def { struct scatterlist sg; struct crypto_skcipher *tfm; struct skcipher_request *req; struct tcrypt_result result; char *scratchpad; char *ciphertext; char *ivdata; }; static struct skcipher_def sk; static void test_skcipher_finish(struct skcipher_def *sk) { if (sk->tfm) crypto_free_skcipher(sk->tfm); if (sk->req) skcipher_request_free(sk->req); if (sk->ivdata) kfree(sk->ivdata); if (sk->scratchpad) kfree(sk->scratchpad); if (sk->ciphertext) kfree(sk->ciphertext); } static int test_skcipher_result(struct skcipher_def *sk, int rc) { switch (rc) { case 0: break; case -EINPROGRESS || -EBUSY: rc = wait_for_completion_interruptible(&sk->result.completion); if (!rc && !sk->result.err) { reinit_completion(&sk->result.completion); break; } pr_info("skcipher encrypt returned with %d result %d\n", rc, sk->result.err); break; default: pr_info("skcipher encrypt returned with %d result %d\n", rc, sk->result.err); break; } init_completion(&sk->result.completion); return rc; } static void test_skcipher_callback(struct crypto_async_request *req, int error) { struct tcrypt_result *result = req->data; if (error == -EINPROGRESS) return; result->err = error; complete(&result->completion); pr_info("Encryption finished successfully\n"); /* decrypt data */ #if 0 memset((void*)sk.scratchpad, '-', CIPHER_BLOCK_SIZE); ret = crypto_skcipher_decrypt(sk.req); ret = test_skcipher_result(&sk, ret); if (ret) return; sg_copy_from_buffer(&sk.sg, 1, sk.scratchpad, CIPHER_BLOCK_SIZE); sk.scratchpad[CIPHER_BLOCK_SIZE-1] = 0; pr_info("Decryption request successful\n"); pr_info("Decrypted: %s\n", sk.scratchpad); #endif } static int test_skcipher_encrypt(char *plaintext, char *password, struct skcipher_def *sk) { int ret = -EFAULT; unsigned char key[SYMMETRIC_KEY_LENGTH]; if (!sk->tfm) { sk->tfm = crypto_alloc_skcipher("cbc-aes-aesni", 0, 0); if (IS_ERR(sk->tfm)) { pr_info("could not allocate skcipher handle\n"); return PTR_ERR(sk->tfm); } } if (!sk->req) { sk->req = skcipher_request_alloc(sk->tfm, GFP_KERNEL); if (!sk->req) { pr_info("could not allocate skcipher request\n"); ret = -ENOMEM; goto out; } } skcipher_request_set_callback(sk->req, CRYPTO_TFM_REQ_MAY_BACKLOG, test_skcipher_callback, &sk->result); /* clear the key */ memset((void *)key, '\0', SYMMETRIC_KEY_LENGTH); /* Use the world's favourite password */ sprintf((char *)key, "%s", password); /* AES 256 with given symmetric key */ if (crypto_skcipher_setkey(sk->tfm, key, SYMMETRIC_KEY_LENGTH)) { pr_info("key could not be set\n"); ret = -EAGAIN; goto out; } pr_info("Symmetric key: %s\n", key); pr_info("Plaintext: %s\n", plaintext); if (!sk->ivdata) { /* see https://en.wikipedia.org/wiki/Initialization_vector */ sk->ivdata = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL); if (!sk->ivdata) { pr_info("could not allocate ivdata\n"); goto out; } get_random_bytes(sk->ivdata, CIPHER_BLOCK_SIZE); } if (!sk->scratchpad) { /* The text to be encrypted */ sk->scratchpad = kmalloc(CIPHER_BLOCK_SIZE, GFP_KERNEL); if (!sk->scratchpad) { pr_info("could not allocate scratchpad\n"); goto out; } } sprintf((char *)sk->scratchpad, "%s", plaintext); sg_init_one(&sk->sg, sk->scratchpad, CIPHER_BLOCK_SIZE); skcipher_request_set_crypt(sk->req, &sk->sg, &sk->sg, CIPHER_BLOCK_SIZE, sk->ivdata); init_completion(&sk->result.completion); /* encrypt data */ ret = crypto_skcipher_encrypt(sk->req); ret = test_skcipher_result(sk, ret); if (ret) goto out; pr_info("Encryption request successful\n"); out: return ret; } static int cryptoapi_init(void) { /* The world's favorite password */ char *password = "password123"; sk.tfm = NULL; sk.req = NULL; sk.scratchpad = NULL; sk.ciphertext = NULL; sk.ivdata = NULL; test_skcipher_encrypt("Testing", password, &sk); return 0; } static void cryptoapi_exit(void) { test_skcipher_finish(&sk); } module_init(cryptoapi_init); module_exit(cryptoapi_exit); MODULE_DESCRIPTION("Symmetric key encryption example"); MODULE_LICENSE("GPL");