Java加密与解密技术(上)

企业应用安全

安全技术目标

根据美国国家信息基础设施(NII)提供的文献,安全技术目标包含:

  • 保密性(Confidentiality):又称机密性。保密性确保数据仅能被合法的用户访问,即数据不能被未授权的第三方使用。
  • 完整性(Integrity):主要确保数据只能由授权方或以授权的方式进行修改,即数据在传输过程中不能被未授权方修改。
  • 可用性(Availability):主要确保所有数据仅在适当的时候可以由授权方访问。
  • 可靠性(Reliability):主要确保系统能在规定条件下、规定时间内、完成规定功能时具有稳定的概率。
  • 抗否认性(Non-Repudiation):又称抗抵赖性,主要确保发送方与接收方在执行各自操作后,对所做的操作不可否认。

除此之外,计算机网络信息系统的其他安全技术目标还包括:

  • 可控性:主要是对信息及信息系统实施安全监控。
  • 可审查性:主要是通过审计、监控、抗否认性等安全机制,确保数据访问者(包括合法用户、攻击者、破坏者、抵赖者)的行为有证可查,当网络出现安全问题时,提供调查依据和手段。
  • 认证(鉴别):主要确保数据访问者和信息服务者的身份真实有效。
  • 访问控制:主要确保数据不被非授权方或以未授权方式使用。

安全技术目标制定的主旨在于预防安全隐患的发生。安全技术目标是构建安全体系结构的基础。

OSI安全体系结构

OSI_security_architecture

图1 OSI参考模型

OSI_security_regime

图2 OSI参考模型安全服务和安全机制的对应关系

捍卫企业应用安全的银弹——密码学

密码学在加密算法上大体可分为单向加密算法、对称加密算法、非对称加密算法三大类。MD5、SHA算法是单向加密算法的代表,单向加密算法是数据完整性验证的常用算法。DES算法是对称加密算法的典型代表,对称加密算法是数据存储加密的常用算法。RSA算法是非对称加密算法的典型代表,非对称加密算法是数据传输加密的常用算法。对称加密算法也可以用做数据传输加密,但非对称加密算法在密钥管理方面更有优势。相对对称加密算法而言,非对称加密算法在安全级别上等级更高,但非对称加密算法在时间效率上远不如对称加密算法。

以密码学为基础的各种安全实现相继出现,如HTTPS协议和一系列的“数字技术”(数字摘要、数字信封、数字签名、数字证书等),这些构成了认证技术的基础。

根据密码体制密码学可分为对称密码体制密码学和非对称密码体制密码学。

  • 对称密码体制(Symmetric Cryptosystem):又称单钥密码体制或私钥密码体制。该密码体制中的加密密钥与解密密钥相同,即加密过程与解密过程使用同一套密钥。
  • 非对称密码体制(Asymmetric Cryptosystem):又称双钥密码体制或公钥密码体制。该密码体制中的加密密钥与解密密钥不同,密钥分为公钥与私钥。公钥对外公开,私钥对外保密。

与上述密码体制对应的算法有对称密码算法和非对称密码算法。

  • 对称密码算法(Symmetric Cipher):又称单钥密码算法或私钥密码算法,指对应于对称密码体制的加密、解密算法。常见的DES、AES算法都是对称密码算法的典范。
  • 非对称密码算法(Asymmetric Cipher):又称双钥密码算法或公钥密码算法,指对应于非对称密码体制的加密、解密算法。RSA、SM2算法就是非对称密码算法,多应用于数字签名、身份认证等。当然,非对称密码算法相对于对称密码算法有着更高的安全性,但也有着不可回避的加密、解密耗时长的问题。

密码学的发家史

密码学是靠着战争发家的。密码学很早就广泛应用于古代战争中,使用手工方式完成加密操作,以确保战争中军事信息的秘密传送,这一阶段称为手工加密阶段。

