一种较为安全的加密IM方式

在这篇文章里,我将介绍一种很传统的即时通信方式,它能够允许我们不借助QQ,WeChat这样的由一家公司运营并管理的聊天工具,实现功能全面的即时通信,同时有很强的加密保护。

前言

研究这个问题还要从上个月说起。我在上个月突发奇想,想尝试调用腾讯QQ的API接口,允许我用自己开发的工具登录QQ并管理和收发消息,这样就可以在自己的客户端加载自己的加密协议了。很久以来我一直在尝试设计一种很方便的加密通信工具,这只是一个尝试。但是无论我通过什么方法,都不能找到一种免费而安全的解决方案:大部分的QQ机器人是收费的,腾讯自己注册开发者需要身份证实名认证,传统的利用WebQQ的方案又因为服务关闭了不能再使用。我甚至尝试了通过Xposed框架接管手机QQ的方法,但是依然失败了。在我准备放弃这种即时通信的尝试的时候,我想起来,在这种聊天工具发明之前,我们用的是更古老的协议进行通信。于是有了今天这篇文章中的尝试。

XMPP

XMPP协议简介

今天介绍的一个方面就是XMPP协议,和利用它进行的即时通信。首先说明,在很多地方看到的Jabber协议,和XMPP协议本身是一个东西。只是Jabber是商标名,XMPP是经过国际规范之后的协议名称。XMPP,即Extensible Messaging and Presence Protocol,是一种基于XML的协议,用来控制进行响应和传输。而它最常见的使用方向就是即时通信。它分为两部分,核心的XML流传输协议,和基于XMLFreeEIM流传输的即时通讯扩展应用。

不过,如果不研究通信协议的话,就没必要继续深究下去了。只需要知道,这是一种通信协议,有服务商提供基于这个协议的通信服务,我们能够使用客户端连接这种服务并进行通信,就足够了。

XMPP账户注册

与其他古老的通信方式相似,XMPP在注册的时候(一般)不需要提供过多的身份信息,基本上只需要给自己选定一个昵称和密码即可。无需验证手机、邮箱等等,但是这样带来的问题是,需要自己记好密码,否则一旦丢失,自己将无法找回。同时这个密码尽量不要使用重要密码,即,不要和别的密码重复,因为这个密码在服务器的保护等级并不高,容易泄露。

在不同的域名注册的XMPP账户之间可以互相通信,这并不奇怪,因为都是使用XMPP协议,就像不同国家的电话卡可以互相发短信一样。所以这表示,我们只需要注册自己所在的区域方便使用的域名,无需专门注册特定的区域。而在中国,比较方便的域名是xmpp.jp。这是日本的域名,但是在中国可以ping通。如果你在阅读的时候,这篇文章已经发出很久,那么请寻找你能用的服务器,不一定能够用这个。

按照网页上的提示完成注册即可。注意,如果你非常注意自己的隐私,请使用合适的手段隐藏自己的IP,具体手段根据个人喜好而异(比如你可以SSH到一个公用的云去操作,因为不是一家所以不共享这一数据)。同时虽然使用的时候可以直接连接,但是注册的时候使用的是谷歌的验证方案,所以注册时需要使用代理。

在注册完成之后,可以直接使用Web客户端进行聊天,不过这不是我们这次的主要内容。下面我们先来看另外一种通信协议。

IRC

IRC协议简介

IRC,即Internet Relay Chat,是一种非常常见的即时聊天协议,也是最早的即时聊天协议之一。首创于芬兰,现在在许多国家(不包括中国)都有实现的服务器。它最大的特点就是借助服务器中转实现了群聊和即时聊天,所以在IRC上,聊天室(即频道)是最主要的部分。当然,也可以通过聊天室或是直接发起私人聊天。

IRC账号注册

因为绝大部分IRC服务器是私有服务器(不一定是个人私有,集团私有也是可能的),所以申请注册新的账号(其实IRC没有账户这个概念,而是叫昵称,和账户等同)需要管理员同意。而一个无需人工审核的地方就是gitter的服务器,所以使用这个会比较方便,直接授权GitHub账户登录即可。很多开发者都有gitter的IRC账户,在这里可以互相交流。但是需要注意的是,不同的IRC服务器之间并不能互相连接。它的网页聊天在这里,但是同样地,我们不使用网页客户端聊天。

Pidgin

下面进入我们的重头戏,就是Pidgin客户端的使用,和使用它进行加密的方法。

Pidgin介绍

Pidgin是一个允许使用者同时登录相同或不同的协议的多个账户,并且管理这些即时聊天的工具。它是全平台的,Windows,Mac,Linux,FreeBSD下均可使用,而且在Linux下有图形界面和命令行两种控制方法。同时它具有丰富的插件库和自己开发的接口,通过插件可以支持绝大多数的即时聊天,包括但不限于Telegram,Skype,Gtalk(服务关闭之后自然不再支持了),SMS短信,等等。但是在腾讯修改协议之后无法支持QQ和WeChat(不过完全没有必要继续使用这两个聊天工具了,没有隐私还有乱七八糟的不需要的功能)。同时它的插件允许它使用比较安全的加密方式,包括标准GPG,标准RSA等等。不过我们今天主要要讲的是OTR加密插件。

