1 简述

storngswan的配置里用一种固定格式的字符串设置了用于协商的预定义算法。在包协商过程中strongswan将字符串转换为固定的枚举值封在数据包里用于传输。

协商成功之后,这组被协商选中的枚举值会通过netlink接口以xfrm定义好的字符串形式,传递给内核,内核再将字符串转换成pfkey定义的枚举值,最终进行加密设置。

DPDK的话,也有其统一的一组枚举值的抽象。在调用不同的cryptodev pmd时,会想这组值转换为对应的值或操作,如转变成openssl对应的API调用。

见下图:

1.1 名词解释

ICV:ICV有两种翻译,两种解释:Integrity Check Value, initial chaining vector。

通常我们把IV理解为: initial chaining vector; 把ICV理解为:Integrity Check Value

2 strongswan

在strongswan的配置里,算法是可以通过字符串进行配置的,这样的字符串如下:

esp_proposals = aes128-sha384-curve25519-esn,aes128-sha384-esn

逗号分隔的是两个套装。横线分隔的是不同的阶段,加密-认证-协商-是否esn

手册里有详细的解释:man  ipsec.conf

The notation is encryption-integrity[-dhgroup][-esnmode].

上面提到的是字符串格式的定义。具体的字符串到数据包中的值的定义,是在RFC中约定的,见文档:

https://wiki.strongswan.org/projects/strongswan/wiki/IKEv2CipherSuites

https://wiki.strongswan.org/projects/strongswan/wiki/IKEv1CipherSuites

3 netlink/xfrm

为了使用xfrm的统一接口,strongswan的netlink模块做了一次转换

见代码:kernel_netlink_ipsec.c

4 linux kernel

kernel的xfrm模块将netlink plugin传递过来的string转换成pfkey中定义的枚举。

xfrm部分的代码:xfrm_algo.c

pfkey中的枚举定义:linux/pfkeyv2.h

5 dpdk

dpdk中cryptodev同样也有自己的封装定义,按类别分为对称,非对称等。

算法的枚举值定义在这个地方: rte_crypto_sym.h

5.1 关键API:

int
rte_cryptodev_sym_session_init(uint8_t dev_id,
struct rte_cryptodev_sym_session *sess,
struct rte_crypto_sym_xform *xforms,
struct rte_mempool *mempool);

如,开篇那个图,所有的算法都是通过这个API注册进dpdk的。

在这个数据结构里,它是一个串在一起的链表,将加密算法和消息认证码算法串在一起作为参数传递。

struct rte_crypto_sym_xform {
struct rte_crypto_sym_xform *next;
/**< next xform in chain */
enum rte_crypto_sym_xform_type type
; /**< xform type */
RTE_STD_C11
union {
struct rte_crypto_auth_xform auth;
/**< Authentication / hash xform */
struct rte_crypto_cipher_xform cipher;
/**< Cipher xform */
struct rte_crypto_aead_xform aead;
/**< AEAD xform */
};
};

接下来逐个讨论加密,消息认证和aead的结构:

5.2 加密:

struct rte_crypto_cipher_xform {
enum rte_crypto_cipher_operation op; // 加密还是解密
enum rte_crypto_cipher_algorithm algo; // 哪一种加密算法
struct {
uint8_t *data;
uint16_t length;
} key; // 秘钥及其长度
struct {
uint16_t offset; // 对于块分组加密这里是初始化向量的起点(rte_crypto_op??),对于CRT分组加密,这里是counter, CCM的时候,第一个字节保留,第二个自己用来写入nonce
uint16_t length; // CRT的时候等于block length, CCM的时候是nonce的长度,7-13之间。
} iv;
};

5.3 消息认证:

struct rte_crypto_auth_xform {
enum rte_crypto_auth_operation op;
enum rte_crypto_auth_algorithm algo;
struct {
uint8_t *data;
uint16_t length; // 必须小于或等于 block size
} key;
struct {
uint16_t offset; // 初始化向量,需要八字节对齐
uint16_t length;
} iv;
uint16_t digest_length; // hash算法的截断长度
};

5.4 AEAD:

struct rte_crypto_aead_xform {
enum rte_crypto_aead_operation op;
enum rte_crypto_aead_algorithm algo;
struct {
uint8_t *data;
uint16_t length;
} key;
struct {
uint16_t offset; // CCM的时候,第一个字节保留,第二个字节用来写入nonce
uint16_t length; // CCM的时候,nonce的长度,7-13之间
} iv;
uint16_t digest_length;
uint16_t aad_length; // 附加验证长度??
};