19世纪末至20世纪初,工业革命促进了机械和机电技术的发展,密码学进入机械加密阶段。工业革命为密码学的发展提供了基础,世界大战的爆发为密码学的飞跃提供了契机。

在第一次世界大战中,密码分析有了重大突破,它是战争能否取得胜利的重要决定因素之一;在第二次世界大战中,密码学经历了它的黄金时代,在战争中扮演了更重要的角色。

柯克霍夫原则(Kerckhoffs’s principle)

又称柯克霍夫假说、公理或定律,是由奥古斯特·柯克霍夫(Auguste Kerckhoffs)在19世纪提出的密码理论,即数据的安全基于密钥而不是算法的保密。换句话说,系统的安全性取决于密钥,对密钥保密,对算法公开。信息论始祖克劳德·艾尔伍德·香农(Claude Elwood Shannon)将其改为“敌人了解系统”,这样的说法称为香农箴言。柯克霍夫原则是现代密码学设计的基本原则。

为企业应用上锁

  • 访问控制:通过为用户设定用户名和口令控制用户访问权限。
  • 数据加密:通过对数据的加密、解密可以有效地提高企业应用的安全性。
  • 证书认证:通过数字证书认证可以鉴别用户身份、消息来源的可靠性,加上HTTPS协议的支持可达到高度的数据安全性

Java与密码学