Pidgin的安装

在Windows下使用的时候,直接在官网下载.exe格式的安装包,安装即可。而在Linux下使用的时候,大部分发行版的包管理器能够直接安装这个工具。以Debian为例,执行

sudo apt install pidgin

即可。对于少数的没有预编译包的发行版,可以从源码编译。这时候建议编译2.x的版本,因为这一版本相对稳定,不过对自己足够有信心可以尝试3.0.0版本,我在实际使用中并没有发现它们有很大的区别。

Windows下Pidgin插件的安装

Windows下插件的安装有三种不同的方法。

下载到的插件是可执行文件

有少数开发者会将自己的插件打包成自解压程序的形式,在Windows下执行就可以自动释放到系统里的对应位置。我们下面要讲的OTR插件就是这样的一种形式。这种插件大部分时候不提供卸载程序,不过都可以在Pidgin中选择禁用。安装这种插件的时候请退出Pidgin,安装完成之后启动Pidgin并在插件列表里启用刚刚安装的插件。

下载到的插件是二进制文件

Windows下的插件路径在安装目录(Windows10下默认是C:\Proogram Files(x86)\Pidgin)下的plugins文件夹内。将获得的.dll文件放进去即可。根据系统配置不同可能需要提供管理员权限。

没有Windows插件可供使用

这样的插件数量不少,因为Pidgin主要用户集中于Linux平台。这时可以自己编译,编译要求大同小异,基础的要求是,Java,Python,clang,版本根据每个插件不同可能略有区别,有的插件会要求别的库,根据要求配置即可。在Windows下编译将获得.dll文件,依然放到插件路径下即可。

Linux下插件的安装

Linux下插件的安装依然是三种方法。两种和Windows下一样,不同的是此时路径不再一样,一般是/usr/lib/pidgin/,如果不确定可以用类似

dpkg -L pidgin

的指令检查一下路径。注意这个指令当然要求你是用dpkg安装的Pidgin……所以ArchLinux之类的自然不一样。L需要大写。而且这个目录默认是只有root用户有写入权限的,记得使用sudo一类。

Linux下还可以直接通过包管理器安装一部分插件。使用

apt-cache search pidgin

将列出所有包名包含pidgin,或依赖包含的包,仔细找一下就可以找到插件。OTR也可以这样安装。尽量不要尝试自己编译OTR,会有各种莫名其妙的报错,问题最大的是它会触发assembler的一个bug,为它指定一组在环境下不存在的寄存器并且触发bad register报错。需要手动定位到源码里的出错部分并且手动指定寄存器。

OTR

在Pidgin上,我们能够使用的一个非常优秀的加密方案是OTR,Off-The-Record。它的官网在这里。需要注意的是,OTR并不只是Pidgin的一个插件,而是一个功能强大并且被广泛使用的加密协议实现,是一种混合加密方式,提供了非常不错的安全性。

OTR的特点

  1. 强加密。在正确实现的情况下,不考虑监听者使用其他非常规手段获取你的信息(比如直接植入远控木马之类),你的信息绝对安全。
  2. 用户认证。通过OTR,可以保证与自己聊天的是自己真正希望联系的人,OTR为此专门设计了对应的认证方法,只有认证通过了才可以开始加密聊天。同样地,不考虑特殊情况(比如一方被挟持或者两个人的认证方式泄露之类)。
  3. 可否认性。OTR加密不添加数字签名,这样令任何人都可以伪造一条消息,允许你在任何时候(从技术上和法律上)否定这条消息源自自己。同时由于第二条,在聊天的时候可以不担心消息是经过伪造的。
  4. 向前保护。即使因为某些原因私钥泄露,也不用担心之前的谈话内容泄露。

OTR协议简介

以下介绍均是基于OTR 3.0。

综合地来说,OTR的实现方法是:一方(Alice)和另一方(Bob)申请开始OTR加密通信,另外一方接受请求并且进行身份认证,认证通过之后进行加密通信。

请求OTR通信

OTR有两种请求方式,直接发送请求和发送一条包含标签的信息。两种方法的区别是,如果Bob的客户端设置为只响应OTR请求,那么它将在收到请求时开始OTR认证,而在收到标签时认为,Alice只是在告诉自己她可以进行OTR通信,而没有实际要求开始OTR。

需要注意的是,首先,这里的请求和标签都是未加密的。而且,请求和标签均会告诉Bob,自己使用的是什么版本的OTR,方便Bob进行后续的操作。

身份认证

