Skip to content

Linux 内核 Crypto 子系统同步加密机制分析 ​

目录 ​

  1. 概述
  2. SKCIPHER 接口
  3. LSKCIPHER 接口
  4. 块加密算法实现
  5. 加密模式实现
  6. 加密流程分析
  7. 数据结构关系图

1. 概述 ​

1.1 Crypto 子系统架构 ​

Linux 内核 Crypto 子系统提供了一套统一的接口用于对称加密、非对称加密、哈希、AEAD 等密码学操作。本文档重点分析同步对称加密机制。

用户空间
    │
    ▼
┌─────────────────────────────────────────────────────────────┐
│                   Crypto API 层                             │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐        │
│  │  skcipher  │  │  lskcipher  │  │    aead     │        │
│  └─────────────┘  └─────────────┘  └─────────────┘        │
└─────────────────────────────────────────────────────────────┘
    │                   │                   │
    ▼                   ▼                   ▼
┌─────────────────────────────────────────────────────────────┐
│                   模式层 (ECB/CBC/CTR/GCM)                   │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐        │
│  │   ECB   │  │   CBC   │  │   CTR   │  │   GCM   │        │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘        │
└─────────────────────────────────────────────────────────────┘
    │                   │                   │
    ▼                   ▼                   ▼
┌─────────────────────────────────────────────────────────────┐
│                   底层算法层                                 │
│  ┌─────────┐  ┌─────────┐  ┌─────────┐  ┌─────────┐        │
│  │   AES   │  │   DES   │  │   SM4   │  │   ...   │        │
│  └─────────┘  └─────────┘  └─────────┘  └─────────┘        │
└─────────────────────────────────────────────────────────────┘
    │                   │                   │
    ▼                   ▼                   ▼
┌─────────────────────────────────────────────────────────────┐
│              硬件加速层 (ARCH-specific)                     │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐                 │
│  │ x86/AES-NI│  │ ARM/NEON │  │  RISC-V  │                 │
│  └──────────┘  └──────────┘  └──────────┘                 │
└─────────────────────────────────────────────────────────────┘

1.2 核心文件位置 ​

文件功能
/crypto/skcipher.cSKCIPHER 接口实现
/crypto/lskcipher.cLSKCIPHER 接口实现
/crypto/cipher.c单块密码操作
/crypto/cbc.cCBC 模式
/crypto/ctr.cCTR 模式
/crypto/gcm.cGCM 模式 (AEAD)
/crypto/aes.cAES 算法
/include/crypto/skcipher.hSKCIPHER 头文件
/include/crypto/internal/skcipher.h内部 SKCIPHER 接口
/include/crypto/aes.hAES 头文件

2. SKCIPHER 接口 ​

2.1 核心数据结构 ​

struct skcipher_request (include/crypto/skcipher.h:40-51) ​

c
struct skcipher_request {
    unsigned int cryptlen;    // 加密/解密数据长度

    u8 *iv;                  // 初始化向量

    struct scatterlist *src; // 源数据 scatter-gather 列表
    struct scatterlist *dst;  // 目标数据 scatter-gather 列表

    struct crypto_async_request base;  // 基础异步请求

    void *__ctx[] CRYPTO_MINALIGN_ATTR;  // 私有上下文
};

struct crypto_skcipher (include/crypto/skcipher.h:53-57) ​

c
struct crypto_skcipher {
    unsigned int reqsize;     // 请求上下文大小
    struct crypto_tfm base;   // 基础 TFM (Transform)
};

struct skcipher_alg (include/crypto/skcipher.h:151-167) ​

c
struct skcipher_alg {
    int (*setkey)(struct crypto_skcipher *tfm, const u8 *key,
                  unsigned int keylen);
    int (*encrypt)(struct skcipher_request *req);
    int (*decrypt)(struct skcipher_request *req);
    int (*export)(struct skcipher_request *req, void *out);
    int (*import)(struct skcipher_request *req, const void *in);
    int (*init)(struct crypto_skcipher *tfm);
    void (*exit)(struct crypto_skcipher *tfm);

