Java加密体系

Java的安全组成

Java Provider体系

参考书籍和文章

本系列其他文章


Java的安全组成

我的主编程语言是Java,所以我用Java语言来学习这些加密技术。

我们先来介绍几个概念

  • JCA (Java Cryptography Architecture)它提供了基础的加密框架,包括”Provider”架构以及一系列Api,比如证书、数字签名、消息摘要、密钥生成器等。通过不同的Provider来实现具体的加密算法,比如说MD5、DES、RSA等。扩展阅读
  • JCE(Java Cryptography Extension) Java对JCA的扩展,提供了具体的加密算法。
  • JSSE(Java Secure Socket Extension,) 提供了对SSL(Secure Socket Layer,安全套接字层) 和TLS(Transport Layer Security ,安全传输层协议)的扩展,确保网络通信的安全 百度百科
    -JAAS( Java Authentication Authorization Service,Java验证和授权API)提供了灵活和可伸缩的机制来保证客户端或服务器端的Java程序,作为标准的用户认证与授权模型。百度百科

Java Provider体系

在Java中,JCA本身并不提供加密算法,而如果想要使用加密算法,就要用到CSP(Cryptographic Service Provider,加密服务提供者),以下简称Provider。Provider是一系列组件的统称。
在使用JCA时,Java寻找指定加密算法的提供者,然后调用他们。每个Provider都有自己独一无二的名称,通过名称来选择特定的提供者。

  1. md = MessageDigest.getInstance("SHA-256");
  2. md = MessageDigest.getInstance("SHA-256", "ProviderC");

以下图片表明,Java是如何请求SHA-256的。第一幅图是找寻SHA-256算法的提供者,第二幅图是请求特定的提供者的算法实现。

以上两张图来自Oracle,详细介绍

在JDK中,本身包含了一些Provider,它们都配置在java.security文件中,它是按照如下方式提供的。

  1. security.provider.1=sun.security.provider.Sun
  2. security.provider.2=sun.security.rsa.SunRsaSign
  3. security.provider.3=sun.security.ec.SunEC
  4. security.provider.4=com.sun.net.ssl.internal.ssl.Provider
  5. security.provider.5=com.sun.crypto.provider.SunJCE
  6. security.provider.6=sun.security.jgss.SunProvider
  7. security.provider.7=com.sun.security.sasl.Provider
  8. security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
  9. security.provider.9=sun.security.smartcardio.SunPCSC
  10. security.provider.10=sun.security.mscapi.SunMSCAPI

你可以将其他的提供者按照以下格式,添加进去。

security.provider.<n>=具体的Provider

也可是在使用之前添加

  1. static {
  2. Security.insertProviderAt(new org.bouncycastle.jce.provider.BouncyCastleProvider(), 1);
  3. }

虽然说Java本身提供了一些算法的实现,但是因为某些国家的进口管制限制,Java发布的运行环境包中的加解密有一定的限制。比如默认不允许256位密钥的AES加解密,解决方法就是修改策略文件。
去官网下载JCE无限制权限策略文件,然后将%JDK_HOME%\jre\lib\security中的jar文件替换为你下载的文件。 下载地址

第三方开源的Provider

  • Bouncy Castle 提供了很多Jdk本身不支持的高强度算法,,比如说DES(64)、IDEA等,其Provider名称为BC 官网
  • SpongyCastle 对最新版本的 BouncyCastle 进行了简单地重新打包。这是因为Android平台使用了删减的Bouncy Castle包,为了提供完整的支持,并且避免冲突,所以使用新的包结构。Provider名称变为SC
  • IBM SDK IBM提供的开发人员工具包 这其中也包含安全服务提供者

参考书籍和文章

关于本章内容,参考了一下书籍和文章

来源: https://blog.csdn.net/laozhaishaozuo/article/details/81812291

--------

Java Security:Java加密框架(JCA)简要说明

加密服务总是关联到一个特定的算法或类型,它既提供了密码操作(如Digital Signature或MessageDigest),生成或供应所需的加密材料(Key或Parameters)加密操作,也会以一个安全的方式生成数据对象(KeyStore或Certificate),封装(压缩)密钥(可以用于加密操作)。

Java Security API中,一个engine class就是定义了一种加密服务,不同的engine class提供不同的服务。下面就来看看有哪些engine class:

1)MessageDigest:对消息进行hash算法生成消息摘要(digest)。

2)Signature:对数据进行签名、验证数字签名。

3)KeyPairGenerator:根据指定的算法生成配对的公钥、私钥。

4)KeyFactory:根据Key说明(KeySpec)生成公钥或者私钥。

5)CertificateFactory:创建公钥证书和证书吊销列表(CRLs)。

6)KeyStore:keystore是一个keys的数据库。Keystore中的私钥会有一个相关联的证书链,证书用于鉴定对应的公钥。一个keystore也包含其它的信任的实体。

7)AlgorithmParameters:管理算法参数。KeyPairGenerator就是使用算法参数,进行算法相关的运算,生成KeyPair的。生成Signature时也会用到。

8)AlgorithmParametersGenerator:用于生成AlgorithmParameters。

9)SecureRandom:用于生成随机数或者伪随机数。

10)CertPathBuilder:用于构建证书链。

11)CertPathValidator:用于校验证书链。

12)CertStore:存储、获取证书链、CRLs到(从)CertStore中。

从上面这些engine class中,可以看出JCA(Java加密框架)中主要就是提供了4种服务:Digest、Key、Cert、Signature、Alogorithm。

