当前位置: 代码迷 >> 综合 >> 网络安全之数据加密/解密/签名/验签/数字证书
  详细解决方案

网络安全之数据加密/解密/签名/验签/数字证书

热度:53   发布时间:2024-02-28 18:43:40.0

数字证书

网络OSI模型中安全服务建立在大量密码学算法之上:消息摘要算法用于验证数据完整性服务,对称加密算法和非对称加密算法用于保证数据保密性服务,数字签名算法用于抗否认性服务。

网络安全向来都不是一个简单的事情,单一的防御手段,很难达到期望的安全强度!安全的网络平台,需要多重密码学算法有机结合!

数字证书正是多种密码算法结合的产物:自身带有公钥信息,可以完成数据的加密/解密操作; 同时,携带的数字i签名,可以鉴别消息来源; 自身带有的消息摘要信息,可验证证书完整性; 由于证书本身含有用户身份信息,因而具有认证性。

数字证书为发布公钥提供了一种简单的途径,成为加密算法以及公钥的载体。数字证书也叫做电子证书,类似我们生活中的身份证。数字证书由数字证书颁发机构(Certificate Authority, CA)签发, 只有经过CA签发的证书在网络中才具备认证性。

国际权威数字证书颁发认证机构三巨头: VeriSign, GeoTrust, Thawte,以VeriSign签发的电子商务用数字证书应用最为广泛。通常这三大机构签发证书时需要收费,而且价格不菲。当然我们可以选择申请免费的数字证书,例如CAcert(http://www.cacert.org/)这个数字证书国际组织。

证书签发过程实际是对申请数字证书的公钥做数字签名,证书的验证过程实际是对数字证书公钥做验证签名,其中包含证书有效期验证。

CA机构颁发给自己的证书叫做 “根证书”

通过使用CA颁发的数字证书,我们可以对网络上传输的数据进行加密/解密 和签名/验证操作,确保数据的机密性、完整性和抗否认性。数字证书中包含的用户信息,保证了认证性、真实性。

实际上,数字证书采用了公钥基础设施(Public Key Infrastructure, PKI),使用了相应的加密算法确保网络应用的安全性:

  • 非对称加密算法用于对数据加密/解密操作,确保数据的机密性。
  • 数字签名算法用于对数据进行签名/验证操作,确保数据的完整性和抗否认性。
  • 消息摘要算法用于对数字证书本身做摘要处理,确保数字证书完整性。

目前,数字证书中最为常用的非对称加密算法是RSA算法,与之配套使用的签名算法是SHA1withRSA算法,而最为常用的消息摘要算法是SHA1算法。

除了RSA算法外,还可以使用DSA算法。DSA算法证书不包含加密/解密功能。

数字证书编码格式

数字证书有多种文件编码格式,主要包含cer编码、der编码等:

  • cer (Canonical Encoding Rules, 规范编码格式), 是ber(Basic Encoding Rules,基本编码格式)的一个变种,比ber规范。
  • der (Distinguished Encoding Rule, 卓越编码格式)同样是ber的一个变种, 区别:der使用定长模式,cer使用变长模式

所有证书符合公钥基础设施(PKI)制定的ITU-T X509国际标准(X.509标准),目前包含3个版本。

  • PKCS (Public-Key Cryptography Standards,公钥加密标准)由RSA实验室等制定的标准。
    PKCS常用标准
公钥加密标准 描述信息 文件后缀
PKCS#7 密码消息语法标准 .p7b、 .p7c、.spc
PKCS#10 证书请求语法标准 .p10、.csr
PKCS#12 个人信息交换语法标准 .p12、.pfx

以上标准主要用于证书的申请和更新等操作,例如,PKCS#10文件用于证书签发申请, PKCS#12文件可作为Java中密钥库或信任库直接使用。

通常使用Base64编码格式作为数字证书存储格式,如下图所示
在这里插入图片描述
实际应用中,很多数字证书属于自签名证书,即证书申请者为自己的证书签名。

模型分析

证书签发

在这里插入图片描述
加密交互
在这里插入图片描述
在这里插入图片描述
证书管理

任何机构和个人都可以申请数字证书,使用数字证书为自己的应用保驾护航。

获取数字证书需要使用数字证书管理工具(如KeyTool和OpenSSL)构建CSR(Certificate Signing Request,数字证书签发申请),交由CA机构签发,形成最终的数字证书。

keystore和truststore的区别

keystore可以bai看成一个放key的库,key就是公钥、私钥、数字du签名等组成的一zhi个信息;truststore是放信任的证书dao的一个store。
keystore和truststore的性质是一样的,都是存放key的一个仓库,区别在于truststore里存放的是只包含公钥的数字证书,代表了可以信任的证书,而keystore是包含私钥的。
我们自己的应用中通常所说的keystore或者truststore主要是针对于应用本身的需求来的。keystore和truststore从其文件格式来看其实是一个东西,只是为了方便管理将其分开。
keystore中一般保存的是我们的私钥,用来加解密或者为别人做签名;truststore中保存的是一些可信任的证书,主要是java在代码中访问某个https的时候对被访问者进行认证的,以确保其是可信任的。

OpenSSL

OpenSSL证书管理

OpenSSL也是一款证书管理工具,功能上远胜KeyTool。

OpenSSL下载安装

OpenSSL通常使用PEM(Privacy Enhanced Mail, 隐私增强邮件)编码格式保存私钥。

ubuntu14.04安装 Apache2 并配置https
https://www.cnblogs.com/yongpan/p/8000725.html

安全协议

网路安全协议使用最多的协议是HTTPS协议,HTTPS = HTTP+SSL/TLS, 其中HTTP是应用层协议, SSL/TLS是传输层协议。SSL/TLS协议本身是带有加密信息的传输协议,数字证书正式为这种协议提供相关加密/解密信息。

基本上,现在商业化的站点都支持HTTPS,甚至强制支持,以我们常用的baidu搜索页面,看下其相关Https支持情况。

在这里插入图片描述
我们看到Baidu首页的证书是一个叫做 GlobalSign Organization的组织颁发的。

HTTPS协议常常在服务器中配置, Apache, Tomcat等,通过配置SSL/TLS协议构建基于HTTPS协议的服务器。

SSL/TLS协议包含两个协议,SSL(Sercure Socket Layer, 安全套接字层)和TLS(Transport Layer Sercurity, 传输层安全)协议。

TLS协议是SSL协议的升级版本, SSL共3个版本:SSL1.0, SSL2.0和SSL3.0。TLS1.0几乎和SSL3.0兼容。
SSL/TLS协议分为两层:记录协议(Record Protocol)和握手协议(Handshake Protocol)。

  • 记录协议(Record Protocol):建立在可靠的传输协议(TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能支持。
  • 握手协议(Handshake Protocol):建立在SSL记录协议之上,用于在实际的数据传输开始i前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。

SSL/TLS协议涉及多种加密算法,包含消息摘要算法、对称加密算法、非对称加密算法,以及数字签名算法。

  • 消息摘要算法: MD5和SHA1
  • 对称加密算法: RC2、RC4、IDEA、DES、Triple DES和AES
  • 非对称加密算法: RSA和DH(Diffie-Hellman)
  • 数字签名算法:RSA和DSA

模型分析

SSL握手协议较复杂,下面分析主要环节,阐述服务器端和客户端构建加密交互相关流程, 主要包括以下几个主要流程:
协商算法
在这里插入图片描述
验证证书
在这里插入图片描述

产生密钥
在这里插入图片描述

加密交互
在这里插入图片描述

认证方式

认证方式分为单向认证服务和双向认证服务

单向认证服务: 仅需要服务端服务器提供证书,验证服务器身份
注意:不同的客户端在同一时间访问同一服务时, 将有可能使用不同的协议或算法。
双向认证服务:需要服务器提供服务器证书前提下,要求客户端提供客户端证书,同时验证服务器和客户身份。
双向认证服务需要根证书、服务器证书和客户证书共3项证书。(ca.p12, server.p12和client.p12文件)

数字签名

散列函数可以确保数据内容完整性,但无法确保数据的可认证(鉴别)和数据发送行为的不可否认性。完整性、认证性和不可否认性,正是数字签名的主要特征。简单说,签名可以保证数据来源的可信任。数字签名中携带了操作者的身份信息。
数字签名中涉及两个概念,签名者、验证者。数字签名以非对称加密体制基础,签名算法受私钥控制,且由签名者保密
; 验证算法受公钥控制,且对外公开。RSA是最为常用的非对称加密算法,也是最常用的签名算法。DSA算法是典型的数字签名算法,但不具备非对称加密/解密功能。
在这里插入图片描述

通常对消息的加密及签名处理流程如下:

先对消息做签名处理,再做加密处理。加密与签名都应该是针对原始消息(明文)做处理。

不建议对消息做加密后在做签名处理。因为消息本身可能是一个可执行文件,消息接收方通过对消息验证来判别该文件是否有权执行,而该文件本身不需要加密。

Java安全领域组成部分

Java安全领域总共分为四个部分:JCA(Java Cryptography Architecture, Java加密体系结构)、JCE(Java Cryptography Extension, Java 加密扩展包)、JSSE(Java Secure Sockets Extension, Java安全套接字扩展包)、JAAS(Java Authentication and Authentication Service, Java鉴别与安全服务)。

  • JCA提供基本加密框架,如证书、数字签名、消息摘要和密钥对产生器。
  • JCE在JCA基础上作了扩展,提供了各种加密算法、消息摘要算法和密钥管理等功能。
  • JSSE提供了基于SSL(Secure Sockets Layer,安全套接字层)的加密功能。
  • JAAS提供了在Java平台上进行用户身份鉴别的功能。

JCA和JCE是Java平台提供的用于安全和加密服务的两组API。他们并不执行任何算法,他们只是连接应用和实际算法实现程序的一组接口。软件开发商可以根据JCE接口(安全提供者接口)将各种算法实现后,打包成一个Provider(安全提供者),动态加到Java运行环境。

JCE提供者包括Sun、Bouncy Castle等

Java安全体系结构通过扩展方式,加入更多算法实现及相应的安全机制。Java安全提供者在下列文件路径配置
java/security/security.properties

内容如下:
在这里插入图片描述
安全提供者实现了两个概念的抽象:引擎和算法。引擎可理解为操作,如加密、解密。算法则定义了操作如何执行,如一个算法可以理解为一个引擎的具体实现。当然一个算法可以有多种实现方式,这意味着同一个算法与多个引擎具体实现对应。

Java加密/解密包主要由3部分组成:

  • Java 自带, 提供基本的摘要及加密/解密算法。
  • Bouncy Castle 开源的加密组件,提供多种Java6所不支持的算法实现,如MD4和SHA-224、 IDEA、 ECDSA等。
  • Commons Codec 该包由Apache提供, 是对Java 6 API的进一步封装,加强了易用性。

主要类介绍

Provider

Provider类实现了Java安全性的一部分或全部,我们称它为提供者,继承关系如下:

public abstract class Provider extends Properties

Provider类可能实现的服务包括:

  • 算法(如DSA、RSA、MD5和SHA-1)
  • 密钥的生成、转换和管理设施(如用于特定算法的密钥)
    每个提供者都有一个名称和一个版本号,并且在它每次装入运行时进行配置
  • 方法详述
public abstract class Provider extends Properties {
    //返回此提供者的名称,如SunRsaSign表示该提供者的名称public String getName(){
    }//返回提供者版本号,如1.5表示该提供者的版本号public double getVersion(){
    }//返回此提供者的信息串,如Sun RSA signature provider表示这是一个用于RSA算法的数字签名提供者public String getInfo() {
    }//从输入流中读取属性列表(键和元素对)public synchronized void load(InputStream var1){
    }//设置键属性,使其具有指定的值public synchronized Object put(Object var1, Object var2){
    }//将指定Map中所有映射关系复制到此提供者中public synchronized void putAll(Map<?, ?> var1){
    }//返回此提供者中所包含的属性项的一个不可修改的Set视图public synchronized Set<Entry<Object, Object>> entrySet(){
    }//移除键属性(及相应的值)public synchronized Object remove(Object var1){
    }//清除此提供者,使其不再包含用来查找由该提供者实现的设施的属性public synchronized void clear(){
    }//Provider类是Properties类的子类,提供了相应的键值操作方法//返回指定键所映射到的值,如果此映射不包含此键的映射,则返回nullpublic Object get(Object var1){
    }//用指定的键在此属性列表中搜索属性public String getProperty(String var1){
    }//返回此散列表中的值的枚举public Enumeration<Object> keys(){
    }//返回此散列表中的值的枚举public Enumeration<Object> elements(){
    }//返回此提供者所包含的属性键的一个不可修改的Set视图public Set<Object> keySet(){
    }//返回此提供者中所包含的属性值的一个不可修改的Collection视图public Collection<Object> values(){
    }
}