    unsigned int walksize;

    union {
        struct SKCIPHER_ALG_COMMON;
        struct skcipher_alg_common co;
    };
};

2.2 crypto_alloc_skcipher() ​

位置: crypto/skcipher.c:636-640

c
struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name,
                                              u32 type, u32 mask)
{
    return crypto_alloc_tfm(alg_name, &crypto_skcipher_type, type, mask);
}

此函数用于分配一个对称密钥密码算法实例。

参数说明:

  • alg_name: 算法名称,如 "cbc(aes)"、"ecb(aes)" 等
  • type: 算法类型标志
  • mask: 算法掩码

返回值: 成功返回 crypto_skcipher 句柄,失败返回错误指针

2.3 crypto_skcipher_encrypt/decrypt() ​

位置: crypto/skcipher.c:435-459

c
int crypto_skcipher_encrypt(struct skcipher_request *req)
{
    struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
    struct skcipher_alg *alg = crypto_skcipher_alg(tfm);

    if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
        return -ENOKEY;
    if (alg->co.base.cra_type != &crypto_skcipher_type)
        return crypto_lskcipher_encrypt_sg(req);
    return alg->encrypt(req);
}
EXPORT_SYMBOL_GPL(crypto_skcipher_encrypt);

int crypto_skcipher_decrypt(struct skcipher_request *req)
{
    struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
    struct skcipher_alg *alg = crypto_skcipher_alg(tfm);

    if (crypto_skcipher_get_flags(tfm) & CRYPTO_TFM_NEED_KEY)
        return -ENOKEY;
    if (alg->co.base.cra_type != &crypto_skcipher_type)
        return crypto_lskcipher_decrypt_sg(req);
    return alg->decrypt(req);
}

2.4 crypto_skcipher_setkey() ​

位置: crypto/skcipher.c:398-432

c
int crypto_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
                           unsigned int keylen)
{
    struct skcipher_alg *cipher = crypto_skcipher_alg(tfm);
    unsigned long alignmask = crypto_skcipher_alignmask(tfm);
    int err;

    if (cipher->co.base.cra_type != &crypto_skcipher_type) {
        struct crypto_lskcipher **ctx = crypto_skcipher_ctx(tfm);
        crypto_lskcipher_clear_flags(*ctx, CRYPTO_TFM_REQ_MASK);
        crypto_lskcipher_set_flags(*ctx,
                       crypto_skcipher_get_flags(tfm) &
                       CRYPTO_TFM_REQ_MASK);
        err = crypto_lskcipher_setkey(*ctx, key, keylen);
        goto out;
    }

    if (keylen < cipher->min_keysize || keylen > cipher->max_keysize)
        return -EINVAL;

    if ((unsigned long)key & alignmask)
        err = skcipher_setkey_unaligned(tfm, key, keylen);
    else
        err = cipher->setkey(tfm, key, keylen);

out:
    if (unlikely(err)) {
        skcipher_set_needkey(tfm);
        return err;
    }

    crypto_skcipher_clear_flags(tfm, CRYPTO_TFM_NEED_KEY);
    return 0;
}

密钥设置流程:

  1. 检查密钥长度是否在算法支持范围内
  2. 处理未对齐的密钥(复制到对齐的缓冲区)
  3. 调用算法的 setkey 回调
  4. 成功清除 CRYPTO_TFM_NEED_KEY 标志

2.5 skcipher_walk 结构 ​

位置: include/crypto/internal/skcipher.h:57-96

c
struct skcipher_walk {
    union {
        struct {
            struct {
                const void *const addr;
            } virt;
        } src;
        struct scatter_walk in;    // 内部使用
    };

    union {
        struct {
            struct {
                void *const addr;
            } virt;
        } dst;
        struct scatter_walk out;   // 内部使用
    };

    unsigned int nbytes;           // 当前步骤处理的字节数
    unsigned int total;            // 剩余总字节数

