目录
密码算法介绍
Hash摘要算法
Cipher加解密算法
块密码算法
认证算法 MAC和HMAC
AEAD算法
Linux内核密码模块的基本构件
Linux内核密码模块介绍
如何使用Linux密码模块
用户层调用Linux内核密码模块的方法
cryptodev
AF_ALG
如何开发一个密码引擎驱动
开发一个密码引擎驱动的流程
以cbc(aes)算法为例的实际代码示例
密码算法主要是为了保护双方或者多方的通信,涉及到保密性、完整性和可认证性。
Hash或Digest是属于完整性,根据指定输入得到“唯一”校验值,比如SHA1,MD5,等等。
针对HASH算法的三个标准:
1、尽可能少的碰撞出相同的摘要值
2、不可能根据摘要值重新生成原数据
3、一个小的修改就能生成完成不同的摘要值
要求使用一组或者几组数据来加密/解密数据
Cipher算法可以分为流密码算法和块密码算法,还可以分为对称密码算法和非对称密码算法。
其中流密码算法是对一串流数据加密,块密码算法需要限定数据大小的数据块;
其中对称密码算法是指加解密都使用相同的密钥,非对称密码算法加密使用公钥,解密使用私钥。有AES,RSA算法等
块密码算法只能对一小块数据进行加解密,我们需要找个方法来处理任意长度的数据,大部分的块密码算法都要求有Initialization Vector(IV)来混淆加密数据。此算法模式有ECB,CBC等。
MAC代表消息认证码,用来认证发送者消息的机制,使用一组密钥和转化算法来生成认证码,使用HASH算法就叫HMAC。
AEAD算法表示对数据进行认证加密,把认证,加密和摘要一步完成。
Linux密码模块的基本构件主要为两个结构体:struct crypto_alg和struct crypto_tfm。支持所有的算法,比如Cipher(加解密)、Hash(摘要)、AEAD(链式)、HMAC(认证)和Compression(解压缩)。
密码算法可以用一个基本算法构建的模块来表示,比如hmac(sha1)表示用SHA1摘要实现的HMAC算法,cbc(aes)表示使用AES的CBC模式,authenc(hmac(sha1),cbc(aes))表示使用AES-CBC加解密和SHA1做认证的链式算法,即一次完成加密和认证。
使用Linux密码模块的流程如下图所示:
左侧为流程分割,右侧为对应的实现函数。
用户层调用Linux内核密码模块的方法有两种,一种是cryptodev,另一种是AF_ALG。
1、Linux内核密码模块并不区分硬件引擎与软件实现
2、开发一个密码引擎就只是通过向密码模块子系统注册crypto_alg
3、辨别你想新增算法的类型并与相关的crypto_alg接口绑定,比如skcipher_alg,ahash_alg等等
4、实现xxx_alg接口内容并调用crypto_register_xxx()来向密码子系统注册
struct skcipher_alg xxx_cbc_aes_alg = {
...
.base = {
/* Name used by the framework to find who is implementing what. */
.cra_name = "cbc(aes)",
/* Driver name. Can be used to request a specific implementation of an algorithm. */
.cra_driver_name = "xxx-cbc-aes",
/* Priority is used when implementation auto-selection takes place:
* if there are several implementers, the one with the highest priority is chosen.
* By convention: HW engine > ASM/arch-optimized > plain C
*/
.cra_priority = 300,
/* CRYPTO_ALG_TYPE_XX: describes the type algorithm implemented here
* CRYPTO_ALG_ASYNC: the engine is operating in an asynchronous manner
* CRYPTO_ALG_KERN_DRIVER_ONLY: engine is not directly accessible to userspace
*/
.cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC,
/* Size of the data blocks this algo operates on. */
.cra_blocksize = AES_BLOCK_SIZE,
/* Size of the context attached to an algorithm instance. */
.cra_ctxsize = sizeof(struct xxx_aes_ctx),
/* constructor/destructor methods called every time an alg instance is created/destroyed. */
.cra_init = xxx_skcipher_cra_init,
.cra_exit = xxx_skcipher_cra_exit,
},
};
struct skcipher_alg mv_cesa_cbc_aes_alg = {
/* Set key implementation. */
.setkey = xxx_aes_setkey,
/* Encrypt/decrypt implementation. */
.encrypt = xxx_cbc_aes_encrypt,
.decrypt = xxx_cbc_aes_decrypt,
/* Symmetric key size. */
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
/* IV size */
.ivsize = AES_BLOCK_SIZE,
.base = {
....
},
};
static int xxx_encrypt(struct skcipher_request *req)
{
struct my_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
/* Prepare and queue the request here. Return 0 if the request has
* been executed, -EINPROGRESS if it's been queued, -EBUSY if it's
* been backlogged or a different error code for other kind of
* errors.
*/
return ret;
}
static int xxx_decrypt(struct skcipher_request *req)
{
struct my_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
/* Similar to xxx_encrypt() except this time we prepare and queue
* a decrypt operation.
*/
return ret;
}
static int xxx_setkey(struct crypto_skcipher *cipher, const u8 *key,
unsigned int len)
{
struct my_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
/* Expand key and assing store the result in the ctx. */
return ret;
}