首先需要StrongSwan在报文交互中记录下来IKE和ESP的秘钥信息,参见如下的save-keys.opt文件,负责这一功能的插件为save-keys。其由4个配置参数,load参数表明是否加载此插件;esp参数表明是否记录保持ESP秘钥;ike参数表明是否记录IKE秘钥;最后最关键的是参数wireshark_keys,其值为目录字符串,表示秘钥存储的位置,IKEv1协议的秘钥存储在指定目录的文件:kev1_decryption_table中,而IKEv2协议的秘钥存储在文件ikev2_decryption_table中,ESP子安全关联的秘钥存储在文件:esp_sa中。
$ cat strongswan-5.8.1/conf/plugins/save-keys.opt
charon.plugins.save-keys.load := no
Whether to load the plugin.
charon.plugins.save-keys.esp = no
Whether to save ESP keys.
charon.plugins.save-keys.ike = no
Whether to save IKE keys.
charon.plugins.save-keys.wireshark_keys
Directory where the keys are stored in the format supported by Wireshark
Directory where the keys are stored in the format supported by Wireshark.
IKEv1 keys are stored in the _ikev1_decryption_table_ file.
IKEv2 keys are stored in the _ikev2_decryption_table_ file.
Keys for ESP CHILD_SAs are stored in the _esp_sa_ file.
如下文件:strongswan-5.8.1/src/libcharon/plugins/save_keys/save_keys_listener.c 中的代码所示,在打开秘钥文件时fopen使用的模式为“a”,所以每次记录保存秘钥时都是向文件中追加。
METHOD(listener_t, ike_derived_keys, bool,
private_save_keys_listener_t *this, ike_sa_t *ike_sa, chunk_t sk_ei,
chunk_t sk_er, chunk_t sk_ai, chunk_t sk_ar)
{
version = ike_sa->get_version(ike_sa);
name = version == IKEV2 ? ikev2_name : ikev1_name;
if (asprintf(&path, "%s/%s", this->path, name) < 0) return TRUE;
file = fopen(path, "a");
if (file) {
id = ike_sa->get_id(ike_sa);
if (version == IKEV2)
{
ike_names(ike_sa->get_proposal(ike_sa), &enc, &integ);
if (enc && integ) {
fprintf(file, "%.16"PRIx64",%.16"PRIx64",%+B,%+B,\"%s\","
"%+B,%+B,\"%s\"\n", be64toh(id->get_initiator_spi(id)),
be64toh(id->get_responder_spi(id)), &sk_ei, &sk_er,
enc, &sk_ai, &sk_ar, integ);
如下在StrongSwan的测试用例ikev2/acert-fallback中加载save-keys插件,在测试所用的网关moon的strongswan.conf文件中做如下修改。在load一行的最后添加save-keys插件,并且在随后的plugins段中增加如下的save-keys的四个参数配置,秘钥保存目录设置为:/home/example/keys。
# vi strongswan-5.8.1/testing/tests/ikev2/acert-fallback/hosts/moon/etc/strongswan.conf
#
# /etc/strongswan.conf - strongSwan configuration file
charon {
load = random nonce aes sha1 sha2 pem pkcs1 curve25519 gmp x509 ...(省略) updown save-keys
plugins {
save-keys {
esp = yes
ike = yes
load = yes
wireshark_keys = /home/example/keys
}
}
}
运行测试用例ikev2/acert-fallback:
$ cd strongswan-5.8.1/testing/
$
$ sudo ./do-tests ikev2/acert-fallback
结束之后,可在moon主机的目录/home/example/keys/下看的生成的秘钥文件:esp_sa 和ikev2_decryption_table。
$ ssh root@10.1.0.1
$
moon:~# cat /home/example/keys/esp_sa
"IPv4","192.168.0.100","192.168.0.1","0xc4e70f8b","AES-CBC [RFC3602]","0x63b7d831b9d2b6d5820086ccf11792dc","HMAC-SHA-256-128 [RFC4868]","0x4e334f0d29a188390f6d5100925fee35fee6c49e86e9c24d01b9c56d250cc63c"
"IPv4","192.168.0.1","192.168.0.100","0xc2e6d4cf","AES-CBC [RFC3602]","0xc4dac45d5a5417325bd5e59dd14df359","HMAC-SHA-256-128 [RFC4868]","0xda364ff9349add2d53323575146aabdd713f184f3b0b6d5714af099801d2af1e"
moon:~#
moon:~# cat /home/kai/example/keys/ikev2_decryption_table
aff259722a847b61,91bcf37f0f42d1e1,0f3dec6591429dac32c8b3d198368ae1,f189c132acddf32445e47d848ec1c720,"AES-CBC-128 [RFC3602]",54a82b10c9f27bf4754383e773903794ce0517cafeab576853fd7f13dac0c0d7,75365c2540f08c7b4ec74735670ca3e8c90b8a68136311a2b5763705962daf3b,"HMAC_SHA2_256_128 [RFC4868]"
要解密测试过程中的IKE和ESP交互报文,只需要将这两个文件拷贝到Wireshark所在主机的目录(假设wireshark信息在windows主机上):C:\Users\zhangkai\AppData\Roaming\Wireshark\下,随后使用wireshark打开测试过程中使用tcpdump抓取的报文即可。
另外,对于ESP SA的解密,还需要在wireshark软件中,edit->preferences->protocols->ESP界面,勾选选项:Attemp to detect/decode encrypted ESP payloads。默认情况下没有打开此选项。
除了以上拷贝秘钥文件的方法外,还可以将save-keys插件生成的秘钥文件内容逐一输入到wireshark中。如上图所示,点击ESP SAs右侧的编辑/Edit按钮,打开如下的秘钥输入界面,进行手动输入。注意界面右下方的保存目录文件,如果之前没有设置过ESP秘钥,此处不会显示目录文件。
对于IKE秘钥的输入,位于界面edit->preferences->protocols->ISAKMP,
最后,save-keys插件并不能够记录所有加密和校验算法的秘钥,如camellia加密算法秘钥就不能记录,还有一些save-keys支持的算法而Wireshark不支持,或者相反。支持的加密和校验算法可参考源码文件:strongswan-5.8.1/src/libcharon/plugins/save_keys/save_keys_listener.c。如下列出了支持的ESP加密算法:
/* Wireshark ESP algorithm identifiers for encryption
*/
static algo_map_t esp_encr[] = {
{ ENCR_NULL, -1, "NULL" },
{ ENCR_3DES, -1, "TripleDes-CBC [RFC2451]" },
{ ENCR_AES_CBC, -1, "AES-CBC [RFC3602]" },
{ ENCR_AES_CTR, -1, "AES-CTR [RFC3686]" },
{ ENCR_DES, -1, "DES-CBC [RFC2405]" },
{ ENCR_CAST, -1, "CAST5-CBC [RFC2144]" },
{ ENCR_BLOWFISH, -1, "BLOWFISH-CBC [RFC2451]" },
{ ENCR_TWOFISH_CBC, -1, "TWOFISH-CBC" },
{ ENCR_AES_GCM_ICV8, -1, "AES-GCM [RFC4106]" },
{ ENCR_AES_GCM_ICV12, -1, "AES-GCM [RFC4106]" },
{ ENCR_AES_GCM_ICV16, -1, "AES-GCM [RFC4106]" },
};
END