    u8 *page;                      // 临时页面缓冲区
    u8 *buffer;                    // 临时对齐缓冲区
    u8 *oiv;                       // 原始 IV
    void *iv;                      // 当前 IV

    unsigned int ivsize;           // IV 大小
    int flags;                     // 行走标志
    unsigned int blocksize;         // 块大小
    unsigned int stride;            // 步进大小
    unsigned int alignmask;         // 对齐掩码
};

SKCIPHER_WALK 标志 (crypto/skcipher.c:31-36):

c
enum {
    SKCIPHER_WALK_SLOW = 1 << 0,   // 需要慢速路径
    SKCIPHER_WALK_COPY = 1 << 1,   // 需要复制
    SKCIPHER_WALK_DIFF = 1 << 2,   // 源和目标不同页
    SKCIPHER_WALK_SLEEP = 1 << 3,  // 允许睡眠
};

3. LSKCIPHER 接口 ​

3.1 概念 ​

LSKCIPHER (Linear Symmetric Key Cipher) 是 SKCIPHER 的简化版本,专门用于线性处理连续内存区域的同步加密操作。相比 SKCIPHER 的 scatter-gather 列表处理,LSKCIPHER 更适合直接内存块加密。

3.2 核心数据结构 ​

struct lskcipher_alg (include/crypto/skcipher.h:202-213) ​

c
struct lskcipher_alg {
    int (*setkey)(struct crypto_lskcipher *tfm, const u8 *key,
                  unsigned int keylen);
    int (*encrypt)(struct crypto_lskcipher *tfm, const u8 *src,
                   u8 *dst, unsigned len, u8 *siv, u32 flags);
    int (*decrypt)(struct crypto_lskcipher *tfm, const u8 *src,
                   u8 *dst, unsigned len, u8 *siv, u32 flags);
    int (*init)(struct crypto_lskcipher *tfm);
    void (*exit)(struct crypto_lskcipher *tfm);

    struct skcipher_alg_common co;
};

3.3 crypto_lskcipher_crypt_sg() ​

位置: crypto/lskcipher.c:158-199

LSKCIPHER 通过 scatter-gather 方式处理加密请求:

c
static int crypto_lskcipher_crypt_sg(struct skcipher_request *req,
                     int (*crypt)(struct crypto_lskcipher *tfm,
                                  const u8 *src, u8 *dst,
                                  unsigned len, u8 *ivs,
                                  u32 flags))
{
    struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
    struct crypto_lskcipher **ctx = crypto_skcipher_ctx(skcipher);
    u8 *ivs = skcipher_request_ctx(req);
    struct crypto_lskcipher *tfm = *ctx;
    struct skcipher_walk walk;
    unsigned ivsize;
    u32 flags;
    int err;

    ivsize = crypto_lskcipher_ivsize(tfm);
    ivs = PTR_ALIGN(ivs, crypto_skcipher_alignmask(skcipher) + 1);
    memcpy(ivs, req->iv, ivsize);

    flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP;

    if (req->base.flags & CRYPTO_SKCIPHER_REQ_CONT)
        flags |= CRYPTO_LSKCIPHER_FLAG_CONT;

    if (!(req->base.flags & CRYPTO_SKCIPHER_REQ_NOTFINAL))
        flags |= CRYPTO_LSKCIPHER_FLAG_FINAL;

    err = skcipher_walk_virt(&walk, req, false);

    while (walk.nbytes) {
        err = crypt(tfm, walk.src.virt.addr, walk.dst.virt.addr,
                    walk.nbytes, ivs,
                    flags & ~(walk.nbytes == walk.total ?
                    0 : CRYPTO_LSKCIPHER_FLAG_FINAL));
        err = skcipher_walk_done(&walk, err);
        flags |= CRYPTO_LSKCIPHER_FLAG_CONT;
    }

    memcpy(req->iv, ivs, ivsize);

    return err;
}

4. 块加密算法实现 ​

4.1 AES 算法 ​

