java-信息安全(十八)java加密解密,签名等总结
0、概述
Java Cryptography Extension(JCE)是一组包,它们提供用于加密、密钥生成和协商以及 Message Authentication Code(MAC)算法的框架和实现。它提供对对称、不对称、块和流密码的加密支持,它还支持安全流和密封的对象。它不对外出口,用它开发完成封装后将无法调用。
在早期JDK版本中,由于受美国的密码出口条例约束,Java中涉及加解密功能的API被限制出口,所以Java中安全组件被分成了两部分: 不含加密功能的JCA(Java Cryptography Architecture )和含加密功能的JCE(Java Cryptography Extension)。
jre\lib\security 目录下的 local_policy.jar 和 US_export_policy.jar 这两个文件起着至关重要的作用。通常我们下载的jdk安装后,这两个文件都是2.4k左右,事实上无JCE限制的应该是5k左右。
在JDK1.1-1.3版本期间,JCE属于扩展包,仅供美国和加拿大的用户下载,JDK1.4+版本后,随JDK核心包一起分发。
首先要下载相应的jce版本。
JDK8对应的版本下载链接:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
JDK7对应的版本下载链接:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
JDK早期版本的下载链接:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-java-plat-419418.html#jce_policy-1.5.0-oth-JPR
JCE的API都在 javax.crypto 包下,核心功能包括:加解密、密钥生成(对称)、MAC生成、密钥协商。
类目 | 详细 | 密钥长度 | 块长 | 速度 | 作用 | 综合【推荐】 | 地址 |
编码类算法 | base64、base58 | 将字符编码,方便传输记录等 | 访问 | ||||
消息摘要 散列(哈希)算法 |
MD、SHA、RIPEMD Tiger、Whirlpool、Gost3411 |
将消息摘要化,方便唯一性比对等 |
HAMC 盐+哈希算法=综合 |
访问 | |||
|
|||||||
对称加密 | DES:数据加密标准 | 56 | 64 | 慢 | 不安全, 不推荐 |
注意,工作模式填充模式, |
|
3DES:密钥加长,多次叠加 | 112、168 | 64 | 很慢 | 中等安全, 适合加密较小的数据 | |||
AES:ssh协议,多用于移动,高级 | 128, 192, 256 | 128 | 快 | 安全 | |||
Blowfish | (4至56)*8 | 64 | 快 | 应该安全, 在安全界尚未被充分分析、论证 | |||
RC2、RC4 | 40-1024 | 64 | 很快 | 安全性不明确 | |||
基于口令加密 | PBE:基于口令加密 | 可以额外加盐,使用口令+盐=实现内部对称加密 | 访问 | ||||
非对称加密 | RSA | 一般公钥加密,私钥解密。 |
公钥(public key)是对外开放的,私钥(private key)是自己拥有的。 |
访问 | |||
ECC(Elliptic curve Cryptography) | 椭圆曲线加密 | 访问 | |||||
ELGamel | 基于离散对数 | ||||||
密钥交换 | DH(Diffie-Hellman)密钥交换算法 | 将非对称加密与堆成加密的结合 | 访问 | ||||
数字签名 | RSA签名 | 非对称算法,基于RSA算法的消息摘要算法,如MD5算法 | 访问 | ||||
DSA签名 | 数字签名算法:DSA仅包含数字签名,不包含加解密 | 访问 | |||||
ECDSA签名 | 椭圆曲线数字签名算法:速度快,强度高,签名短 | 访问 | |||||
https |
java-信息安全(七)-https001-基于非对称加密,对称加密等理解 |
||||||
数字证书 |
1. 算法选择
对称算法一般速度较快,非对称算法速度较慢;对称算法的密钥管理比较困难,非对称算法密钥管理简单;非对称算法一般用于认证和加密会话密钥,通讯双方大部分也就是在开启会话时使用一次,对称算法一般用来加密双方之间的报文/交换的数据,使用频度较高。
不安全算法:明文、XOR 异或、MD5、SHA1、Base64编码、DES/4DES、私有算法等、AES 的非 HMAC 模式【CBC、OFB、CTR、ECB】
采用基于 摘要算法和加入盐值(salt)方式安全存储口令信息:SHA2、bcrypt、JWT HS256/RS256、AES:128位,GCM 模式,NoPaddding Cipher c = Cipher.getInstance("AES/GCM/NoPadding");、RSA:2018位,OAEPWithMD5AndMGF1Padding rsa = javax.crypto.Cipher.getInstance("RSA/ECB/OAEPWithMD5AndMGF1Padding");、DSA:2048位
2. 块/流模式选择
块(Block)模式加密以块为基本单位,适用于明文长度已知的情形;流(Stream)模式以bit或byte为加解密单位, 适用于明文长度未知、内容较大的情形,如加密一个套接字管道或文件读写流等,一般仅适用于硬件实现。块模式下不同算法的块大小可能不一样,一般都是2的次方数,大部分长度为64bits,整个明文长度不是块长度整倍数时,需在最后一个Block进行补长(Padding)
3. 反馈模式选择
使用块算法加密,如果明文有大量重复的内容,则对块加密后得到的密文也会存在大量的重复,这对密文分析、破解提供了极大的便利,为消除这方面的威胁,有个思路就是对不同块密文再进行运算,这样就极大去除了块密文与块明文几间的特征关联,这种做法称为块反馈模式。常见的反馈模式有:ECB、CBC、CFB、OFB等。对于第1个block,因没有其它块密文可供运算,有的模式引入了初始矢量(Initialization Vector,IV,由用户指定)作为第1个block内容,这样就进一步解决了第1个block密文的脆弱性。注意:尽量不要使用ECB模式。
4. 密钥的选择
密钥可以使用KeyGenerator/KeyPairGenerator生成,也可以由外部导入,还可以有密钥参数构造KeySpec再转换为Key。
5. 密钥长度选择
对于对称加密算法,128bits的密钥足够安全,条件许可请选择256bits,注意密钥长度大于128bits需单独下载并安装jurisdiction policy files;对于非对称加密算法,1024bits的密钥足够安全。
最后,如选用基于口令的算法或在用户输入密码时,请避免使用String来引用,使用char[],用完立刻置空char[],避免内存攻击,如heap dump分析等。
一、对称加密算法
1.1、加解密 Cipher
JCE中最常用和最核心的功能就是加解密,此功能由Cipher组件提供
加解密功能由Cipher组件提供,其也是JCE中最核心的组件。Cipher的几个知识点:
1、Cipher在使用时需以参数方式指定transformation
2、transformation的格式为algorithm/mode/padding(算法/模式/填充),其中algorithm(算法)为必输项,如: DES/CBC/PKCS5Padding
3、缺省的mode为ECB,缺省的padding为PKCS5Padding
4、在block算法与流加密模式组合时, 需在mode后面指定每次处理的bit数, 如DES/CFB8/NoPadding, 如未指定则使用缺省值, SunJCE缺省值为64bits
5、Cipher有4种操作模式: ENCRYPT_MODE(加密), DECRYPT_MODE(解密), WRAP_MODE(导出Key), UNWRAP_MODE(导入Key),初始化时需指定某种操作模式(都是静态参数)。
1.2、对称加密算法与秘钥长度选择
注意工作模式的填充,使用feedback模式时(如CBC, CFB, OFB或PCBC), 将用到IV
一般情况下,不要选择DES算法,推荐使用AES算法。128bits的密钥已足够安全,如果可以请选择256bits的密钥。
1、密钥长度是在生成密钥时指定的。如:
KeyGenerator generator = KeyGenerator.getInstance("AES/CBC/PKCS5PADDING"); generator.init(256);//generator.init(56, new SecureRandom()); SecretKey key = generator.generateKey();
2、生成长度超128bits的密钥,需单独从Oracle官网下载对应JDK版本的Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files文件
主要算法:代码地址:https://github.com/bjlhx15/algorithm-sign.git
1.3、基于口令的加密PBE
PBEWithMD5AndDES将用到salt和iteration count,内部对称加密,访问
1.4、加解密流程
1、DES、3DES、AES加密流程:
发送方—>构建密钥-》公布密钥给接收方—>使用密钥对数据加密-》发送加密数据给接收方。
接收方—》接收密钥和加密数据解密数据
2、PBE加密流程:
发送方—>构建密钥-》公布密钥给接收方-》构建盐—>使用口令,盐对数据加密-》发送盐、加密数据给接收方。
接收方—》使用密钥、口令,盐解密数据
二、非常对称密钥生成
非对称密钥的生成请参考java.security.KeyPairGenerator
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm); keyPairGenerator.initialize(keySize); KeyPair keyPair = keyPairGenerator.generateKeyPair(); RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
2.1、流程
公钥加密,私钥解密
发送方—>公钥钥解密加密消息—》发送加密消息给接收方
接收方—》使用私钥解密消息
私钥加密,公钥解密
发送方—>私钥钥解密加密消息—》发送加密消息给接收方
接收方—》使用公钥解密消息
2.2、几种类型说明
如上
三、MAC生成
MAC技术用于确认数据的完整性,Mac要求通讯双方共享一个secret key,示例代码如下:
public class HmacUtils { public static final String HmacMD5 = "HmacMD5"; public static final String HmacSHA1 = "HmacSHA1"; public static final String HmacSHA224 = "HmacSHA224"; public static final String HmacSHA256 = "HmacSHA256"; public static final String HmacSHA384 = "HmacSHA384"; public static final String HmacSHA512 = "HmacSHA512"; public static String initMacKey(String algorithm) throws Exception { // HmacMD5,HmacSHA1,HmacSHA256,HmacSHA384,HmacSHA512 KeyGenerator keyGenerator = KeyGenerator.getInstance(algorithm);// 初始化KeyGenerator SecretKey secretKey = keyGenerator.generateKey();// 产生密钥 return Base64.getEncoder().encodeToString(secretKey.getEncoded());// 获得密钥 } public static String hashMsgCode(String algorithm, String key, byte[] data) throws Exception { // 还原密钥 SecretKey secretKey = new SecretKeySpec(Base64.getDecoder().decode(key), algorithm); Mac mac = Mac.getInstance(secretKey.getAlgorithm());// 实例化MAC mac.init(secretKey);// 初始化Mac return new String(Hex.encodeHex(mac.doFinal(data)));// 执行摘要 } public static boolean check(String algorithm, String key, String hash, String data) throws Exception { String hash2 = hashMsgCode(algorithm, key, data.getBytes("utf-8")); return hash.equals(hash2); } }
MAC优于数据摘要的地方在于:MAC双方要共享一个密钥,所以其也有互相认证的功能,可有效防止数据摘要中明文和数据摘要被同时替换而无法发现的问题。
四、密钥协商
密钥协商就是在通讯多方间不直接交换通讯密钥的情况下而选择一个大家达成一致的密钥(session key),这个session key是对称密钥。
4.1、密钥协商可以通过2种途径实现
1、通过KeyAgreement组件完成,常用算法包括DH(Diffie-Hellman),ECDH(Elliptic Curve Diffie-Hellman),ECMQV(Elliptic Curve Menezes-Qu-Vanstone)等。
2、通过数字信封完成,常用算法包括RSA等。
4.2、流程
1、通过KeyAgreement使用DH算法协商密钥
DH算法由PKCS#3定义,DH算法需在多方间交换公钥,大素数p,私钥的基数g,和私钥的长度l。
1、初始化DH算法密钥对:
发送方—>构建发送方密钥对-》公布发送方公钥、算法等给接收方-》使用接收者公钥构建发送方本地密钥
接收方—》使用发送方密钥构建接收方密钥对-》公布接收者公钥给发送方—》构建接收方本地密钥
2、DH算法加密消息传递:
发送方—>使用本地密钥、对方公钥构建密钥,加密消息—》发送加密消息给接收方
接收方—》使用本地密钥解密消息
2、通过数字信封使用RSA算法协商密钥
数字信封的原理就是利用通讯对方的公钥加密目标密钥(session key,对称密钥),使用目标密钥对报文进行加密,然后将密钥密文与报文密文一起发送给接收方。接收方首先使用自己的私钥对密钥报文进行解密,这样就得到了协商后的密钥,再使用解密后的密钥解密报文,这样就得到了业务数据。过程图示如下:
package com.github.bjlhx15.security.changekey003DigitalEnvelopeDH; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.DESKeySpec; import java.security.*; import java.security.spec.KeySpec; import java.util.HashMap; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public final class DigitalEnvelope { /** Client端与Server端交换数据的队列, 模拟两者之间通讯的通道, 现实中两者可能是通过Socket通讯的. */ private static final BlockingQueue<Map<String,byte[]>> CHANNEL = new LinkedBlockingQueue<>(1); /** * 生成RSA算法的公私密钥对. * * @return 生成RSA算法的公私密钥对. */ public static final KeyPair generatorKeyPair() { KeyPairGenerator keyGen = null; try { keyGen = KeyPairGenerator.getInstance("RSA"); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } SecureRandom random = null; try { random = SecureRandom.getInstance("SHA1PRNG"); } catch (Exception e) { throw new RuntimeException(e); } random.setSeed(53); keyGen.initialize(1024, random); KeyPair pair = keyGen.generateKeyPair(); return pair; } /** * 模拟密钥交换的服务器端, 服务器端与客户端通过共享内存来交换Digital Envelope. */ static class Server extends Thread { /** * 实际中有可能是客户端在请求服务器端时上送了自己的公钥, 也有可能是在注册 * 时就在服务器端登记了公钥. * * @param clientPublicKey 客户端的公钥. */ public Server(PublicKey clientPublicKey) { this.clientPublicKey = clientPublicKey; } /* (non-Javadoc) * @see java.lang.Thread#run() */ @Override public void run() { try { String msg = "Legend of AK47"; KeyGenerator generator = KeyGenerator.getInstance("DES"); SecretKey sessionKey = generator.generateKey(); // Key sessionKey = KeyGeneratorDemo.generatePlainDES(); Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, sessionKey); byte[] p = msg.getBytes("UTF-8"); byte[] msgCipher = cipher.doFinal(p); cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, clientPublicKey); byte[] keyCipher = cipher.doFinal(sessionKey.getEncoded()); Map result = new HashMap(); result.put("msg", msgCipher); result.put("key", keyCipher); CHANNEL.offer(result); } catch (Exception e) { // TODO Exception handling... } } /** 客户端的公钥. */ private final PublicKey clientPublicKey; } /** * 模拟密钥交换的客户端, 服务器端与客户端通过共享内存来交换Digital Envelope. * * @author Rich, 2012-6-14. * @version 1.0 * @since 1.0 */ static class Client extends Thread { /** * 密钥对应该在客户端内部产生, 然后客户端在请求服务器端时上送了自己的公钥, 也有可能是在注册时就在服务器端登记了公钥. * * @param keyPair 客户端的公私密钥对. */ public Client(KeyPair keyPair) { this.keyPair = keyPair; } @Override public void run() { try { Map<String,byte[]> received = CHANNEL.take(); byte[] msgCipher = received.get("msg"); byte[] keyCipher = received.get("key"); PrivateKey privateKey = keyPair.getPrivate(); Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] encoded = cipher.doFinal(keyCipher); KeySpec keySpec = new DESKeySpec(encoded); SecretKeyFactory fac = SecretKeyFactory.getInstance("DES"); Key key = fac.generateSecret(keySpec); cipher = Cipher.getInstance("DES/ECB/PKCS5Padding"); cipher.init(Cipher.DECRYPT_MODE, key); byte[] msg = cipher.doFinal(msgCipher); String plainText = new String(msg, "UTF-8"); System.out.println(plainText); } catch (Exception e) { // TODO Exception handling... } } /** 客户端的公私密钥对. */ private final KeyPair keyPair; } }
实例
public static void main(String[] args) { KeyPair pair = DigitalEnvelope.generatorKeyPair(); Thread client = new DigitalEnvelope.Client(pair); Thread server = new DigitalEnvelope.Server(pair.getPublic()); server.start(); client.start(); }
KeyAgreement的DH与数字信封的RSA比较:
a. DH仅限于交换共享密钥,而无法对交换双方的身份进行认证,易受中间人攻击
b. RSA可以用于交换共享密钥也可以用于身份认证
c. 建议:在双方都有数字证书时,使用RSA,一方或两方都没有数字证书则使用Diffie-Hellman,SSL3.0就是采用的此策略
五、基本概念
加密:
密码常用术语: 明文,密文,加密,加密算法,加密秘钥,解密,解密算法,解密秘钥,
密码分析:分析密文从而推断出明文或秘钥的过程
主动攻击:入侵密码系统,采用伪造,修改,删除等手段向系统注入假消息进行欺骗。(对密文有破坏作用)
被动攻击:对一个保密系统采取截获密文并对其进行分析和攻击。(对密文没有破坏作用)
密码体制:由明文/密文/密钥空间,加密算法和解密算法五部分构成
密码协议:也称安全协议,以密码学为基础的消息交换通信协议
密码系统:指用于加密、解密的系统。
柯克霍夫原则:密码的安全基于密钥而不是算法的保密。现代密码学设计的基本原则
密码分类:
古典密码:以字符块为基本加密单元;现代密码:以信息块为基本加密单元
受限算法:保密性基于算法,应用军事,属于古典密码;基于密钥算法:算法公开,密钥保密。属于现在密码。
对称密码:加解密密钥相同;非对称密码:密钥分为公钥私钥。
分组密码:明文分组,对每块加密;流密码:也称序列密码,每次加密一位或一个字节。
散列函数:用来验证数据的完整性,长度不限,哈希值容易算,运算过程不可逆。如,md5,sha,mac
数字签名:针对以数字的形式存储的消息进行的处理。
OSI安全体系:
osi:应表会传网数物
安全机制:认证,数字签名,访问控制,路由控制,加密机制,业务流填充,数据完整性,公证
安全服务:认证(来源鉴别),访问控制,数据保密性服务,数据完整性服务,抗否认性服务
tcp/ip:应传网网,每一层都有相应的安全体系结构
数字签名:带有密钥(公钥、私钥,私钥签名,公钥验证)的消息摘要算法
OSI参考模型,验证数据完整性、认证数据来源、抗否认
三、java的安全组成
java的安全组成:jca(加密架构),jce(加密扩展),jsse(安全套接扩展,基于ssl),jaas(鉴别与安全服务)
jdk相关包:
java.security:消息摘要
javax.crypto:安全消息摘要,消息认证(鉴别)码
java.net.ssl:java套接字,常用类HttpsURLConnection、SSLContext
第三方扩展:
Bouncy Castle两种支持方案
1.在jdk中的jre\lib\security\java.security文件配置Provider
2.Security类中使用addProvider 或 insertProviderAt方法
Commons Codec
Apache
Base64、二进制、十六进制、字符集编码
Url编码/解码
四、加密、签名常用类
密钥生成器:KeyGenerator/KeyPairGenerator
密钥:SecretKey、KeyPair
密钥规范:DESKeySpec/SecretKeySpec/PBEKeySpec、PKCS8EncodedKeySpec/X509EncodedKeySpec
密钥工厂:SecretKeyFactory、KeyFactory
加解密:Cipher
签名:Signature
加密参数规范:PBEParameterSpec、DHParameterSpec
密钥协定(或密钥交换)协议:KeyAgreement
其他类:Security、SecureRandom
类说明:
Security:类集中了所有的安全属性和常见的安全方法。其主要用途之一是管理提供者
SecureRandom:提供强加密随机数生成器
KeyGenerator:提供(对称)密钥生成器的功能
SecretKey:(对称)密钥
SecretKeyFactory:用于密钥、密钥规范的互转。(如KeySpec和SecretKey)
KeyPairGenerator:用于生成公钥和私钥对
KeyPair:简单的密钥对
PublicKey/PrivateKey:公钥/私钥
KeyFactory:用于密钥、密钥规范的互转。(如KeySpec、公钥私钥)
KeyAgreement:此类提供密钥协定(或密钥交换)协议的功能。
KeySpec:组成加密密钥的密钥内容的(透明)规范,是一个接口
DESKeySpec:此类指定一个 DES 密钥
SecretKeySpec:此类以与 provider 无关的方式指定一个密钥,继承了KeySpec和SecretKey,可以直接当做SecretKey使用
PBEKeySpec:可随同基于密码的加密法 (PBE) 使用的供用户选择的密码
PKCS8EncodedKeySpec:专用密钥的 ASN.1 编码,PKCS#8 中定义的 PrivateKeyInfo;
X509EncodedKeySpec:进行编码的公用密钥的 ASN.1 编码,X.509 标准中定义的 SubjectPublicKeyInfo
;
Cipher:此类为加密和解密提供密码功能
Signature:提供数字签名算法功能
PBEParameterSpec:指定随同以密码为基础的加密法 (PBE) 使用的参数集合
DHParameterSpec:指定随同 Diffie-Hellman 算法使用的参数集合