前文的IV offset与一个结构体相关struct rte_crypto_op cop

这个结构体是作为参数传递给下面api的

static inline int
rte_crypto_op_attach_sym_session(struct rte_crypto_op *op,
struct rte_cryptodev_sym_session *sess)

在不使用rte_ipsec库的情况下,op中的一些值需要用户关心。使用rte_ipsec库的时候,一般不用关心。rte_ipsec将其封装在内部处理。

6 rte_ipsec

在rte_ipsec库中,围绕这前文提到的加密算法及其参数主要做了以下三方面的动作:

1. 通过API rte_cryptodev_sym_session_init()将算法和参数下发给底层的pmd设备。

2. 为每一个需要加解密的报文准备op(rte_crypto_op),然后attach进session里边。通过这个函数esp_inb_tun_cop_prepare() [librte_ipsec/sa.c]

3. 为每一个需要加解密的报文准备数据包的esp封装。通过这个函数esp_inb_tun_pkt_prepare() [librte_ipsec/sa.c]

所以在整个rte_ipsec库的使用过程中。只有保证以上3者的数据和设置可以正常配合,便能保证成功使用。

详见:[dev][dpdk][crypto] dpdk加解密设备与IPSEC

(另外:在分析rte_ipsec的源码过程中,并没有发现对API rte_crypto_op_attach_sym_session的调用。奇怪。。。)

7 strongswan libipsec

基于我们对于dpdk库的分析,此刻已经了解到,一个算法的基本构成单元,是由方法本身及一组参数构成的。参数为:key长度,iv长度,digest长度,盐等组成的。

现在回到strongswan,它的代码里边除了对rfc中各个函数的定义以为,一定还拥有这些参数值与办法定义直接的对应关系。

前文,我们已经知道与内核通信时的netlink plugin中对这部分参数在传递过程中进行了定义,但由于内核的支持有限,所以也并不完整。同时,strongswan也提供了一个用户态的esp实现,

叫做libipsec,根据文档中的描述,该库对rfc中的所有算法实现了完整的支持。接下来我们对这个库进行简要的分析。

进入这部分功能的入口在,函数 create_traditional() [/strongswan.git/src/libipsec/esp_context.c]中。

1. create_traditional() 会调用函数crypto_factory.c::create_crypter()

2. 之后会进入加解密plugin的create函数

METHOD(crypto_factory_t, create_crypter, crypter_t*,
private_crypto_factory_t *this, encryption_algorithm_t algo,
size_t key_size)
{
。。。 。。。
enumerator = this->crypters->create_enumerator(this->crypters);
while (enumerator->enumerate(enumerator, &entry))
{
。。。 。。。
crypter = entry->create_crypter(algo, key_size);
。。。 。。。
}
。。。 。。。
}

红色字体是一个函数指针,是由下文中的这个宏,注册进去的。

METHOD(plugin_t, get_features, int,
private_aes_plugin_t *this, plugin_feature_t *features[])
{
static plugin_feature_t f[] = {
PLUGIN_REGISTER(CRYPTER, aes_crypter_create),
... ...
};
... ...
}

故,逐个分析每一个算法plugin的实现,将能够得到具体的参数数值。

8 RFC

一些关于算法参数的细节除了可以查看7中的实现以外,我们还可以查看RFC。

所有RFC的列表可以从第二章的两个链接关联出来,便能针对不同的算法找到它所对应的RFC文件了。

在RFC中有对各种算法的参数特别详细的描写。

https://www.iana.org/assignments/ikev2-parameters/ikev2-parameters.xhtml

https://www.iana.org/assignments/ipsec-registry/ipsec-registry.xhtml

https://www.iana.org/assignments/isakmp-registry/isakmp-registry.xhtml