struct aes_key (include/crypto/aes.h:113-116) ​

c
struct aes_key {
    struct aes_enckey;           // 加密密钥
    union aes_invkey_arch inv_k; // 解密密钥(等效逆 cipher)
};

aes_preparekey() (crypto/aes.c) ​

c
int aes_preparekey(struct aes_key *key, const u8 *in_key, size_t key_len)

此函数根据 FIPS-197 标准扩展密钥:

  • AES-128: 10 轮,16 字节密钥
  • AES-192: 12 轮,24 字节密钥
  • AES-256: 14 轮,32 字节密钥

aes_encrypt()/aes_decrypt() ​

位置: crypto/aes.c:22-34

c
static void crypto_aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
    const struct aes_key *key = crypto_tfm_ctx(tfm);
    aes_encrypt(key, out, in);
}

static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
{
    const struct aes_key *key = crypto_tfm_ctx(tfm);
    aes_decrypt(key, out, in);
}

4.2 crypto_cipher_encrypt_one() ​

位置: crypto/cipher.c:79-84

c
void crypto_cipher_encrypt_one(struct crypto_cipher *tfm,
                               u8 *dst, const u8 *src)
{
    cipher_crypt_one(tfm, dst, src, true);
}
EXPORT_SYMBOL_NS_GPL(crypto_cipher_encrypt_one, "CRYPTO_INTERNAL");

cipher_crypt_one() (crypto/cipher.c:58-77):

c
static inline void cipher_crypt_one(struct crypto_cipher *tfm,
                    u8 *dst, const u8 *src, bool enc)
{
    unsigned long alignmask = crypto_cipher_alignmask(tfm);
    struct cipher_alg *cia = crypto_cipher_alg(tfm);
    void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
        enc ? cia->cia_encrypt : cia->cia_decrypt;

    if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
        unsigned int bs = crypto_cipher_blocksize(tfm);
        u8 buffer[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
        u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);

        memcpy(tmp, src, bs);
        fn(crypto_cipher_tfm(tfm), tmp, tmp);
        memcpy(dst, tmp, bs);
    } else {
        fn(crypto_cipher_tfm(tfm), dst, src);
    }
}

功能说明:

  • 检查源/目标地址是否对齐
  • 如未对齐,使用临时缓冲区处理
  • 调用底层加密/解密函数

5. 加密模式实现 ​

5.1 ECB 模式 (Electronic Codebook) ​

ECB 是最简单的模式,将数据分成块,每块独立加密。

特点:

  • 相同明文块产生相同密文块(安全性问题)
  • 无法隐藏数据模式
  • 适合小块数据或随机数据

5.2 CBC 模式 (Cipher Block Chaining) ​

加密流程 ​

P0 →───→ XOR ───→ [AES Encrypt] ───→ C0
                ↑
               IV

P1 →───→ XOR ───→ [AES Encrypt] ───→ C1
                ↑
               C0

P2 →───→ XOR ───→ [AES Encrypt] ───→ C2
                ↑
               C1

crypto_cbc_encrypt_segment() (crypto/cbc.c:15-28) ​

c
static int crypto_cbc_encrypt_segment(struct crypto_lskcipher *tfm,
                      const u8 *src, u8 *dst, unsigned nbytes,
                      u8 *iv)
{
    unsigned int bsize = crypto_lskcipher_blocksize(tfm);

    for (; nbytes >= bsize; src += bsize, dst += bsize, nbytes -= bsize) {
        crypto_xor(iv, src, bsize);                      // 明文 XOR IV
        crypto_lskcipher_encrypt(tfm, iv, dst, bsize, NULL); // AES 加密
        memcpy(iv, dst, bsize);                          // 更新 IV
    }

    return nbytes;
}

crypto_cbc_encrypt_inplace() (crypto/cbc.c:30-51) ​

