摘要(MD5\SHA1\MAC)、对称加密(DES\AES)、非对称加密(DSA\RSA)签名在JAVA中应用
引言:去年阅读了《JAVA加密与解密的艺术》草草总结了一些概念,实际在JAVA里的代码应用迟迟没有记录、更新、总结。今天重新梳理一下,温故一下应用知识。
本文主要介绍内容:
1、JAVA安全领域的组成部分
2、摘要、对称加密、非对称加密的区别
3、具体实现代码
JAVA安全领域的组成部分
Java安全领域总共分为四个部分:
- JCA(Java加密体系结构):基本的加密框架,如证书、数字签名、消息摘要、**对产生器。
- JCE(Java加密扩展包):在JCA的基础上进行拓展,提供了各种加密算法、消息摘要算法和**管理等功能。包括DES\AES\RSA\DSA等等算法,都是由JCE来提供的,JCE的实现主要在javax.cryptpo包(及其子包)中。
- JSSE(Java安全套接字扩展包):提供了基于SSL(安全套接字层)的加密功能。在网络的传输过程中,信息会经过多个主机(很可能其中一台被窃听),最终传送给接受者,这是不安全的。这种确保网络通信安全的服务就是由JSSE来提供的。
- JAAS(Java鉴别与安全服务):提供了在Java平台上进行用户身份鉴别的功能。
JAC和JCE是Java平台提供用于安全和加密服务的两组API。它们不执行任何算法,他们只是连接应用和实际算法实现程序的一直接口
。软件开发商可以根据JCE接口将各种算法实现后,打包成一个Provider(安全提供者),动态地加载到Java运行环境。下面展示一下如何查看JDK自带的一些提供者以及其提供的算法。
public void provider() {
for (Provider provider : Security.getProviders()) {
System.out.println(provider);
for (Map.Entry<Object, Object> entry : provider.entrySet()) {
System.out.println("\t" + entry.getValue());
}
}
}
Java安全体系安全不仅支持来自Sun官方的提供者,同时也可以配置第三方安全提供者以扩展相应的算法实现。
安全提供者实现了两个抽象的概念:引擎和算法。引擎可以理解为操作,如加密、解密等。算法则定义了如何操作如何执行,如一个算法可以理解为引擎的具体实现。当然,一个算法可以有多种实现方式,这就意味着同一个算法可以和多个引擎具有不同的实现。
摘要、对称加密、非对称加密的区别
摘要:采用单向加密算法,比如MD5\SHA\MAC等,这是一种数据完整性的加密,这种单向加密一般我们称为摘要,而不是纯意义上的加密。防止数据在传输过程中被篡改,因为摘要不可逆的,比较常见的场景,某会员系统里,会员密码信息都是通过摘要入库的,验证密码是否一致,也是通过对比摘要,这保护了用户密码的安全性。
对称加密:对称加密*要求加密与解密使用同一个共享**,解密是加密的逆运算,由于双方共享同一个**,就要求必须在通信前商定该**,并妥善保管。我们在网络中传输**时,往往为了**的安全性,再对**进行一次非对称加密。对称加密有两种方式,一种是基于固定**的加密与解密,另一种是基于随机源**的加密与解密。这两种方式在后面均会以代码形式讲解。常用的一些对称加密如DES\AES\三重DES等。从底层加密原理角度,
非对称加密:非对称加密*的加***和解***不同,一个公开,称为公钥;一个保密,称为私钥。因此,通信双方都有一对自己的公私钥,私钥自己保管好,公钥提供给对方。非对称加密一般有两种
其一,进行数据认证(鉴权)服务校验,即对发送数据方是否是我们所期望的那个做验证。私钥加签,公钥验签。
其二,对数据进行加密,公钥加密,私钥解密。由于非对称加密算法的低效,所以各密码机构主张对称加 密算法和非对称加密算法结合,用对称加密算法加密内容,用非对称加密算法加密对称算法的**。在算法设计上,非对称加密算法对待加密数据长度要求极为苛刻。比如,RSA算法要求待加密数据长度不得超过53个字节。所以,非对称加密主要用于交换对称加密的秘***,而非数据内容上的加密。
常用的一些非对称加密如DSA\RSA\ECDSA等。
具体实现代码
1、摘要实现
public void messageDigest() throws Exception {
//初始化摘要引擎,指定provider来源及摘要算法
MessageDigest messageDigest = MessageDigest.getInstance("MD5", "SUN");
byte[] bytes = new String("comeonboby").getBytes();
messageDigest.update(bytes);
//执行消息摘要
byte[] bytesFinal = messageDigest.digest();
System.out.println("摘要:" + Arrays.toString(bytesFinal));
messageDigest.update(bytesFinal);
//转换成十六进制字符串
int j = 0;
for (int i = 0; i < bytesFinal.length; i++) {
String hex = Integer.toHexString(bytesFinal[i] & 0xFF);
if (hex.length() < 2) {
hex = "0" + hex;
}
System.out.print(hex.toUpperCase());
j++;
}
}
2、对称加密(以AES为例子)
带随机源**加密:
//content:待加密内容
//strkey:**随机源字符串
//chiperAlogrithm:加密器算法
public static byte[] encryptWithRandom(byte[] content, String strKey, String chiperAlgorithm) {
try {
//获取**随机源,传入随机源算法
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
//随机源偏移
random.setSeed(strKey.getBytes("UTF-8"));
//**生成器,**算法这里直接传入AES
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//生成128位的AES**,AES**只有128位、192位、256位 三类
keyGenerator.init(128, random);
//构建秘***规范
SecretKeySpec key = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");
//构建加密器,传入加密器规则,包括算法\工作模式\填充模式,这里传入AES的话,默认为ECB/PKCS5Padding
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//初始化,传入加密MODE
cipher.init(Cipher.ENCRYPT_MODE, key);
//加密
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
logger.error("AES加密异常", e);
throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES加密异常");
}
}
带随机源**解密:
//content:待解密内容
//strkey:**随机源字符串
//chiperAlogrithm:解密器算法
public static byte[] encryptWithRandom(byte[] content, String strKey, String chiperAlgorithm) {
try {
//获取**随机源,传入随机源算法
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
//随机源偏移
random.setSeed(strKey.getBytes("UTF-8"));
//**生成器,**算法这里直接传入AES
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
//生成128位的AES**,AES**只有128位、192位、256位 三类
keyGenerator.init(128, random);
//构建秘***规范
SecretKeySpec key = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");
//构建解密器,传入加密器规则,包括算法\工作模式\填充模式,这里传入AES的话,默认为ECB/PKCS5Padding
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
//初始化,传入解密MODE
cipher.init(Cipher.DECRYPT_MODE, key);
//解密
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
logger.error("AES解密异常", e);
throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES解密异常");
}
}
不带随机源加密:
//content:待加密内容
//strKey:**
//chiperAlgorithm:加密器算法
public static byte[] encrypt(byte[] content, String strKey, String chiperAlgorithm) {
try {
//生成**规范
SecretKeySpec secretKeySpec = new SecretKeySpec(strKey.getBytes("UTF-8", "AES");
//构建加密器
Cipher cipher = Cipher.getInstance(chiperAlgorithm);
//初始化加密器,传入加密MODE
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
//加密
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
logger.error("AES加密异常", e);
throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES加密异常");
}
}
不带随机源解密:
//content:待解密内容
//strKey:**
//chiperAlgorithm:解密器算法
public static byte[] encrypt(byte[] content, String strKey, String chiperAlgorithm) {
try {
//生成**规范
SecretKeySpec secretKeySpec = new SecretKeySpec(strKey.getBytes("UTF-8", "AES");
//构建解密器
Cipher cipher = Cipher.getInstance(chiperAlgorithm);
//初始化加密器,传入解密MODE
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
//解密
byte[] result = cipher.doFinal(content);
return result;
} catch (Exception e) {
logger.error("AES解密异常", e);
throw new AppException(ResponseCode.SUPPLIER_EXCEPTION.getCode(), "AES解密异常");
}
}
3、RSA加签与验签
public void rsaTest() throws Exception {
//构建加签参数
Map<String, String> params = new HashMap<String, String>();
params.put("version", "1.0");
params.put("app_id", "yfbm70058763e2017120101");
params.put("mContractNo", "20171206000000108009");
params.put("merchantNo", "70058763");
params.put("sign_type", "RSA2");
params.put("signkey_index", "0001");
params.put("timestamp", "20171211102406");
params.put("cardInfo", "349B6AC92254D9C7B0B1523F95DF7C6A4D9AF29505781DC9B1A745D7A6CD37849B573F211AF24BBCB350BCDFA09693C04D81C8446827D6A09C4FF01EBE74670CF78D4DAE4308FE66343399950829D53DD412E1499A1F9C5FCD03381B678898AF8073D3C52CDB5E409D284CFCDC606BC13D1993BFACDB22CD34CC4BE5E40E1E45F77DE7AADD91E7F36D858D57C5767C5A668FB65E9C28C31A8F41E22000EC1D62E8E104C97F704C3F210E28FFB82BFB827DDA2B59DF7202148E8C607682CA21EB0CB4CA25DEC4DEACCDBE6758A8010116F792BEEC2D3A1DE3F2E4F0086E37AC258F79E24CBCABEB2A69BEEC6E6F6AD54943BCA11E37FAE63A70E90BFC45EF5335");
params.put("requestTime", "20171211102406");
params.put("service", "suning.fosps.eps.signfacade.singlebankcardsign");
//对参数进行消息摘要计算
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
messageDigest.update(map2String(params, "signkey_index", "sign_type").getBytes("UTF-8"));
//RSA私钥---Base64字符串
String base64PrimaryKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALLf5WqaIRA9FCC6FN94n9HqCBlfjTZ4/KO1NpoZoyO+EOAO11eEryPBg8+HooTbqCXmP1oecETa4QIVnMZ8TgDfz8f77DZfF1KeqWGUxSosh8RMq1B2zn0UOAk4O4vBFwqrOOF1aU+MhQ5DeLQAYXn2gPgqg5PM96H6DfDyZKlFAgMBAAECgYByQnDianfqTom36gWBRiUYypzH0HB8tkXzMMMjJnM+Vp+i7/gAUKIrfeZ7v1FB+qnrI6ueHklqwkHuue1+IFMWTFRkIMvxanXX3bTj832LrswpKkhCYITDBb8L4f70tFYZWrAnYD1xmjN0yHut5LJ46MlPlpejHQLrK69QHHoRQQJBAN2KJwZUw1OIONPTmxqpGJHgz+7/fR2c+YcjGkLH1cn/LF5ET7jm+cbfpXcHZK4eATJ7L4N9SFsfbCnA2jWP0RUCQQDOsstS/pfJ8QPds69roDeEIxMfYRsw4ys+peJJsh47wwjHKgpCFY8g6KbsUwmRuYcd0Q5u8/zWDc114Qjk5aNxAkEA2g+uMfElAgfHx9k1hpyC7rQWd+1LPebRRk8q/iitKtLc3TzoK9xOZ46j0/GXDDvEeef+8LJUkjzvvnlxT99rsQJAQgPCgmBDlECAjpcryIDkGjSlj9kQuR1km16ZlhXoKAgTTqCzpAWEr+r+HO4sWTla2QACzxbnwmmoHCTiFVDuUQJAGMKTtk2h3S6gvn2Co+V7d24L6EIDGSWhR+divx9Za2SA7ZPKj7KCP0BUJOC+3qqko1nO/l2i15MVATHlUJ7KOQ==";
//RSA公钥---Base64字符串
String base64publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCy3+VqmiEQPRQguhTfeJ/R6ggZX402ePyjtTaaGaMjvhDgDtdXhK8jwYPPh6KE26gl5j9aHnBE2uECFZzGfE4A38/H++w2XxdSnqlhlMUqLIfETKtQds59FDgJODuLwRcKqzjhdWlPjIUOQ3i0AGF59oD4KoOTzPeh+g3w8mSpRQIDAQAB";
//生成PKCS8规范
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decode(base64PrimaryKey));
//生产X509规范
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decode(base64publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
//生成私钥
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
//生成公钥
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
//构建签名类,签名算法为SHA1WithRSA
Signature signature = Signature.getInstance("SHA1WithRSA");
//初始化为加签状态,传入私钥
signature.initSign(privateKey);
byte[] digestByte = messageDigest.digest();
String digest = toHexString(digestByte);
System.out.println("md5摘要:" + digest);
byte[] digestdata = digest.getBytes("UTF-8");
signature.update(digestdata);
//加签
byte[] bytes = signature.sign();
String base64Sign = Base64.encode(bytes).trim();
System.out.println("sign值:" + base64Sign);
//初始化为验签状态,传入公钥
signature.initVerify(publicKey);
signature.update(digestdata);
//验签
System.out.println("验签结果:" + signature.verify(Base64.decode(base64Sign)));
}
通过**对生成器生产**对,简易版加签与验签:
public void signAndVerify() throws Exception {
byte[] data = "mylove".getBytes();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(1024);
KeyPair keyPair = keyPairGenerator.genKeyPair();
Signature signature = Signature.getInstance(keyPairGenerator.getAlgorithm());
signature.initSign(keyPair.getPrivate());
signature.update(data);
byte[] sign = signature.sign();
System.out.println("签名:" + toHexString(sign));
//初始化**---更新---加签或验签 这三步顺序不能变
signature.initVerify(keyPair.getPublic());
signature.update(data);
boolean result = signature.verify(sign);
System.out.println("验签结果:" + result);
}