Java安全领域总共分为4个部分:JCA(Java Cryptography Architecture,Java加密体系结构)、JCE(Java Cryptography Extension,Java加密扩展包)、JSSE(Java Secure Sockets Extension,Java安全套接字扩展包)、JAAS(Java Authentication and Authentication Service,JavaJava安全领域总共分为4个部分: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的基础上作了扩展,提供了各种加密算法、消息摘要算法和密钥管理等功能。我们已经有所了解的DES算法、AES算法、RSA算法、DSA算法等就是通过JCE来提供的。有关JCE的实现主要在javax.crypto包(及其子包)中。
  • JSSE提供了基于SSL(Secure Sockets Layer,安全套接字层)的加密功能。在网络的传输过程中,信息会经过多个主机(很有可能其中一台就被窃听),最终传送给接收者,这是不安全的。这种确保网络通信安全的服务就是由JSSE来提供的。
  • JAAS提供了在Java平台上进行用户身份鉴别的功能。如何提供一个符合标准安全机制的登录模块,通过可配置的方式集成至各个系统中呢?这是由JAAS来提供的。

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

根据美国出口限制规定,JCA可出口(JCA和Sun的一些默认实现包含在Java发行版中),但JCE对部分国家是限制出口的。因此,要实现一个完整的安全结构,就需要一个或多个第三方厂商提供的JCE产品,称为安全提供者。BouncyCastle JCE就是其中的一个安全提供者。

安全提供者是承担特定安全机制实现的第三方。有些提供者是完全免费的,而另一些提供者则需要付费。提供安全提供者的公司有Sun、Bouncy Castle等,Sun提供了如何开发安全提供者的细节。Bouncy Castle提供了可以在J2ME/J2EE/J2SE平台得到支持的API,而且Bouncy Castle的API是免费的。

以下是以下内容是JDK 1.8所提供的安全提供者的配置信息,在${JAVA_HOME}/jre/lib/security/java.security中列出。

#
# List of providers and their preference orders (see above):
#
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC
security.provider.10=apple.security.AppleProvider

JCE 环境检查

在使用比8u161、7u171和6u181更早的JDK 8、7和6更新时需要无限制的策略文件。在这些版本及以后的版本中,默认情况下提供了更强的加密算法。

如果使用了早期版本,我们这里需要一个不限长度的JCE,可以从Oracle官网下载,下载之后,解压的目录结构如下所示:

|---README.txt
|---US_export_policy.jar
|---local_policy.jar

将解压后的文件拷贝到jdk/jre/lib/security目录下面覆盖文件。

参考:https://www.oracle.com/java/technologies/javase-jce-all-downloads.html

Java EE对密码学的支持是相当广泛的,主要表现在如下几个方面:

  • Java API支持:Java API支持多种加密算法。如MessageDigest类,可以构建MD5、SHA两种加密算法;Mac类可以构建HMAC加密算法;Cipher类可以构建多种加密算法,如DES、AES、Blowfish对称加密算法,以及RSA、DSA、DH等多种非对称加密算法;Signature类可以用于数字签名和签名验证;Certificate类可用于操作证书;等等。
  • Servlet容器支持:常用的应用服务器(如Tomcat)通过简单的配置即可支持SSL/TLS协议,获取证书配置,有效地构建HTTPS应用。
  • Java工具支持:通过KeyTool可以很好地完成密钥管理、证书管理等;通过JarSigner可以完成代码签名。

java.security

java.security包为安全框架提供类和接口。通过该包中的Java实现,仅能完成消息摘要算法的实现(消息摘要处理的MessageDigestDigestInputStreamDigestOutputStream类),并且其源代码是可见的。而要实现真正的加密与解密,需要参考javax.crypto包中的内容。当然,这个包中的源代码内容是不可见的。

java.security.Provider抽象类

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

  • 算法(如DSA、RSA、MD5或SHA-1)。
  • 密钥的生成、转换和管理设施(如用于特定于算法的密钥)。 每个提供者都有一个名称和一个版本号,并且在它每次装入运行时中进行配置。
  • 方法详述。

增加自定义或第三方的Provider实现的两种方式:

security.provider.11=org.bouncycastle.jce.provider.BouncyCastleProvider

static {
    if (Security.getProvider("BC") == null) {
        Security.addProvider(new BouncyCastleProvider());
    }
}

java.security.MessageDigest

MessageDigest类实现了消息摘要算法,它继承于MessageDigestSpi类,是Java安全提供者体系结构中最为简单的一个引擎类。

目前Java 8支持MD2、MD5、SHA-1(SHA)、SHA-224、SHA-256、SHA-384、SHA-512等消息摘要算法,算法名不区分大小写。

SPI(Service Provider Interface,服务提供者接口)

使用示例

// 待做消息摘要算法的原始信息
byte[] input = "sha".getBytes();
// 初始化MessageDigest对象,将使用SHA算法
MessageDigest sha = MessageDigest.getInstance("SHA"); 
// 更新摘要信息
sha.update(input); 
// 获取消息摘要结果
byte[] output = sha.digest();
// Base64转码
String digest = Base64.getEncoder().encodeToString(output);

关于消息摘要算法的实现

MessageDigestDigestInputStreamDigestOutputStreamMac均是消息认证技术的引擎类。MessageDigest提供核心的消息摘要实现;DigestInputStreamDigestOutputStream提供以MessageDigest为核心的消息摘要流实现;Mac提供基于秘密密钥的安全消息摘要实现。MacMessageDigest无任何依赖关系。

除了MessageDigest类提供的MD和SHA两大类算法外,还有一种摘要算法——Mac,它的算法实现是通过Mac类(javax.crypto.Mac)来实现的。

java.security.Key接口

Key接口是所有密钥接口的顶层接口,一切与加密解密有关的操作都离不开Key接口。

所有的密钥都具有三个特征:

  • 算法。这里指的是密钥的算法,如DES和DSA等,通过getAlgorithm()方法可获得算法名。
  • 编码形式。这里指的是密钥的外部编码形式,密钥根据标准格式(如X.509 SubjectPublicKeyInfoPKCS#8)编码,使用getEncoded()方法可获得编码格式。
  • 格式。这里指的是已编码密钥的格式的名称,使用getFormat()方法可获得格式。

SecretKeyPublicKeyPrivateKey三大接口继承于Key接口,定义了对称密钥和非对称密钥接口。

SecretKey

SecretKey(javax.crypto.SecretKey)接口是对称密钥顶层接口。DES、AES等多种对称密码算法密钥均可通过该接口提供,PBE(javax.crypto.interfaces.PBE)接口提供PEB算法定义并继承了该接口。Mac算法实现过程中,通过SecretKey接口提供秘密密钥。通常使用的是SecretKey接口的实现类SecretKeySpec(javax.crypto.spec.SecretKeySpec)

PBE:Password-based encryption。

PublicKey和PrivateKey

PublicKeyPrivateKey接口是非对称密钥顶层接口。DH、RSA、DSA和EC等多种非对称密钥接口均继承了这两个接口。RSA、DSA、EC接口均在java.security.interfaces包中。DH的密钥接口位于javax.crypto.interfaces包中。

java.security.AlgorithmParameters

AlgorithmParameters类是一个引擎类,它提供密码参数的不透明表示。

不透明表示与透明表示的区别在于:

  • 不透明表示:在这种表示中,不可以直接访问各参数域,只能得到与参数集相关联的算法名及该参数集的某类编码。
  • 透明表示:用户可以通过相应规范类中定义的某个get方法来分别访问每个值。

AlgorithmParameters对象只能被初始化一次,无法重用。

在上述init()方法中,我们看到AlgorithmParameterSpec参数,它是加密参数的(透明)规范接口,位于java.security.spec包中,其接口内部无任何方法,仅用于将所有参数规范分组,并为其提供类型安全。所有参数规范都必须实现此接口。

java.security.AlgorithmParameterGenerator

AlgorithmParameterGenerator类用于生成将在某个特定算法中使用的参数集合,我们把它称为算法参数生成器,它同样是一个引擎类。

java.security.KeyPair

KeyPair类是对非对称密钥的扩展,它是密钥对的载体,我们把它称为密钥对。KeyPair类包含两个信息:公钥和私钥。

KeyPair只能通过构造方法初始化内部的公钥和私钥,此外不提供设置公钥和私钥的方法,仅提供获取公钥和私钥的方法:

// 返回对此KeyPair对象的公钥组件的引用
public PublicKey getPublic() 
// 返回对此KeyPair对象的私钥组件的引用
public PrivateKey getPrivate()

KeyPair通常由KeyPairGeneratorgenerateKeyPair()方法来提供。

java.security.KeyPairGenerator

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

在Java 8中,提供了DH、ECDH、ECDSA、DSA和RSA等多种非对称加密算法或签名算法实现。

经过上述方法相结合,我们可以很方便地生成一个密钥对,如生成一个DSA算法密钥对:

// 实例化KeyPairGenerator对象
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA"); 
// 初始化KeyPairGenerator对象
kpg.initialize(1024); 
// 生成KeyPair对象
KeyPair keys = kpg.genKeyPair();

KeyPairGenerator类提供了非对称密钥对的生成实现,如果要生成私钥,则可使用KeyGenerator(javax.crypto.KeyGenerator)类。

java.security.KeyFactory

KeyFactory类也是用来生成密钥(公钥和私钥)的引擎类,我们将它称为密钥工厂,它用来生成公钥/私钥,或者说它的作用是通过密钥规范还原密钥。与KeyFactory类相对应的类是SecretKeyFactory类,这个类用于生成秘密密钥。

KeyFactory类最常用的操作就是通过密钥规范获得相应的密钥。

// 根据提供的密钥规范(密钥材料)生成PublicKey对象
public final PublicKey generatePublic(KeySpec keySpec) 
// 根据提供的密钥规范(密钥材料)生成PrivateKey对象
public final PrivateKey generatePrivate(KeySpec keySpec)

构建密钥对与还原密钥

// 实例化KeyPairGenerator对象,并指定RSA算法
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); 
// 初始化KeyPairGenerator对象
keyPairGen.initialize(1024); 
// 生成KeyPair对象
KeyPair keyPair = keyPairGen.generateKeyPair();  
// 获得私钥密钥字节数组。实际使用过程中该密钥以此种形式保存传递给另一方
byte[] keyBytes = keyPair.getPrivate().getEncoded();
// 由私钥密钥字节数组获得密钥规范
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 
// 实例化密钥工厂,并指定RSA算法
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
// 生成私钥
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);