c
static int crypto_cbc_encrypt_inplace(struct crypto_lskcipher *tfm,
                      u8 *src, unsigned nbytes, u8 *oiv)
{
    unsigned int bsize = crypto_lskcipher_blocksize(tfm);
    u8 *iv = oiv;

    if (nbytes < bsize)
        goto out;

    do {
        crypto_xor(src, iv, bsize);                      // XOR IV
        crypto_lskcipher_encrypt(tfm, src, src, bsize, NULL); // 原地加密
        iv = src;                                        // 更新 IV

        src += bsize;
    } while ((nbytes -= bsize) >= bsize);

    memcpy(oiv, iv, bsize);

out:
    return nbytes;
}

CBC 解密流程 ​

C0 →───→ [AES Decrypt] ───→ XOR ───→ P0
                            ↑
                           IV

C1 →───→ [AES Decrypt] ───→ XOR ───→ P1
                            ↑
                           C0

注意: CBC 解密可以并行化(利用解密算法的特点)

crypto_cbc_decrypt_inplace() (crypto/cbc.c:94-120) ​

c
static int crypto_cbc_decrypt_inplace(struct crypto_lskcipher *tfm,
                      u8 *src, unsigned nbytes, u8 *iv)
{
    unsigned int bsize = crypto_lskcipher_blocksize(tfm);
    u8 last_iv[MAX_CIPHER_BLOCKSIZE];

    if (nbytes < bsize)
        goto out;

    /* Start of the last block. */
    src += nbytes - (nbytes & (bsize - 1)) - bsize;
    memcpy(last_iv, src, bsize);

    for (;;) {
        crypto_lskcipher_decrypt(tfm, src, src, bsize, NULL);
        if ((nbytes -= bsize) < bsize)
            break;
        crypto_xor(src, src - bsize, bsize);
        src -= bsize;
    }

    crypto_xor(src, iv, bsize);
    memcpy(iv, last_iv, bsize);

out:
    return nbytes;
}

5.3 CTR 模式 (Counter Mode) ​

特点 ​

  • 将块密码转换为流密码
  • 支持随机访问(并行加密/解密)
  • 无需填充

加密流程 ​

Counter → [AES Encrypt] → Keystream
                         ↓
Keystream XOR Plaintext → Ciphertext

crypto_ctr_crypt_segment() (crypto/ctr.c:46-70) ​

c
static int crypto_ctr_crypt_segment(struct skcipher_walk *walk,
                    struct crypto_cipher *tfm)
{
    void (*fn)(struct crypto_tfm *, u8 *, const u8 *) =
           crypto_cipher_alg(tfm)->cia_encrypt;
    unsigned int bsize = crypto_cipher_blocksize(tfm);
    u8 *ctrblk = walk->iv;
    const u8 *src = walk->src.virt.addr;
    u8 *dst = walk->dst.virt.addr;
    unsigned int nbytes = walk->nbytes;

    do {
        /* create keystream */
        fn(crypto_cipher_tfm(tfm), dst, ctrblk);   // 生成密钥流
        crypto_xor(dst, src, bsize);               // XOR 明文

        /* increment counter in counterblock */
        crypto_inc(ctrblk, bsize);                 // 计数器递增

        src += bsize;
        dst += bsize;
    } while ((nbytes -= bsize) >= bsize);

    return nbytes;
}

crypto_ctr_crypt() (crypto/ctr.c:99-125) ​

c
static int crypto_ctr_crypt(struct skcipher_request *req)
{
    struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
    struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
    const unsigned int bsize = crypto_cipher_blocksize(cipher);
    struct skcipher_walk walk;
    unsigned int nbytes;
    int err;

    err = skcipher_walk_virt(&walk, req, false);

    while (walk.nbytes >= bsize) {
        if (walk.src.virt.addr == walk.dst.virt.addr)
            nbytes = crypto_ctr_crypt_inplace(&walk, cipher);
        else
            nbytes = crypto_ctr_crypt_segment(&walk, cipher);

        err = skcipher_walk_done(&walk, nbytes);
    }

    if (walk.nbytes) {
        crypto_ctr_crypt_final(&walk, cipher);  // 处理最后的不完整块
        err = skcipher_walk_done(&walk, 0);
    }

    return err;
}