Android系统提供的安全提供者Provider
在这里插入图片描述

Security

Security类的任务就是管理Java程序中所用到的提供者类。Security类是final类,除了私有构造方法,其余均为静态方法。

public final class Security {
    static {
    ......//加载security.properties中配置的ProviderInputStream configStream = Security.class.getResourceAsStream("security.properties");InputStream input = new BufferedInputStream(configStream);secprops.load(input);......  }//在提供者数组尾部追加新的提供者public static int addProvider(Provider provider){
    ......}//在指定位置添加提供者public static synchronized int insertProviderAt(Provider provider, int position){
    ......}  //移除带有指定名称的提供者。public static synchronized void removeProvider(String name) {
    }//获取指定名称的提供者public static synchronized Provider getProvider(String name){
    }//获取所有提供者public static synchronized Provider[] getProviders(){
    }//返回包含满足指定的选择标准的所有已安装的提供者数组(拷贝),如果尚未安装此类提供者,则返回nullpublic static synchronized Provider[] getProviders(Map<String,String> filter){
    }//获取安全属性public static String getProperty(String key){
    }//设置安全属性public static void setProperty(String key, String value){
    }//返回Set视图,Set视图的字符串包含了指定的Java加密服务的所有可用算法或类型的名称(例如: Signature、 MessageDigest、 Cipher、Mac、 KeyStore)public static Set<String> getAlgorithms(String serviceName){
    }
}

