技术经验分享:JavaSecurity:Java加密框架(JCA)简要说明

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 技术经验分享:JavaSecurity: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


//代码效果参考:http://www.lyjsj.net.cn/wx/art_22936.html

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

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


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


package com.fjn.util;


import java.security.MessageDigest;


import java.security.NoSuchAlgorithmException;


/



@author fs1194361820@163.com



/


public class MD5 {


private static MessageDigest md5MsgDigest;


static{


try {


md5MsgDigest=MessageDigest.getInstance("md5");


} catch (NoSuchAlgorithmException e) {


e.printStackTrace();


}


}


// 转字符串


public static String byte2hex(byte【】 b){


String hs = "";


String stmp = "";


//代码效果参考:http://www.lyjsj.net.cn/wz/art_22934.html

for (int n = 0; n < b.length; n++) {

stmp = Integer.toHexString(b【n】 & 0xFF);


if (stmp.length() == 1)


hs = hs + "0" + stmp;


else


hs = hs + stmp;


}


return hs.toUpperCase();


}


public static String getMD5(String srcMsg){


if(srcMsg == null){


throw new IllegalArgumentException("srcMsg is null.");


}


byte【】 md5Bytes=md5MsgDigest.digest(srcMsg.getBytes());


return byte2hex(md5Bytes);


}


public static void main(String【】 args) {


System.out.println(MD5.getMD5("hello"));


System.out.println(MD5.getMD5("world"));


}


}


View Code


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


下面来一个自定义的MessageDigest:


package com.fjn.security.messageDigest;


import java.security.MessageDigest;


/


@author fs1194361820@163.com


/