OTR使用的身份认证的方法是基于Diffie-Hellman密钥交换的方法。因为是非常常见的密钥交换方法,在这里不再描述数学原理,只介绍流程。全部的指数操作是对一个1536位的素数取模,下文中的g是一个生成器。

  • Bob:
    1. 选取一个128位的r
    2. 选取一个至少320位的随机数x
    3. 生成\(AES_r(g^x)\)和\(HASH(g^x)\)并发送给Alice
  • Alice:
    1. 选择一个至少320位的随机数y
    2. 生成\(g^y\)并发送给Bob
  • Bob:
    1. 验证Alice发来的\(g^y\)是合法的值,即\(2 \leq gy \leq modulus-2\)
    2. 计算\(s = (g^y)^x\)
    3. 对s进行不同的哈希运算,计算两个AES密钥c和c’,和四个MAC密钥m1,m1’,m2,m2’。
    4. 选择\(keyid_B\),作为他的D-H密钥\(g^x\)的序列号
    5. 计算\(M_B = MAC_{m1} (g^x, g^y, pub_B, keyid_B)\)
    6. 计算\(X_B = pub_B, keyid_B, sig_B(M_B)\)
    7. 计算\(AES_c(X_B)\)和\(MAC_{m2}(AES_c(X_B))\),并连之前的r一起发送给Alice。
  • Alice:
    1. 使用r解密之前发来的\(g^x\)
    2. 验证\(HASH(g^x)\)与之前发来的一致
    3. 验证Bob发来的\(g^x\)是合法值,即\(2 \leq g^x \leq modulus-2\)
    4. 计算\(s = (g^x)^y,这与Bob计算得到的应该是同一个值
    5. 对s进行不同的哈希运算,计算两个AES密钥c和c’,和四个MAC密钥m1,m1’,m2,m2’(这里和Bob一样)。
    6. 使用m2验证\(MAC_{m2}(AES_c(X_B))\)
    7. 使用c解密\(AES_c(X_B)\)以获得\(X_B = pub_B, keyid_B, sig_B(M_B)\)
    8. 计算\(M_B = MAC_{m1} (g^x, g^y, pub_B, keyid_B)\)
    9. 使用\(pub_B\)验证\(sig_B(M_B)\)
    10. 选择\(keyid_A\),作为她的D-H密钥\(g^y\)的序列号
    11. 计算\(M_A = MAC_{m1’}(g^y, g^x, pub_A, keyid_A)\)
    12. 计算\(X_A = pub_A, keyid_A, sig_A(M_A)\)
    13. 计算\(AES_{c’}(X_A)\)和\(MAC_{m2’}(AES_{c’}(X_A))\)并发送给Bob
  • Bob:
    1. 使用m2’验证\(MAC_{m2’}(AES_{c’}(X_A))\)
    2. 使用c’解密\(AES_{c’}(X_A)\)以获取\(X_A = pub_A, keyid_A, sig_A(M_A)\)
    3. 计算\(M_A = MAC_{m1’}(g^y, g^x, pub_A, keyid_A)\)
    4. 使用\(pub_A\)验证\(sig_A(M_A)\)

通过这一流程可以看出,两人交换了密钥,最终的结果是双方完全掌握对方的密钥,但是只有公钥在网路上被直接传输,而在没有双方任何一方完整信息的条件下,从公钥逆推私钥都是只能依靠暴力算法的,其运算量之大可以想见。

在密钥交换之后,OTR将进行最后一道身份认证,就是双方商定好的认证。可以是通过提问回答的方式,或者是同时使用相同的暗语的放肆,或者直接认证对方的指纹密钥等等,来确定对方的真实身份(即,使用对方的电脑的人的身份)。这一过程是加密的,无需担心暗语泄露。如果身份认证失败,密钥将被焚毁重来。

加密通信

OTR在加密通信方面使用的是标准的AES对称加密,但是鉴于其使用D-H密钥交换,极大的降低了密钥泄露的风险,所以基本上不会出现加密被泄露的情况。不过当然,加密通信的弱点不止算法这一块,还有很多地方可能被攻破。要做到更安全只能多方小心。

最后,因为所有的加密解密都是在本地完成的,这表示明文信息从来没有在网路上直接传输,配合D-H密钥交换能够让中间人攻击完全失效。

在Windows上部署OTR

OTR插件在Windows上部署的时候非常简单,只需要下载官方提供的安装程序即可。不依赖于任何库(当然,你得先装上Pidgin,因为我们安装的是OTR插件)。安装完成之后启动Pidgin,在插件列表里启用OTR,之后进行简单的配置,就可以和另外一名安装有OTR的好友进行加密聊天了。

在Linux上部署OTR

首先,官方提供的在Ubuntu,Debian,和ArchLinux上部署的方法是自己编译库和插件,但是这是一个非常困难的工作……因为在Debian和其衍生环境中,make-util包带的汇编器有一个隐藏的Bug,一般代码写的好的情况下不会触发,但是原因不明地,OTR的库会触发……导致寄存器配置错误,编译失败,如果要手动修改代码比较麻烦。经过我一上午折腾未果,我发现其实Debian是自带这个预编译好的包的,只需执行

sudo apt install pidgin-otr-plugin

即可。

所以尽量不要自己试着编译这个东西了……

这篇文章大致就介绍到这里了,更多的内容可以在这些工具的官网上找到资料。总结一下,这是一种方便快捷的加密通信方法,而且不经过国内主流的服务商,安全性更高。