1) 对消息内容使用某种hash算法就可以生成Digest。

2) 利用KeyFactory、KeyPairGenerator就可以生成公钥、私钥。

3) 证书中心使用公钥就可生成Cert。

4) 可以使用私钥和Digest就可以消息进行签名Signature。

5) 不论是Digest、Key、Cert、Signature,都要使用到算法Algorithm。

JCA Core API

1)engine class的提供商Provider

从JCA的设计上来说,这些engine的实现都离不开Provider。

这个类继承了Properties,提供了JCA中的engine class。每个engine class都有getInstance()方法,它们都是从provider中获取相关实例的。所以说Provider是JCA engine class的提供商。

2)管理Provider的工具:Security

其实就是一个存放Provider的集合。如果你自定义了一个Provider,可以使用Java Security属性文件配置provider,也可以直接使用Security采用编程的方式来添加Provider。然后就可以使用自定义的engine class了。

Java Security 属性文件在Java Security Policy中已有提过。在安装目录下:

下面是一个自定义的Provider:

复制代码
/**
* @author fs1194361820@163.com
*/
public class XYZProvider extends Provider{
public XYZProvider(){
super("XYZ", 1.0, "XYZ Security Provider v1.0");
put("MessageDigest.XYZ", XYZMessageDigest.class.getName());
}
}
复制代码

已经默认配置了下列Provider:

配置为:security.provider.11=com.fjn.security.XYZProvider 即可。

编码方式就更加简单了:Security.addProvider(new XYZProvider());

3)消息摘要服务:MessageDigest
消息摘要服务其实就是使用hash算法将一段消息(可以是字符串、文件内容、html等)进行计算生成的一个byte[]。

常用加密算法MD5、SHA、SHA-1其实都是hash算法。

下面就给一个简单的MD5算法工具:

View Code

Md5算法我并没有去实现,因为在JDK中已经内置了md5算法。上面的代码就是使用消息摘要服务,并使用md5算法,生成相应的摘要。

下面来一个自定义的MessageDigest:

View Code
这个自定义的MessageDigest中备注的内容,其实就是MessageDigest的执行过程,所有的MessageDigest都要遵从这个过程的。

测试用例:

View Code
在这个用例中,writeMessage()将一段字符串保存后并将生成的digest也保存。

readMessage()将消息读取后,使用MessageDigest.isEqual()方法进行比较,这样可以知道文件是否被人改动过。

而实际上利用私钥更新签名信息时,就是使用MessageDigest#update()方法的。

4)Key 相关的服务
Key包括公钥(PublicKey)、私钥(PrivateKey)两种。

4.1 KeyPairGenerator
这个服务用于生成PublicKey和PrivateKey。

获取实例后,只需要根据上面4种initialize方法进行初始化后,就可以生成KeyPair了。

View Code
第一次调用generateKeyPair()都会生成不同的KeyPair。KeyPairGenerator 每次生成的都是一个KeyPair。

4.2 KeyFactory
KeyFactory用于在Key与KeySpec之间转换,即可以根据key获取到KeySpec,也可以根据KeySpec获取Key。

View Code

5)Cert相关的服务
从上一篇的例子中知道,用户使用的Public Key有可能被不法分子偷偷地窜改,这样用户就得不到应有的服务,也会受到不法分子的危害。如何保证public key不被窜改或者替换呢?认证服务就出现了。

5.1 CertificateFactory
用于生成Certificate或者CRL的。

复制代码
FileInputStream fis = new FileInputStream(filename);
BufferedInputStream bis = new BufferedInputStream(fis);

CertificateFactory cf = CertificateFactory.getInstance("X.509");

while (bis.available() > 0) {
Certificate cert = cf.generateCertificate(bis);
System.out.println(cert.toString());
}
复制代码

什么是CRL ?

一个证书颁发机构需要证书吊销其颁发的证书——也许是虚假的,或者证书的用户已经使用证书从事非法行为。在这样的情况下,证书的有效期不足保护;证书必须立即失效。

下面的这个例子就是在验证完证书的有效性后,判断这个证书是否是一个吊销的证书。

5.2 CertPathBuilder构建证书链CertPath

CertPath就是之前说的证书链。其实就是一个Certificate的有序列表。在列表的最后的一个Cert是一个自签名的Cert。

5.3 CertPathValidator验证Cert链

CertPathValidator用于校验Cert。

6)KeyStore
一个KeyStore是一个key、cert的库,里面存储了PrivateKey, Aliases, Certs.

KeyStore将会有专门的说明。

7)Signature签名
用私钥签名,用公钥验证:
复制代码
public class SignatureTest {

@Test
public void test() throws Exception{
KeyPairGenerator keyPairGen=KeyPairGenerator.getInstance(Message.alogthem);
keyPairGen.initialize(1024);
KeyPair keyPair= keyPairGen.generateKeyPair();
PublicKey puk=keyPair.getPublic();
PrivateKey pik=keyPair.getPrivate();

String data="Hello, Java.";
Signature signature=Signature.getInstance("SHA1withDSA");

// private key sign
signature.initSign(pik);
signature.update(data.getBytes());
byte[] signinfo=signature.sign();

// public key resolve sign
signature.initVerify(puk);
boolean ok=signature.verify(signinfo);
System.out.println(ok);

signature.update(data.getBytes());
ok=signature.verify(signinfo);
System.out.println(ok);

}

}