[dev][ipsec][dpdk] strongswan/dpdk源码分析之ipsec算法配置过程的更多相关文章

  1. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  2. SpringBoot源码分析之SpringBoot的启动过程

    SpringBoot源码分析之SpringBoot的启动过程 发表于 2017-04-30   |   分类于 springboot  |   0 Comments  |   阅读次数 SpringB ...

  3. Envoy 源码分析--程序启动过程

    目录 Envoy 源码分析--程序启动过程 初始化 main 入口 MainCommon 初始化 服务 InstanceImpl 初始化 启动 main 启动入口 服务启动流程 LDS 服务启动流程 ...

  4. Spring源码分析专题 —— IOC容器启动过程(上篇)

    声明 1.建议先阅读<Spring源码分析专题 -- 阅读指引> 2.强烈建议阅读过程中要参照调用过程图,每篇都有其对应的调用过程图 3.写文不易,转载请标明出处 前言 关于 IOC 容器 ...

  5. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  6. 死磕以太坊源码分析之Kademlia算法

    死磕以太坊源码分析之Kademlia算法 KAD 算法概述 Kademlia是一种点对点分布式哈希表(DHT),它在容易出错的环境中也具有可证明的一致性和性能.使用一种基于异或指标的拓扑结构来路由查询 ...

  7. Dubbo源码分析之ExtensionLoader加载过程解析

    ExtensionLoader加载机制阅读: Dubbo的类加载机制是模仿jdk的spi加载机制:  Jdk的SPI扩展加载机制:约定是当服务的提供者每增加一个接口的实现类时,需要在jar包的META ...

  8. tair源码分析——leveldb新增的CompactRangeSelfLevel过程

    tair是一个分布式KV存储引擎,当新增机器或者有机器down掉的时候,tair的dataserver会根据ConfigServer生成的新的对照表进行数据的迁移和清理.在数据清理的过程中就用到了在t ...

  9. 【Spring源码分析】原型Bean实例化过程、byName与byType及FactoryBean获取Bean源码实现

    原型Bean加载过程 之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式: & ...

  10. springMVC源码分析--HandlerInterceptor拦截器调用过程(二)

    在上一篇博客springMVC源码分析--HandlerInterceptor拦截器(一)中我们介绍了HandlerInterceptor拦截器相关的内容,了解到了HandlerInterceptor ...

随机推荐

  1. HDU - 1013

    wa了两遍: (1)没有弄清楚输入数据的范围,实际上是字符串输入,数字很大. (2)此题太水,没有标数据范围. #include<iostream> #include<cstdio& ...

  2. MVC中一般为什么用IQueryable而不是用IList?

    IList(IList<T>)会立即在内存里创建持久数据,这就没有实现“延期执行(deferred execution)”,如果被加载的实体有关联实体(associations),此关联实 ...

  3. 【深度学习】吴恩达网易公开课练习(class2 week1 task2 task3)

    正则化 定义:正则化就是在计算损失函数时,在损失函数后添加权重相关的正则项. 作用:减少过拟合现象 正则化有多种,有L1范式,L2范式等.一种常用的正则化公式 \[J_{regularized} = ...

  4. 论文阅读笔记四十四:RetinaNet:Focal Loss for Dense Object Detection(ICCV2017)

    论文原址:https://arxiv.org/abs/1708.02002 github代码:https://github.com/fizyr/keras-retinanet 摘要 目前,具有较高准确 ...

  5. python数据类型一:字符串

    Python 字符串 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello W ...

  6. Ios还是安卓的判断

    最近在做app的h5页面,涉及到一些小知识点 记录一下 1.微信屏蔽了下载的链接,所以在网页中添加的下载链接都要在浏览器中打开,这里需要一个提示用户在浏览器打开的提示弹框 //判断是否在微信终端打开 ...

  7. js查找字符串、js截取

    js查找元素.js查找字符串 let index=data.indexOf(","); js截取.js截取字符串 $("#bankurl_id").val(da ...

  8. hdu5701-中位数计数

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5701 题目: Problem Description 中位数定义为所有值从小到大排序后排在正中间的那个 ...

  9. elasticsearch搜索框架的安装相关

    安装JAVA SE 百度一下JAVA SE,按照自己的平台,位数选择就是了, 这里遇到过一个坑,双击exe安装包一直无法打开jdk的安装,在任务管理器里面就一闪而过, 后来我卸载了所有JAVA的相关安 ...

  10. port bridge enable命令导致的环路

    1.故障描述 前几天机房一台连接数据中心与核心交换的交换机宕机(硬件故障),机房有备用的设备,随即更换(配置也是早就配置好了的),但是下午就出现数据中心网络丢包问题,表现为存在mac漂移 2.拓扑 核 ...