MessageDigest

MessageDigest类实现了消息摘要算法,它继承于MessageDigestSpi类, 类继承关系如下:

public abstract class MessageDigest extends MessageDigestSpi

MessageDigest使用了SPI(Service Provider Interface, 服务提供者接口)做解偶实现。MessageDigestSpi类是MessageDigest类的服务提供者接口。通过继承MessageDigestSpi实现自定义消息摘要算法。

方法详述请参考MessageDigest类的具体代码。

DigestInputStream

通过MessageDigest类,我们实现了消息摘要算法,但是通过字节或字节数组方式完成摘要操作,使用起来并不是很方便,因此有了消息摘要流,包含消息摘要输入流和消息摘要输出流。DigestInputStream的继承关系如下:

public class DigestInputStream extends FilterInputStream

方法详述请参考DigestInputStream类的实现。

示例代码:


DigestOutputStream

DigestOutputStream类继承了FilterOutputStream类,可以通过写入输出流的方式完成摘要更新,因此我们称它为消息摘要输出流,在指定的写操作方法内部完成MessageDigest类的update()方法。
类的继承关系如下:

public class DigestOutputStream extends FilterOutputStream 

方法详述请参考DigestOutputStream类的实现。

示例代码:


Key

Key接口是所有密钥接口的顶层接口,一切与加密解密相关的操作都离不开Key接口。
相关的继承关系如下:

public interface Key extends Serializable

方法详述参考Key类的实现。

所有的密钥都具有三个特征:
算法
这里指的是密钥的算法,如DES和DSA等,通过getAlgorithm()方法获得算法名。
编码形式
这里指的是密钥的外部编码形式,密钥根据标准格式(如X.509 SubjectPublicKeyInfo或PKCS#8)编码,使用getEncoded()方法可获得编码格式。
格式
这里指的是已编码密钥的格式名称,使用getFormat()方法可获得格式。
SecretKey、PublicKey、PrivateKey三大接口继承于Key接口,定义了对称密钥和非对称密钥接口。
SecretKey(javax.crypto.SecretKey)接口是对称密钥顶层接口。
DES、 AES等多种对称密码算法密钥均通过该接口提供,PBE(javax.crypto.interface.PBE)接口提供PEB算法定义并继承了该接口。Mac算法实现过程中,通过SecretKey接口提供秘密密钥。通常使用SecretKey接口的实现类SecretKeySpec(javax.crypto.spec.SecretKeySpec)
PublicKey、PrivateKey接口是非对称密钥顶层接口。
DH、RSA、DSA和EC等多种非对称密钥接口均继承了这两个接口。

AlgorithmParameters

通过getInstance()工厂方法实例化AlgorithmParameters对象。
AlgorithmParameters类是一个引擎类,提供密码参数不透明表示。
不透明表示:不可以直接访问参数域,只能得到与参数集相关联的算法名及该参数集的某类编码。
透明表示:用户可以通过相应的规范类中定义的某个“get”方法分别访问每个值。

AlgorithmParameterGenerator

AlgorithmParameterGenerator类用于生成将在某个特定算法中使用的参数集合,我们称为算法参数生成器。
AlgorithmParameterGenerator类同样通过getInstance()工厂方法完成实例化对象。

KeyPair

KeyPair类是对非对称密钥的扩展,它是密钥对的载体,我们把它称为密钥对。

KeyPairGenerator

公钥和私钥的生成是由KeyPairGenerator类来实现的,因此我们把它称为密钥对生成器,它同样是一个引擎类。
类继承关系如下:

public abstract class KeyPairGenerator extends KeyPairGeneratorSpi

KeyPairGenerator本身是一个抽象类,可以通过getInstance()工厂方法实例化对象。
通常我们指定算法名称,直接获得密钥对实例化对象。

KeyFactory

KeyFactory类也是用来生成密钥(公钥和私钥)的引擎类,我们称为密钥工厂,用来生成公钥/私钥。与KeyFactory类对应的类是SecretKeyFactory类,用于生产秘密密钥。
KeyFactory类同样通过getInstance()工厂方法获得实例化对象。

SecureRandom

SecureRandom类继承于Random类(java.util.Random), 它起到强加密随机数生成器(Random Number Generator, RNG)的作用,我们称它为安全随机数生产器,它同样是一个引擎类。

Signature

Signature类用来生成和验证数字签名,它同样是一个引擎类。

使用Signature对象签名数据或验证签名包括以下三个阶段:
1)初始化
2)更新
3)签署或验证所有更新字节的签名