java.security.SecureRandom

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

构建安全随机数对象及秘密密钥对象

// 实例化SecureRandom对象
SecureRandom secureRandom = new SecureRandom();
// 实例化KeyGenerator对象
KeyGenerator kg = KeyGenerator.getInstance("DES"); 
// 初始化KeyGenerator对象
kg.init(secureRandom); 
// 生成SecretKey对象
SecretKey secretKey = kg.generateKey();

java.security.Signature

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

使用Signature对象签名数据或验证签名包括以下三个阶段:
1)初始化。

  • 初始化验证签名的公钥
  • 初始化签署签名的私钥

2)更新数据。

根据初始化类型,可更新要签名或验证的字节。

3)签署或验证所有更新字节的签名。

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

数字签名处理

// 待做数字签名的原始信息
byte[] data = "Data Signature".getBytes();
// 实例化KeyPairGenerator对象,并指定DSA算法
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DSA"); 
// 初始化KeyPairGenerator对象
keyPairGen.initialize(1024); 
// 生成KeyPair对象
KeyPair keyPair = keyPairGen.generateKeyPair();  
// 实例化Signature对象
Signature signature = Signature.getInstance(keyPairGen.getAlgorithm());
// 初始化用于签名操作的Signature对象
signature.initSign(keyPair.getPrivate());
// 更新
signature.update(data); 
// 获得签名,即字节数组sign
byte[] sign = signature.sign();

