1、引言
在社区中,分享了很多篇基于Netty编写的IM聊天入门文章(比如《跟着源码学IM》系列、《基于Netty,从零开发IM》系列等),在这些文章中分享了各种IM通信算法原理和功能逻辑的实现。但是这样简单的IM聊天系统是比较容易被窃听的,如果想要在里面说点悄悄话是不太安全的。
怎么办呢?学过密码学的朋友可能就想到了一个解决办法,聊天的时候对消息加密,处理的时候再对消息进行解密。是的,道理就是这样。
但密码学本身的理论就很复杂,加上相关的知识和概念又太多太杂,对于IM入门者来说,想要快速理清这些概念并实现合适的加解密方案,是比较头疼的。
本文正好借此机会,以Netty编写的IM聊天加密为例,为入门者理清什么是PKI体系、什么是SSL、什么是OpenSSL、以及各类证书和它们间的关系等,并在文末附上简短的Netty代码实示例,希望能助你通俗易懂地快速理解这些知识和概念!
补充说明:本文为了让文章内容尽可能言简意赅、通俗易懂,尽量不深入探讨各个技术知识和概念,感兴趣的读者可以自行查阅相关资料进一步学习。
学习交流:
- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》
- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(备用地址点此)
(本文已同步发布于:http://www.52im.net/thread-4104-1-1.html)
2、相关文章
- 《即时通讯安全篇(一):正确地理解和使用Android端加密算法》
- 《即时通讯安全篇(二):探讨组合加密算法在IM中的应用》
- 《即时通讯安全篇(三):常用加解密算法与通讯安全讲解》
- 《即时通讯安全篇(四):实例分析Android中密钥硬编码的风险》
- 《即时通讯安全篇(五):对称加密技术在Android平台上的应用实践》
- 《即时通讯安全篇(六):非对称加密技术的原理与应用实践》
- 《即时通讯安全篇(十):IM聊天系统安全手段之通信连接层加密技术》
- 《即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术》
3、什么是PKI?
我们需要先了解一下公钥和私钥的加密标准体系PKI。
3.1 基本概念
PKI的全称是Public Key Infrastructure,是指支持公钥管理体制的基础设施,提供鉴别、加密、完整性和不可否认性服务。
通俗讲:PKI是集机构、系统(硬件和软件)、人员、程序、策略和协议为一体,利用公钥概念和技术来实现和提供安全服务的、普适性的安全基础设施。
在公钥密码中,发送者用公钥(加密密钥)加密,接收者用私钥(解密密钥)解密。公钥一般是公开的,不再担心窃听,这解决了对称密码中的密钥配送问题。但是接收者依然无法判断收到的公钥是否合法(有可能是中间人假冒的)。
事实上,仅靠公钥密码本身,无法防御中间人攻击。于是,需要(认证机构)对公钥进行签名,从而确认公钥没有被篡改。加了数字签名的公钥称为公钥证书,一般简称证书。
有了证书来认证,可以有效防御中间人攻击,随之带来了一系列非技术性工作。
例如:谁来发证书?如何发证书?不同机构的证书怎么互认?纸质证书作废容易,数字证书如何作废?解决这些问题,需要制定统一的规则,即PKI体系。
PKI体系是通过颁发、管理公钥证书的方式为终端用户提供服务的系统,最核心的元素是证书。
围绕证书构成了PKI体系的要素:
- 1)使用PKI的用户;
- 2)颁发证书的机构(Certificate Authority,CA);
- 3)保存证书的仓库。
总之:PKI是一个总称,既包括定义PKI的基础标准,也包括PKI的应用标准。
3.2 PKI体系现状
事实上PKI已经有两代了。
第一代的PKI标准主要是由美国RSA公司的公钥加密标准PKCS、国际电信联盟的ITU-T X.509、IETF的X.509、WAP和WPKI等标准组成。但是因为第一代PKI标准是基于抽象语法符号ASN.1进行编码的,实现起来比较复杂和困难,所以产生了第二代PKI标准。
第二代PKI标准是由微软、VeriSign和webMethods三家公司在2001年发布的基于XML的密钥管理规范也叫做XKMS。
事实上现在CA中心使用的最普遍的规范还是X.509系列和PKCS系列。
X.509系列主要由X.209、X.500和X.509组成,其中X.509是由国际电信联盟(ITU-T)制定的数字证书标准。在X.500基础上进行了功能增强,X.509是在1988年发布的。
X.509证书由用户公共密钥和用户标识符组成。此外还包括版本号、证书序列号、CA标识符、签名算法标识、签发者名称、证书有效期等信息。
而PKCS是美国RSA公司的公钥加密标准,包括了证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。它定义了一系列从PKCS#1到PKCS#15的标准。
其中最常用的是PKCS#7、PKCS#12和PKCS#10。PKCS#7 是消息请求语法,常用于数字签名与加密,PKCS#12是个人消息交换与打包语法主要用来生成公钥和私钥(题外话:iOS程序员对PKCS#12不陌生,在实现APNs离线消推送时就需要导出.p12证明,正是这个)。PKCS#10是证书请求语法。
4、什么是SSL?
4.1 基本概念
SSL(全称 Secure Socket Layer)安全套接层是网景公司(Netscape)率先采用的网络安全协议。它是在传输通信协议(TCP/IP)上实现的一种安全协议,采用公开密钥技术。
通俗地说:SSL被设计成使用TCP来提供一种可靠的端到端的安全服务,它不是单个协议,而是二层协议。低层是SSL记录层,用于封装不同的上层协议,另一层是被封装的协议,即SSL握手协议,它可以让服务器和客户机在传输应用数据之前,协商加密算法和加密密钥,客户机提出自己能够支持的全部加密算法,服务器选择最适合它的算法。
SSL特点是:它与应用层协议独立无关。上层的应用层协议(例如:HTTP、FTP、Telnet等)能透明的建立于SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商以及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。
4.2 与TLS的关系
SSL是网景公司(Netscape)设计,但IETF将SSL作了标准化,即RFC2246,并将其称为TLS(Transport Layer Security),其最新版本是RFC5246、版本1.2。
实际上:TLS是IETF在SSL3.0基础上设计的,相当于SSL的后续版本。所以我们通常都是SSL/TLS放一起说。
5、什么是OpenSSL?
5.1 基本概念
OpenSSL是一个开放源代码的软件库,应用程序可以使用这个包来进行安全通信,它包括代码、脚本、配置和过程的集合。例如:如果您正在编写一个需要复杂安全加密的软件,那么只有添加一个安全加密库才有意义,这样您就不必自己编写一大堆复杂的加解密函数(而且密码学本身很复杂,要写好它们并不容易)。
其主要库是以 C 语言所写成,实现了基本的加密功能,实现了 SSL 与 TLS 协议。
OpenSSL整个软件包大概可以分成三个主要功能部分:
- 1)SSL协议库;
- 2)应用程序;
- 3)密码算法库。
OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。
OpenSSL 可以运行在 OpenVMS、 Microsoft Windows 以及绝大多数类 Unix 操作系统上。
5.2 具体来说
密钥和证书管理是PKI的一个重要组成部分,OpenSSL为之提供了丰富的功能,支持多种标准。
OpenSSL实现了ASN.1的证书和密钥相关标准,提供了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。
OpenSSL提供了产生各种公开密钥对和对称密钥的方法、函数和应用程序,同时提供了对公钥和私钥的DER编解码功能。并实现了私钥的PKCS#12和PKCS#8的编解码功能。
OpenSSL在标准中提供了对私钥的加密保护功能,使得密钥可以安全地进行存储和分发。
在此基础上,OpenSSL实现了对证书的X.509标准编解码、PKCS#12格式的编解码以及PKCS#7的编解码功能。并提供了一种文本数据库,支持证书的管理功能,包括证书密钥产生、请求产生、证书签发、吊销和验证等功能。
5.3 发展历程
OpenSSL 计划在 1998 年开始,其目标是发明一套自由的加密工具,在互联网上使用。
OpenSSL 以 Eric Young 以及 Tim Hudson 两人开发的 SSLeay 为基础,随着两人前往 RSA 公司任职,SSLeay 在 1998 年 12 月停止开发。因此在 1998 年 12 月,社群另外分支出 OpenSSL,继续开发下去。
▲ 上图为 Tim Hudson
OpenSSL 管理委员会当前由 7 人组成有 13 个开发人员具有提交权限(其中许多人也是 OpenSSL 管理委员会的一部分)。只有两名全职员工(研究员),其余的是志愿者。
该项目每年的预算不到 100 万美元,主要依靠捐款。 TLS 1.3 的开发由 Akamai 赞助。
5.4 下载方法
OpenSSL可以从其官网上下载,地址是:/source/index.html,感兴趣的读者可以自行下载安装研究。
6、各类证书
6.1 证书类型
操作过证书的朋友可能会对各种证书类型眼花缭乱,典型的体现就是各种不同的证书扩展名上,一般来说会有DER、CRT、CER、PEM这几种证书的扩展名。
以下是最常见的几种:
- 1)DER文件:表示证书的内容是用二进制进行编码的;
- 2)PEM文件:是一个文本文件,其内容是以“ - BEGIN -” 开头的,Base64编码的字符;
- 3)CRT和CER文件:基本上是等价的,他们都是证书的扩展,也是文本文件,不同的是CRT通常用在liunx和unix系统中,而CER通常用在windows系统中。并且在windows系统中,CER文件会被MS cryptoAPI命令识别,可以直接显示导入和/或查看证书内容的对话框;
- 4)KEY文件:主要用来保存PKCS#8标准的公钥和私钥。
6.2 常用OpenSSL命令
下面的命令可以用来查看文本证书内容:
openssl x509 -incert.pem -text -noout
openssl x509 -incert.cer -text -noout
openssl x509 -incert.crt -text -noout
下面的命令可以用来查看二进制证书内容:
openssl x509 -incert.der -inform der -text -noout
下面是常见的PEM和DER相互转换。
PEM到DER的转换:
openssl x509 -incert.crt -outform der-out cert.der
DER到PEM的转换:
openssl x509 -incert.crt -inform der -outform pem -out cert.pem
补充说明:上述命令中用到的openssl程序,就是本文中提到的OpenSSL开源库提供的程序。
7、Netty中的聊天加密代码示例
7.1 关于Netty
Netty是一个Java NIO技术的开源异步事件驱动的网络编程框架,用于快速开发可维护的高性能协议服务器和客户端,事实上用Java开发IM系统时,Netty是几乎是首选。
有关Netty的介绍我就不啰嗦了,如果不了解那就详读以下几篇:
《史上最强Java NIO入门:担心从入门到放弃的,请读这篇!》
《Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!》
《新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析》
《史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战》
基它有关Netty的重要资料:
7.2 启动SSL Server代码示例
事实上这个标题是不对的,Netty中启动的server还是原来那个server,只是对发送的消息进行了加密解密处理。也就是说添加了一个专门进行SSL操作的Handler。
netty中代表ssl处理器的类叫做SslHandler,它是SslContext工程类的一个内部类,所以我们只需要创建好SslContext即可通过调用newHandler方法来返回SslHandler。
让服务器端支持SSL的代码:
ChannelPipeline p = channel.pipeline();
SslContext sslCtx = SslContextBuilder.forServer(...).build();
p.addLast("ssl", sslCtx.newHandler(channel.alloc()));
让客户端支持SSL的代码:
ChannelPipeline p = channel.pipeline();
SslContext sslCtx = SslContextBuilder.forClient().build();
p.addLast("ssl", sslCtx.newHandler(channel.alloc(), host, port));
netty中SSL的实现有两种方式,默认情况下使用的是OpenSSL,如果OpenSSL不可以,那么将会使用JDK的实现。
要创建SslContext,可以调用SslContextBuilder.forServer或者SslContextBuilder.forClient方法。
这里以server为例,看下创建流程。
SslContextBuilder有多种forServer的方法,这里取最简单的一个进行分析:
publicstaticSslContextBuilder forServer(File keyCertChainFile, File keyFile) {
returnnewSslContextBuilder(true).keyManager(keyCertChainFile, keyFile);
}
该方法接收两个参数:
- 1)keyCertChainFile是一个PEM格式的X.509证书文件;
- 2)keyFile是一个PKCS#8的私钥文件。
熟悉OpenSSL的童鞋应该知道使用openssl命令可以生成私钥文件和对应的自签名证书文件。
具体openssl的操作可以查看我的其他文章,这里就不详细讲解了。
除了手动创建证书文件和私钥文件之外,如果是在开发环境中,大家可能希望有一个非常简单的方法来创建证书和私钥文件,netty为大家提供了SelfSignedCertificate类。
看这个类的名字就是知道它是一个自签名的证书类,并且会自动将证书文件和私钥文件生成在系统的temp文件夹中,所以这个类在生产环境中是不推荐使用的。默认情况下该类会使用OpenJDK's X.509来生成证书的私钥,如果不可以,则使用 Bouncy Castle作为替代。
7.3 启动SSL Client代码示例
同样的在client中支持SSL也需要创建一个handler。
客户端的SslContext创建代码如下:
// 配置 SSL.
finalSslContext sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
上面的代码我们使用了一个InsecureTrustManagerFactory.INSTANCE作为trustManager。
什么是trustManager呢?
当客户端和服务器端进行SSL连接的时候,客户端需要验证服务器端发过来证书的正确性。
通常情况下,这个验证是到CA服务器中进行验证的,不过这样需要一个真实的CA证书环境,所以在测试中,我们使用InsecureTrustManagerFactory,这个类会默认接受所有的证书,忽略所有的证书异常。
当然:CA服务器也不是必须的,客户端校验的目的是查看证书中的公钥和发送方的公钥是不是一致的,那么对于不能联网的环境,或者自签名的环境中,我们只需要在客户端校验证书中的指纹是否一致即可。
netty中提供了一个FingerprintTrustManagerFactory类,可以对证书中的指纹进行校验。
该类中有个fingerprints数组,用来存储安全的授权过的指纹信息。通过对比传入的证书和指纹,如果一致则校验通过。
使用openssl从证书中提取指纹的步骤如下:
openssl x509 -fingerprint -sha256 -inmy_certificate.crt
8、小结一下
上面我们对Netty聊天用到的加密技术和相关概念进行了梳理,我来简单这些概念之间的关系。
这些概念之间的关系,简单来说就是:
- 1)PKI:是一套加密体系和标准的合集,它是理论方案;
- 2)SSL:是利用了PKI理论体系,针对Socket网络这个场景设计的一套安全通信标准,属于是PKI的一个具体应用场景;
- 3)OpenSSL:是PKI体系及SSL标准的算法和代码实现,它包括了具体的开源代码、工具程序等;
- 4)各种证书:是在SSL或其它基于PKI体系的安全协议标准中需要使用的到一些加密凭证文件等。
而具体到Netty中的聊天加密,那就是应用了上述的PKI体系,基于SSL协议,在OpenSSL等开源库的帮助下实现的安全程序。
9、参考资料
[4] OpenSSL是什么软件
[5] netty系列之对聊天进行加密
[6] 跟着源码学IM
[7] 基于Netty,从零开发IM
[9] 快速理解TCP协议一篇就够
(本文已同步发布于:http://www.52im.net/thread-4104-1-1.html)