5.4 GCM 模式 (Galois/Counter Mode) ​

GCM 是提供认证加密 (AEAD) 的模式,结合了 CTR 加密和 GMAC 认证。

核心结构 ​

c
struct crypto_gcm_ctx {
    struct crypto_skcipher *ctr;   // CTR 模式加密
    struct crypto_aead *ghash;     // GHASH 认证
};

crypto_gcm_encrypt() (crypto/gcm.c:445-457) ​

c
static int crypto_gcm_encrypt(struct aead_request *req)
{
    struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
    struct skcipher_request *skreq = &pctx->u.skreq;
    u32 flags = aead_request_flags(req);

    crypto_gcm_init_common(req);      // 初始化
    crypto_gcm_init_crypt(req, req->cryptlen);
    skcipher_request_set_callback(skreq, flags, gcm_encrypt_done, req);

    return crypto_skcipher_encrypt(skreq) ?:
           gcm_encrypt_continue(req, flags);
}

GCM 加密流程 ​

  1. J0 = IV || 0^31 || 1 - 形成初始计数器
  2. C = E(K, J0 || counter) - CTR 模式加密
  3. S = GHASH(H, A || C || len(A) || len(C)) - 计算认证标签
  4. T = S XOR E(K, J0) - 生成最终认证标签

6. 加密流程分析 ​

6.1 完整加密流程图 ​

用户空间调用
    │
    ▼
┌─────────────────────────────────────────┐
│  1. 分配算法实例                         │
│  crypto_alloc_skcipher("cbc(aes)", ...)   │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  2. 设置密钥                             │
│  crypto_skcipher_setkey(tfm, key, ...)   │
│  ├── 验证密钥长度                         │
│  ├── 调用底层 setkey                      │
│  └── aes_expandkey() 扩展密钥             │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  3. 分配请求                             │
│  skcipher_request_alloc()                │
│  └── skcipher_request_set_crypt()        │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  4. 执行加密                             │
│  crypto_skcipher_encrypt(req)            │
│  ├── 检查 NEED_KEY 标志                   │
│  ├── 调用 alg->encrypt()                  │
│  └── skcipher_walk_virt()                 │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  5. Scatter-Gather 行走                   │
│  skcipher_walk_virt()                    │
│  ├── scatterwalk_start()                 │
│  ├── 处理跨页数据                         │
│  └── skcipher_walk_next()                │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  6. 模式加密                             │
│  crypto_cbc_encrypt_segment()            │
│  ├── crypto_xor() XOR 操作               │
│  └── crypto_lskcipher_encrypt()          │
│      └── aes_encrypt()  AES 块加密       │
└─────────────────────────────────────────┘
    │
    ▼
┌─────────────────────────────────────────┐
│  7. 完成行走                             │
│  skcipher_walk_done()                    │
│  ├── 更新 scatterlist 位置                │
│  ├── 处理剩余数据                         │
│  └── 返回结果                            │
└─────────────────────────────────────────┘

6.2 setkey 详细流程 ​

位置: crypto/skcipher.c:398-432

crypto_skcipher_setkey()
    │
    ├──► 检查算法类型是否为 skcipher_type
    │       │
    │       └──► 是: 直接调用 cipher->setkey()
    │           │
    │           └──► 否: 调用 crypto_lskcipher_setkey()
    │               └──► 处理未对齐密钥
    │
    ├──► 检查密钥长度 (min_keysize ~ max_keysize)
    │
    └──► 调用底层 setkey
            │
            └──► aes_preparekey()
                │
                ├──► aes_expandkey()
                │       │
                │       └──► 生成加密轮密钥
                │
                └──► 生成解密轮密钥 (inv_k)

6.3 加密操作详细流程 ​

CBC 模式加密示例:

skcipher_walk_virt() 初始化
    │
    ▼