public class XYZMessageDigest extends MessageDigest{


private int hash;


private int store;


private int count;


public XYZMessageDigest(){


super("XYZ");


engineReset();


}


/


算法执行过程,每次执行{@link MessageDigest#update(byte)}时,都会调用这个方法,


也就是使用这个算法对在已经计算的数据的基础上再次计算,计算出最新的结果


/


@Override


protected void engineUpdate(byte b) {


switch (count) {


case 0:


store = (b [ 24) & 0xff000000;


break;


case 1:


store |= (b [ 16) & 0x00ff0000;


break;


case 2:


store |= (b [ 8) & 0x0000ff00;


break;


case 3:


store |= (b [ 0) & 0x000000ff;


break;


}


count++;


if(count==4){


hash = hash ^ store;


count = 0;


store = 0;


}


}


@Override


protected void engineUpdate(byte【】 b, int offset, int length) {


for (int i = 0; i < length; i++){


engineUpdate(b【i + offset】);


}


}


/**


每次执行{@link MessageDigest#digest()}时,都会获取之前计算好的结果。


同时也会将数据置为初始状态。


/


@Override


protected byte【】 engineDigest() {


while (count != 0){


engineUpdate((byte) 0);


}


byte b【】 = new byte【4】;


b【0】 = (byte) (hash ]> 24);


b【1】 = (byte) (hash ]> 16);


b【2】 = (byte) (hash ]> 8);


b【3】 = (byte) (hash ]> 0);


engineReset();


return b;


}


/


数据转为初始状态


/


@Override


protected void engineReset() {


hash = 0;


store = 0;


count = 0;


}


}


View Code


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


测试用例:


package com.fjn.security.messageDigest;


import java.io.File;


import java.io.FileInputStream;


import java.io.FileOutputStream;


import java.io.ObjectInputStream;


import java.io.ObjectOutputStream;


import java.security.MessageDigest;


import java.security.Security;


public class XYZMessageDigestTest {


private static String filename="MessageDigestTest.txt";


static{


Security.addProvider(new XYZProvider());


}


public static void main(String【】 args) throws Exception {


XYZMessageDigestTest test=new XYZMessageDigestTest();


test.writeMessage();


test.readMessage();


}


public void writeMessage() throws Exception {


File file=new File(filename);


file.deleteOnExit();


file.createNewFile();


FileOutputStream fos = new FileOutputStream(file);


MessageDigest md = MessageDigest.getInstance("XYZ");


ObjectOutputStream oos = new ObjectOutputStream(fos);


String data = "This have I thought good to deliver thee, "+


"that thou mightst not lose the dues of rejoicing " +


"by being ignorant of what greatness is promised thee.";


byte buf【】 = data.getBytes();


md.update(buf);


oos.writeObject(data); // original message


oos.writeObject(md.digest()); // digest


oos.close();


}


public void readMessage() throws Exception{


File file=new File(filename);


FileInputStream fis=new FileInputStream(file);


ObjectInputStream ois=new ObjectInputStream(fis);


Object o = ois.readObject(); // String data: original message


if (!(o instanceof String)) {


System.out.println("Unexpected data in file");


System.exit(-1);


}


String data = (String) o;


System.out.println("Got message : " + data);


o = ois.readObject(); // byte【】 : digest


if (!(o instanceof byte【】)) {


System.out.println("Unexpected data in file");


System.exit(-1);


}


byte origDigest【】 = (byte 【】) o;


MessageDigest md = MessageDigest.getInstance("XYZ");


md.update(data.getBytes());


if (MessageDigest.isEqual(md.digest(), origDigest))


System.out.println("Message is valid");


else


System.out.println("Message was corrupted");


MessageDigest md2 = MessageDigest.getInstance("SHA");


md2.update(data.getBytes());


if (MessageDigest.isEqual(md2.digest(), origDigest))


System.out.println("Message is valid");


else


System.out.println("Message was corrupted");


ois.close();


}


}


View Code


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


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


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


4)Key 相关的服务


Key包括公钥(PublicKey)、私钥(PrivateKey)两种。


4.1 KeyPairGenerator


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


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


@Test


public void generateKeyPair() throws Exception {


// 算法名称有规定的值,不能乱写的


KeyPairGenerator dsaKeyPairGenerator=KeyPairGenerator.getInstance("dsa");


SecureRandom random=SecureRandom.getInstance("SHA1PRNG","SUN");


random.setSeed(new byte【】{1,2,3,4});


/


jdk8: key必须在【512,1024】之间,并且是64的倍数。有的JDK版本要求是8的倍数,这要根据实际情况和需求设定


/


dsaKeyPairGenerator.initialize(576, random);


KeyPair keyPair=dsaKeyPairGenerator.generateKeyPair();


DSAPublicKey puk=(DSAPublicKey)keyPair.getPublic();


DSAPrivateKey pik=(DSAPrivateKey)keyPair.getPrivate();


System.out.println(puk.getFormat());


System.out.println(pik.getFormat());


System.out.println(puk);


System.out.println(pik);


}


View Code


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


4.2 KeyFactory


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


package com.fjn.security.key;


import java.io.File;


import java.io.FileInputStream;


import java.io.FileOutputStream;


import java.io.ObjectInputStream;


import java.io.ObjectOutputStream;


import java.math.BigInteger;


import java.security.KeyFactory;


import java.security.KeyPair;


import java.security.KeyPairGenerator;


import java.security.PublicKey;


import java.security.SecureRandom;


import java.security.spec.DSAPublicKeySpec;


import org.junit.Test;


public class KeyFactoryTest {


private static final String DSA="DSA";


private static final String keyspecFile="keyspec.text";


@Test


public void genenatePublicKey() throws Exception{


writeKeySpec();


readKeySpec();


}


private void writeKeySpec() throws Exception {


File file=new File(keyspecFile);


file.deleteOnExit();


file.createNewFile();


KeyPairGenerator keyGen = KeyPairGenerator.getInstance(DSA);


keyGen.initialize(512, new SecureRandom());


KeyPair keyPair=keyGen.generateKeyPair();


KeyFactory factory=KeyFactory.getInstance(DSA);


DSAPublicKeySpec keySpec=factory.getKeySpec(keyPair.getPublic(), DSAPublicKeySpec.class);


FileOutputStream fos = new FileOutputStream(file);


ObjectOutputStream oos = new ObjectOutputStream(fos);


oos.writeObject(keySpec.getY());


oos.writeObject(keySpec.getP());


oos.writeObject(keySpec.getQ());


oos.writeObject(keySpec.getG());


oos.flush();


oos.close();


}


private void readKeySpec() throws

相关文章
|
2月前
|
存储 安全 数据安全/隐私保护
Codota的数据加密技术包括静态数据加密和传输中的数据加密
Codota的数据加密技术包括静态数据加密和传输中的数据加密
58 4
|
3月前
|
安全 网络安全 区块链
网络安全与信息安全:构建数字世界的防线在当今数字化时代,网络安全已成为维护个人隐私、企业机密和国家安全的重要屏障。随着网络攻击手段的不断升级,从社交工程到先进的持续性威胁(APT),我们必须采取更加严密的防护措施。本文将深入探讨网络安全漏洞的形成原因、加密技术的应用以及提高公众安全意识的重要性,旨在为读者提供一个全面的网络安全知识框架。
在这个数字信息日益膨胀的时代,网络安全问题成为了每一个网民不可忽视的重大议题。从个人信息泄露到企业数据被盗,再到国家安全受到威胁,网络安全漏洞如同隐藏在暗处的“黑洞”,时刻准备吞噬掉我们的信息安全。而加密技术作为守护网络安全的重要工具之一,其重要性不言而喻。同时,提高公众的安全意识,也是防范网络风险的关键所在。本文将从网络安全漏洞的定义及成因出发,解析当前主流的加密技术,并强调提升安全意识的必要性,为读者提供一份详尽的网络安全指南。
|
4月前
|
存储 SQL 安全
网络安全与信息安全:守护数字世界的坚盾在这个高度数字化的时代,网络安全和信息安全已经成为个人、企业乃至国家安全的重要组成部分。本文将深入探讨网络安全漏洞、加密技术以及安全意识的重要性,旨在为读者提供一个全面的网络安全知识框架。
随着互联网技术的飞速发展,网络安全问题日益凸显。从个人信息泄露到企业数据被盗,再到国家安全受到威胁,网络安全事件层出不穷。本文将从网络安全漏洞的定义与分类入手,探讨常见的网络攻击手段;随后深入解析加密技术的原理及其在保护信息安全中的作用;最后强调提升公众与企业的安全意识的重要性,并提出具体的建议。通过综合运用这些知识点,我们可以更好地构建起一道道坚固的防线,守护我们的数字世界。
|
3月前
|
Java Maven 数据安全/隐私保护
如何实现Java打包程序的加密代码混淆,避免被反编译?
【10月更文挑战第15天】如何实现Java打包程序的加密代码混淆,避免被反编译?
350 2
|
3月前
|
存储 安全 算法
C#一分钟浅谈:数据加密与解密技术
【10月更文挑战第3天】在数字化时代,信息安全至关重要。数据加密作为保障信息不被未授权访问的有效手段,通过特定算法将明文转换为密文,确保即使数据被截获也难以解读。本文从基础概念入手,介绍C#中实现数据加密的方法,涵盖对称加密(如AES、DES)与非对称加密(如RSA),并通过具体示例代码演示如何使用`System.Security.Cryptography.Aes`类完成AES加密和解密过程。此外,还强调了密钥管理及安全策略的重要性。
99 4
|
3月前
|
安全 算法 Java
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
本文提供了在数据库中对密码等敏感信息进行加盐加密的详细教程,包括手写MD5加密算法和使用Spring Security的BCryptPasswordEncoder进行加密,并强调了使用BCryptPasswordEncoder时需要注意的Spring Security配置问题。
220 0
数据库信息/密码加盐加密 —— Java代码手写+集成两种方式,手把手教学!保证能用!
|
4月前
|
存储 安全 算法
RSA在手,安全我有!Python加密解密技术,让你的数据密码坚不可摧
【9月更文挑战第11天】在数字化时代,信息安全至关重要。传统的加密方法已难以应对日益复杂的网络攻击。RSA加密算法凭借其强大的安全性和广泛的应用场景,成为保护敏感数据的首选。本文介绍RSA的基本原理及在Python中的实现方法,并探讨其优势与挑战。通过使用PyCryptodome库,我们展示了RSA加密解密的完整流程,帮助读者理解如何利用RSA为数据提供安全保障。
153 5
|
3月前
|
安全 测试技术 Go
Python 和 Go 实现 AES 加密算法的技术详解
Python 和 Go 实现 AES 加密算法的技术详解
154 0
|
4月前
|
安全 Java 数据安全/隐私保护
- 代码加密混淆工具-Java 编程安全性
在Java编程领域,保护代码安全与知识产权至关重要。本文探讨了代码加密混淆工具的重要性,并介绍了五款流行工具:ProGuard、DexGuard、Jscrambler、DashO 和 Ipa Guard。这些工具通过压缩、优化、混淆和加密等手段,提升代码安全性,保护知识产权。ProGuard 是开源工具,用于压缩和混淆Java代码;DexGuard 专为Android应用程序设计,提供强大加密功能;Jscrambler 基于云,保护Web和移动应用的JavaScript及HTML5代码;DashO 支持多种Java平台和
269 1
|
10天前
|
安全 算法 网络协议
【网络原理】——图解HTTPS如何加密(通俗简单易懂)
HTTPS加密过程,明文,密文,密钥,对称加密,非对称加密,公钥和私钥,证书加密

热门文章

最新文章