目前,Signature支持NONEwithDSA和SHA1withDSA两种基于DSA算法的签名算法,同时还支持MD2withRSA、MD5withRSA、SHA1withRSA、SHA256withRSA、SHA384withRSA和SHA512withRSA六种基于RSA算法的签名算法。

KeyStore

KeyStore类被称为密钥库,用于管理密钥和证书的存储。KeyStore是个引擎类,提供一些相当完善的接口来访问和修改密钥仓库中的信息。

KeyStore类通过getInstance()工厂方法获得实例化对象。

密钥库类型不区分大小。主要类型:JKS、PKCS12、JCEKS, JCEKS出口受限, PKCS12这种类型的密钥库管理支持不完备,只能读取,不能修改,因此,JKS是最好的选择。

方法详述请参考KeyStore类的实现。

javax.crypto包详解

SecretKeyFactory

SecretKeyFactory类同样属于引擎类,与KeyFactory类相对应,用于产生秘密密钥,我们称为密钥工厂。
SecretKeyFactory通过getInstance()工厂方法实例化。

Cipher

Cipher类为加密和解密提供密码功能。它构成了Java Cryptographic Extension(JCE)框架的核心。加密/解密操作需要通过Cipher类来实现。
Cipher类是引擎类,需要通过getInstance()工厂方法来实例化对象。