私钥完成签名,公钥则用于完成验证,方法如下:

// 初始化用于验证操作的Signature对象
signature.initVerify(keyPair.getPublic());
// 更新
signature.update(data); 
// 获得验证结果
boolean status = signature.verify(sign);

java.security.KeyStore

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

密钥库类型不区分大小。例如,“JKS”被认为与“jks”相同。除了JKS这种类型以外,还有PKCS12和JCEKS两种类型。JCEKS本身受美国出口限制,所以通常我们可以使用的只有JKS和PKCS12两种类型。但PKCS12这种类型的密钥库管理支持不是很完备,只能够读取该类型的证书,却不能对其进行修改。因此,JKS是最好的选择。

通过以下两种方法来加载和存储密钥库:

// 从给定输入流中加载此密钥库
public final void load(InputStream stream, char[] password) 
// 将此密钥库存储到给定输出流,并用给定密码保护其完整性
public final void store(OutputStream stream, char[] password)

在密钥库中,密钥和证书都是通过别名进行组织的。

加载密钥库

// 加载密钥库文件
FileInputStream is = new FileInputStream("D:\\.keystore"); 
// 实例化KeyStore对象
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
// 加载密钥库,使用密码"password"
ks.load(is, "password".toCharArray()); 
// 关闭文件流
is.close();

得到密钥库对象后,可以获得其别名对应的私钥:

// 获得别名为"alias"所对应的私钥
PrivateKey key = (PrivateKey) ks.getKey("alias", "password".toCharArray());

或者使用以下私钥项的方式获得私钥:

// 获得私钥项
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)ks.getEntry("alias", "password".toCharArray());
// 获得私钥
PrivateKey privateKey = pkEntry.getPrivateKey();

有关证书类Certificate将在后面介绍。

javax.crypto

javax.crypto包为加密操作提供类和接口。在上一节中,我们了解了如何实现消息摘要算法、获得对称密钥等API内容。但是,如果缺乏Cipher类,我们将无法完成加密与解密的实现。

javax.crypto.Mac

Mac属于消息摘要的一种,但它不同于一般消息摘要(如MessageDigest提供的消息摘要实现),仅通过输入数据无法获得消息摘要,必须有一个由发送方和接收方共享的秘密密钥才能生成最终的消息摘要——安全消息摘要。安全消息摘要又称消息认证(鉴别)码(Message Authentication Code,Mac)。