while (walk.nbytes > 0) {
    │
    ├──► crypto_cbc_encrypt_segment()
    │       │
    │       ├──► for each block:
    │       │       │
    │       │       ├──► crypto_xor(plaintext, iv) → tmp
    │       │       │
    │       │       └──► crypto_lskcipher_encrypt(tfm, tmp, tmp)
    │       │               │
    │       │               └──► cipher->encrypt()
    │       │                       │
    │       │                       └──► aes_encrypt()
    │       │                               │
    │       │                               └──► 轮密钥加 → 字节替换 → 行移位 → 列混合
    │       │
    │       └──► memcpy(iv, ciphertext)
    │
    └──► skcipher_walk_done()
            │
            ├──► scatterwalk_advance()
            │
            └──► skcipher_walk_next()
}

7. 数据结构关系图 ​

7.1 核心数据结构关系 ​

┌─────────────────────────────────────────────────────────────────┐
│                        crypto_skcipher                          │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ unsigned int reqsize                                        ││
│  │ struct crypto_tfm base                                      ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ container_of
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      struct skcipher_alg                        │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ int (*setkey)(...)                                          ││
│  │ int (*encrypt)(struct skcipher_request *req)                 ││
│  │ int (*decrypt)(struct skcipher_request *req)                 ││
│  │ unsigned int walksize                                        ││
│  │ struct skcipher_alg_common co                               ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ 实例化
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      struct skcipher_request                     │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ unsigned int cryptlen                                        ││
│  │ u8 *iv                                                      ││
│  │ struct scatterlist *src                                      ││
│  │ struct scatterlist *dst                                      ││
│  │ struct crypto_async_request base                             ││
│  │ void *__ctx[]                                               ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
                              │
                              │ 用于遍历
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                        struct skcipher_walk                      │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │ union { src.virt.addr / scatter_walk in }                   ││
│  │ union { dst.virt.addr / scatter_walk out }                  ││
│  │ unsigned int nbytes                                         ││
│  │ unsigned int total                                          ││
│  │ u8 *page, *buffer, *oiv, *iv                                ││
│  │ unsigned int ivsize, blocksize, stride, alignmask            ││
│  │ int flags                                                   ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘

7.2 算法注册与查找 ​

crypto_register_skcipher(&alg)
    │
    ▼
skcipher_prepare_alg()
    │
    ├──► skcipher_prepare_alg_common()
    │       │
    │       └──► 验证 ivsize, chunksize, statesize
    │
    └──► 设置 cra_type = &crypto_skcipher_type
            │
            ▼
    crypto_register_alg()
        │
        ▼
    添加到 crypto_alg_list
        │
        ▼
    可通过 crypto_alloc_skcipher() 查找使用

7.3 Scatter-Gather 行走示意图 ​

初始状态:
    src: [Page 0 ] [Page 1 ] [Page 2 ]
         ████████████

walk.nbytes = 4096 (一页)
walk.total = 12000
walk.src.virt.addr → Page 0

第一次 skcipher_walk_next():
    ├──► n = min(stride, total) = 4096
    ├──► scatterwalk_clamp() 确保在单页内
    └──► walk.nbytes = 4096

第二次 skcipher_walk_next():
    ├──► scatterwalk_done() 推进到下一页
    └──► walk.src.virt.addr → Page 1

8. 使用示例 ​

8.1 同步 CBC-AES 加密 ​

c
#include <crypto/skcipher.h>
#include <linux/scatterlist.h>