加密/解密实现增强及三方实现

受限于美国出口限制,JDK本身不具备很高的加密强度,例如密钥长度受限,加密/解密方式受限等。在当地相应出口政策允许前提下,可以从Sun官方网站下载相应的权限文件,在一定范围内提高JDK(JRE)的加密强度。

三方可用的开源实现

  • Bouncy Castle 提供的Java加密/解密实现
  • Apache提供的Commons Codec作为辅助工具, 提供各种编码转换实现,如Base64、二进制、十六进制、语音等编码转换,同时封装了消息摘要算法。Commons Codec提供了Base64类除了完成一般Base64算法实现,同时实现了Url Base64算法实现。

Base64编码

Base64属于一种编码方式,其使用了单表置换方式完成编码。Base64可以对多种编码格式的字符串做处理,例如ASCII, UTF-8等编码。
Base64编码在RFC2045中有详细描述。经过Base64编码后的数据会比原始数据略长,为原来的4/3倍。经过Base64编码的字符串的字符数是以4为单位的整数倍。

RFC2045还规定,在电子邮件中,每行为76字符,每行末需添加一个回车换行符("\r\n"),不论每行是否够76字符,都要添加一个回车换行符。

在这里插入图片描述
Value指十进制编码,Encoding指的是字符,共映射了64个字符。映射表最后一个字符是等号,它是用来补位。

Base64家族其他算法Base32, Base16以及Url Base64。

Url Base64的出现是为了能在http get请求中传递二进制数据, 其主要是替换了Base64字符映射表中的第62和63个字符,也就是将“+” 和“/” 符号替换成了“-” 和“_”符号。但是对于补位符“=”, 一种建议是使用“~”符号,另一种建议是使用“.”符号。由于“~”符号与文件系统冲突,不建议使用,而对于“.”符号,如果出现连续两次,则认为是错误。Bouncy Castle使用“.” 作为补位符,而Commons Codec则完全杜绝使用补位符。

Base64算法与加密算法关系

Base64算法不能称为加密算法,Base64算法常作为密钥、密文和证书的一种通用存储编码格式,与加密算法形影不离。

Base64实现原理

Base64算法主要是将给定的字符以与字符编码(如ASCII码, UTF-8码)对应的十进制数作为基准,做编码操作:
1)将给定的字符串以字符为单位,转换为对应的字符编码(如ASCII)
2)将获得的字符编码转换为二进制码
3)对获得的二进制码做分组转换操作,每3个8位二进制码为一组,转换为每4个6位二进制码为一组(不足6位低位补0)。这是一个分组变化过程,3个8位二进制码和4个6位二进制码的长度都是24位(3x8=4x6=24)
4) 对获得4-6位二进制码补位,向6位二进制码添加2位高位0,组成4个8位二进制码。
5)将获得的4-8二进制码转换为十进制码。
6)将获得的十进制码转换为Base64字符表中对应的字符。

在这里插入图片描述
在这里插入图片描述
当然,如果使用GBK编码就不是这个结果了。字符串“密”对应的GBK编码是-61, -36, 经过Base64编码后就是字符串“w9w=”了。

  相关解决方案