在Java 8版本中支持HmacMD5、HmacSHA1、HmacSHA224、HmacSHA256、HmacSHA384和HmacSHA512、PBEWithHmacSHA*** 等算法。

HmacMD5算法摘要处理:

// 待做安全消息摘要的原始信息
byte[] input = "MAC".getBytes();
// 初始化KeyGenerator对象,使用HmacMD5算法
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5"); 
// 构建SecretKey对象
SecretKey secretKey = keyGenerator.generateKey();
// 构建Mac对象
Mac mac = Mac.getInstance(secretKey.getAlgorithm());
// 初始化Mac对象
mac.init(secretKey); 
// 获得经过安全消息摘要后的信息
byte[] output = mac.doFinal(input);

javax.crypto.KeyGenerator

KeyGenerator类与KeyPairGenerator类相似,KeyGenerator类用来生成秘密密钥,我们称之为秘密密钥生成器。

javax.crypto.KeyAgreement

KeyAgreement类提供密钥协定协议的功能,它同样是一个引擎类。

javax.crypto.SecretKeyFactory

SecretKeyFactory类同样属于引擎类,与KeyFactory类相对应,它用于产生秘密密钥,我们称之为秘密密钥工厂。

javax.crypto.Cipher

Cipher类为加密和解密提供密码功能。它构成了Java Cryptographic Extension(JCE)框架的核心。

javax.crypto.CipherInputStreamjavax.crypto.CipherOutputStream

CipherInputStreamCipherOutputStream同属Cipher类的扩展,统称为密钥流。按流的输入和输出方式分为密钥输入流和密钥输出流。

java.security.spec包和javax.crypto.spec

java.security.spec包和javax.crypto.spec包都提供了密钥规范和算法参数规范的类和接口。获得密钥规范后,我们将有机会还原密钥对象。

KeySpecAlgorithmParameterSpe接口

KeySpecAlgorithmParameterSpecjava.security.spec包中两个较为重要的接口。这两个接口本身都是空接口,仅用于将所有参数规范分组,并为其提供类型安全。

KeySpec

此接口不包含任何方法或常量。它仅用于将所有密钥规范分组,并为其提供类型安全。所有密钥规范都必须实现此接口。

KeySpec的抽象实现类(EncodedKeySpec)构建了用于构建公钥规范和私钥规范的两个实现(X509EncodedKeySpec用于构建公钥规范,PKCS8EncodedKeySpec用于构建私钥规范)。

SecretKeySpec接口是KeySpec的实现类,用于构建秘密密钥规范。

AlgorithmParameterSpec

此接口不包含任何方法或常量。它仅用于将所有参数规范分组,并为其提供类型安全。所有参数规范都必须实现此接口。

AlgorithmParameterSpec接口有很多的子接口和实现类,用于特定于算法的初始化。使用起来也很方便,只需要使用指定参数填充构造方法即可获得一个实例化对象。

java.security.spec.EncodedKeySpec

EncodedKeySpec类用编码格式来表示公钥和私钥,我们称之为编码密钥规范。编码密钥规范的实现子类很多,在这里不一一详述。本书将详细介绍最为常用的用于表示公钥和私钥的两个实现类。

X509EncodedKeySpecPKCS8EncodedKeySpec两个类均为EncodedKeySpec的子类,X509EncodedKeySpec类用于转换公钥编码密钥,PKCS8EncodedKeySpec类用于转换私钥编码密钥。

X509EncodedKeySpecPKCS8EncodedKeySpec两个类在加密解密环节中经常会用到。密钥很可能会以二进制方式存储于文件中,由程序来读取。这时候,就需要通过这两个类将文件中的字节数组读出转换为密钥对象。

javax.crypto.spec.SecretKeySpec

SecretKeySpec类是KeySpec接口的实现类,用于构建秘密密钥规范。可根据一个字节数组构造一个SecretKey,而无须通过一个(基于provider的)SecretKeyFactory。

java.security.cert

java.security.cert包提供证书解析和管理、证书撤销列表(CRL)和证书路径的类和接口。