int encrypt_example(void)
{
    struct crypto_skcipher *tfm;
    struct skcipher_request *req;
    struct scatterlist src, dst;
    u8 iv[AES_BLOCK_SIZE];
    u8 key[32];  // AES-256
    u8 plaintext[64];
    u8 ciphertext[64];
    int err;

    /* 1. 分配算法 */
    tfm = crypto_alloc_skcipher("cbc(aes)", 0, 0);
    if (IS_ERR(tfm))
        return PTR_ERR(tfm);

    /* 2. 设置密钥 */
    err = crypto_skcipher_setkey(tfm, key, 32);
    if (err)
        goto out_free_tfm;

    /* 3. 分配请求 */
    req = skcipher_request_alloc(tfm, GFP_KERNEL);
    if (!req) {
        err = -ENOMEM;
        goto out_free_tfm;
    }

    /* 4. 设置 IV */
    memcpy(iv, "\x00\x01\x02...", AES_BLOCK_SIZE);

    /* 5. 设置加密参数 */
    sg_init_one(&src, plaintext, 64);
    sg_init_one(&dst, ciphertext, 64);
    skcipher_request_set_crypt(req, &src, &dst, 64, iv);

    /* 6. 执行加密 */
    err = crypto_skcipher_encrypt(req);

    skcipher_request_free(req);
out_free_tfm:
    crypto_free_skcipher(tfm);
    return err;
}

8.2 同步 CTR-AES 加密 ​

c
int encrypt_ctr_example(void)
{
    struct crypto_skcipher *tfm;
    struct skcipher_request *req;
    struct scatterlist src, dst;
    u8 iv[16];  // CTR 模式使用 16 字节 IV
    u8 key[16]; // AES-128
    u8 plaintext[100];
    u8 ciphertext[100];
    int err;

    tfm = crypto_alloc_skcipher("ctr(aes)", 0, 0);
    if (IS_ERR(tfm))
        return PTR_ERR(tfm);

    err = crypto_skcipher_setkey(tfm, key, 16);
    if (err)
        goto out;

    req = skcipher_request_alloc(tfm, GFP_KERNEL);
    if (!req) {
        err = -ENOMEM;
        goto out;
    }

    memset(iv, 0, 16);  // 计数器初始值
    sg_init_one(&src, plaintext, 100);
    sg_init_one(&dst, ciphertext, 100);
    skcipher_request_set_crypt(req, &src, &dst, 100, iv);

    err = crypto_skcipher_encrypt(req);

    skcipher_request_free(req);
out:
    crypto_free_skcipher(tfm);
    return err;
}

9. 关键 API 总结 ​

9.1 分配与释放 ​

API位置功能
crypto_alloc_skcipher()skcipher.c:636分配 SKCIPHER 实例
crypto_free_skcipher()skcipher.h:327释放 SKCIPHER 实例
crypto_alloc_sync_skcipher()skcipher.c:643分配同步 SKCIPHER
skcipher_request_alloc()skcipher.h:846分配请求
skcipher_request_free()skcipher.h:865释放请求

9.2 密钥操作 ​

API位置功能
crypto_skcipher_setkey()skcipher.c:398设置密钥
crypto_sync_skcipher_setkey()skcipher.h:617同步设置密钥

9.3 加密/解密操作 ​

API位置功能
crypto_skcipher_encrypt()skcipher.c:435加密数据
crypto_skcipher_decrypt()skcipher.c:448解密数据

9.4 Scatter-Gather 操作 ​

API位置功能
skcipher_walk_virt()skcipher.c:283初始化 scatter-gather 行走
skcipher_walk_done()skcipher.c:71完成行走步骤

10. 总结 ​

Linux 内核 Crypto 子系统的同步加密机制通过 SKCIPHER 和 LSKCIPHER 接口提供了一套完整的对称加密抽象。主要特点包括:

  1. 分层架构: 从上到下分为 API 层、模式层、算法层和硬件加速层
  2. 统一接口: 通过 skcipher_request 结构支持各种加密模式和算法
  3. scatter-gather 支持: 通过 skcipher_walk 机制高效处理跨页数据
  4. 内存对齐处理: 自动处理未对齐的密钥和数据
  5. 模板机制: 通过 crypto_template 支持运行时创建算法实例(如 cbc(aes))

常用的加密模式:

  • ECB: 简单但不安全,不推荐使用
  • CBC: 适合常规加密,需要填充
  • CTR: 流密码模式,无需填充,支持随机访问
  • GCM: 提供认证加密 (AEAD),适合网络安全协议

基于 VitePress 构建