java.security.cert.Certificate

Certificate类是一个用于管理证书的抽象类。证书有多种类型,如X.509证书、PGP证书和SDSI证书,并且它们都以不同的方式存储并存储不同的信息,但却都可以通过继承Certificate类来实现它们。

java.security.cert.CertificateFactory

CertificateFactory类是一个引擎类,称之为证书工厂,可以通过它将证书导入程序中。

javax.net.ssl

javax.net.ssl包提供用于安全套接字包的类。

javax.net.ssl.KeyManagerFactory

KeyManagerFactory类是一个引擎类,它用来管理密钥,称为密钥管理工厂。

javax.net.ssl.TrustManagerFactory

TrustManagerFactory类是用于管理信任材料的管理器工厂。

javax.net.ssl.SSLContext

SSLContext类用于表示安全套接字上下文

javax.net.ssl.HttpsURLConnection

HttpsURLConnection类继承于HttpURLConnection类。

javax.net.ssl.SSLSession

SSLSession接口用于保持SSL协议网络交互会话状态。在SSL的会话中,可以获得加密套件(CipherSuite)、数字证书等。

加密套件中明确给出了加密参数,具体包括:协议、密钥交换算法、加密算法、工作模式和消息摘要算法。如TLS_RSA_WITH_AES_256_CBC_SHA就是一个完成加密套件信息,它表示:使用TLS协议,密钥交换算法为RSA,对称加密算法为AES(密钥长度256位),使用CBC工作模式,并使用SHA消息摘要算法。

javax.net.ssl.SSLSocket

SSLSocket类是基于SSL协议的Socket。用于设置加密套件、处理握手结束事件,并管理SSLSession。

目前,Java 环境中支持的协议有SSLv2Hello、SSLv3、TLSv1、TLSv1.1、TLSv1.2和TLSv1.3等。

javax.net.ssl.SSLServerSocket

SSLServerSocket类是专用于服务器端的SSLSocket,是ServerSocket的子类。

剩余内容请阅读《Java加密与解密技术(下)》

如何确认您的机器上支持哪些算法:

import java.security.MessageDigest;
import java.security.Provider;
import java.security.Provider.Service;
import java.security.Security;
import java.security.Signature;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.crypto.Cipher;
import javax.crypto.Mac;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class ShowHashAlgorithms {

    // 加载 Bouncy Castle 算法实现
    static {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    private static final void showHashAlgorithms(Provider prov, Class<?> typeClass) {
        String type = typeClass.getSimpleName();

        List<Service> algos = new ArrayList<>();

        Set<Service> services = prov.getServices();
        for (Service service : services) {
            if (service.getType().equalsIgnoreCase(type)) {
                algos.add(service);
            }
        }

        if (!algos.isEmpty()) {
            System.out.printf(" --- Provider %s, version %.2f --- %n", prov.getName(), prov.getVersion());
            for (Service service : algos) {
                String algo = service.getAlgorithm();
                System.out.printf("Algorithm name: \"%s\"%n", algo);


            }
        }

        // --- find aliases (inefficiently)
        Set<Object> keys = prov.keySet();
        for (Object key : keys) {
            final String prefix = "Alg.Alias." + type + ".";
            if (key.toString().startsWith(prefix)) {
                String value = prov.get(key.toString()).toString();
                System.out.printf("Alias: \"%s\" -> \"%s\"%n",
                        key.toString().substring(prefix.length()),
                        value);
            }
        }
    }

    public static void main(String[] args) {
        Provider[] providers = Security.getProviders();
        for (Provider provider : providers) {
            // 打印支持的摘要算法
            //showHashAlgorithms(provider, MessageDigest.class);
            // 打印支持的带密钥的摘要算法
            //showHashAlgorithms(provider, Mac.class);
            // 打印支持的加密算法
            //showHashAlgorithms(provider, Cipher.class);
            // 打印支持的签名算法
            showHashAlgorithms(provider, Signature.class);
        }
    }
}