注意:建议阅读本文之前,先行阅读下面这篇文章,建立对密码学技术体系的整体认知:
https://blog.csdn.net/weixin_39190897/article/details/82223408
加密代码提供方
JDK:代码在java安装目录下的jre\lib\jce.jar包里;
CC:Apache公司提供的org.apache.commons.codec
主页: http://commons.apache.org/proper/commons-codec/
BC:org.bouncecastle
主页: http://www.bouncycastle.org/java.html
基本常用的使用JDK就够了。
maven引入外部依赖方式:
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
加密分类
1、双向加密
双向加密即明文加密后形成的密文,可以通过逆向算法还原出明文。
(1)对称加密:即加密与解密用的是同一把秘钥,常用的对称加密技术有DES、AES、AES3、PBE等。
(2)非对称加密:加密与解密用的是不同的秘钥,常用的非对称加密技术有RSA、DH、ElGamal等。
1.1、对称加密
采用单钥密码系统的加密方法,同一个密钥可以同时用作信息的加密和解密,这种加密方法称为对称加密,也称为单密钥加密。
需要对加密和解密使用相同密钥的加密算法。由于其速度,对称性加密通常在消息发送方需要加密大量数据时使用。
1.2、非对称加密
假设这样一种场景A要发送一段消息给B,但是又不想以明文发送,所以就需要对消息进行加密。如果采用对称加密技术,那么加密与解密用的是同一把秘钥。除非B事先就知道A的秘钥,并且保存好,这样才可以解密A发来的消息。
由于对称技术只有一把秘钥,所以秘钥的管理是一个很麻烦的问题。而非对称技术的诞生就解决了这个问题。非对称加密与解密使用的是不同的秘钥,并且秘钥对是一一对应的,即用A的私钥加密的密文只有用A的公钥才能解密。
这样的话,每个人都有两把秘钥,私钥和公钥,私钥是只有自己才知道的,不能告诉别人,而公钥是公开的,大家都可以知道。这样,当A想要发送消息给B的时候,只需要用B的公钥对消息进行加密就可以了,由于B的私钥只有B才拥有,所以A用B的公钥加密的消息只有B才能解开。而B想更换自己的密钥时也很方便,只须把公钥告诉大家就可以了。
贴张图:
那么,既然非对称加密如此之好,对称加密就没有存在的必要了啊,其实不然,由于非对称加密算法的开销很大,所以如果直接以非对称技术来加密发送的消息效率会很差。那么怎么办呢?解决的办法也很简单,就是把对称加密技术与非对称加密技术结合起来使用。
举个例子:
假如A要发送一个消息给B,对于发送方的A:
(1) A先生成一个对称秘钥,这个秘钥可以是随机生成的;
(2) A用B的公钥加密第一步生成的这个对称秘钥;
(3) A把加密过的对称秘钥发给B;
(4) A用第一步生成的这个对称秘钥加密实际要发的消息;
(5) A把用对称秘钥加密的消息发给B.
对于接收方B:
(1)他先收到A发来的对称秘钥,这个秘钥是用B的公钥加密过的,所以B需要用自己的私钥来解密这个秘钥
(2)然后B又收到A发来的密文,这时候用刚才解密出来的秘钥来解密密文
对称性加密代码贴上:
package com.pica.cloud.health.sms.server.mapper.symmetric_encryption;
import java.security.Key;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* @Description AES算法测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:07
* @ModifyDate 2019/7/29 15:07
* @Params
* @Return
*/
public class AESTest {
public static final String src = "aes test";
public static void main(String[] args) {
jdkAES();
bcAES();
}
/**
* @Description 用jdk实现
* @Author Chongwen.jiang
* @Date 2019/7/29 15:09
* @ModifyDate 2019/7/29 15:09
* @Params []
* @Return void
*/
public static void jdkAES() {
try {
// 生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
byte[] keyBytes = secretKey.getEncoded();
// KEY转换
Key key = new SecretKeySpec(keyBytes, "AES");
// 加密
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("jdk aes encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, key);
result = cipher.doFinal(result);
System.out.println("jdk aes decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用bouncy castle实现
* @Author Chongwen.jiang
* @Date 2019/7/29 15:09
* @ModifyDate 2019/7/29 15:09
* @Params []
* @Return void
*/
public static void bcAES() {
try {
Security.addProvider(new BouncyCastleProvider());
// 生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES", "BC");
keyGenerator.getProvider();
keyGenerator.init(128);
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
byte[] keyBytes = secretKey.getEncoded();
// KEY转换
Key key = new SecretKeySpec(keyBytes, "AES");
// 加密
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("bc aes encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, key);
result = cipher.doFinal(result);
System.out.println("bc aes decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.symmetric_encryption;
import java.security.Key;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* @Description DES算法实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:11
* @ModifyDate 2019/7/29 15:11
* @Params
* @Return
*/
public class DESTest {
public static final String src = "des test";
public static void main(String[] args) {
jdkDES();
bcDES();
}
/**
* @Description 用jdk实现DES加解密
* @Author Chongwen.jiang
* @Date 2019/7/29 10:38
* @ModifyDate 2019/7/29 10:38
* @Params []
* @Return void
*/
public static void jdkDES() {
try {
// 生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");
keyGenerator.init(56);
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
byte[] bytesKey = secretKey.getEncoded();
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
Key convertSecretKey = factory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("jdk des encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
result = cipher.doFinal(result);
System.out.println("jdk des decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用bouncy castle实现DES加解密
* @Author Chongwen.jiang
* @Date 2019/7/29 10:38
* @ModifyDate 2019/7/29 10:38
* @Params []
* @Return void
*/
public static void bcDES() {
try {
Security.addProvider(new BouncyCastleProvider());
// 生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("DES", "BC");
keyGenerator.getProvider();
keyGenerator.init(56);
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
byte[] bytesKey = secretKey.getEncoded();
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(bytesKey);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
Key convertSecretKey = factory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("bc des encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
result = cipher.doFinal(result);
System.out.println("bc des decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.symmetric_encryption;
import java.security.Key;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DESedeKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* @Description DES3算法实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:07
* @ModifyDate 2019/7/29 15:07
* @Params
* @Return
*/
public class DES3Test {
public static final String src = "3des test";
public static void main(String[] args) {
jdk3DES();
bc3DES();
}
/**
* @Description 用jdk实现DES3加解密
* @Author Chongwen.jiang
* @Date 2019/7/29 10:39
* @ModifyDate 2019/7/29 10:39
* @Params
* @Return
*/
public static void jdk3DES() {
try {
// 生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede");
// 必须长度是:112或168
// keyGenerator.init(168);
keyGenerator.init(new SecureRandom());
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
byte[] bytesKey = secretKey.getEncoded();
// KEY转换
DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
Key convertSecretKey = factory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("jdk 3des encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
result = cipher.doFinal(result);
System.out.println("jdk 3des decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用bouncy castle实现DES3加解密
* @Author Chongwen.jiang
* @Date 2019/7/29 10:40
* @ModifyDate 2019/7/29 10:40
* @Params
* @Return
*/
public static void bc3DES() {
try {
Security.addProvider(new BouncyCastleProvider());
// 生成KEY
KeyGenerator keyGenerator = KeyGenerator.getInstance("DESede", "BC");
keyGenerator.getProvider();
keyGenerator.init(168);
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
byte[] bytesKey = secretKey.getEncoded();
// KEY转换
DESedeKeySpec desKeySpec = new DESedeKeySpec(bytesKey);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
Key convertSecretKey = factory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, convertSecretKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("bc 3des encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, convertSecretKey);
result = cipher.doFinal(result);
System.out.println("bc 3des decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.symmetric_encryption;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.apache.commons.codec.binary.Hex;
/**
* @Description PBE算法实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:08
* @ModifyDate 2019/7/29 15:08
* @Params
* @Return
*/
public class PBETest {
public static final String src = "pbe test";
public static void main(String[] args) {
jdkPBE();
}
/**
* @Description 用jdk实现PBE加解密
* @Author Chongwen.jiang
* @Date 2019/7/29 10:44
* @ModifyDate 2019/7/29 10:44
* @Params []
* @Return void
*/
public static void jdkPBE() {
try {
// 初始化盐
SecureRandom random = new SecureRandom();
byte[] salt = random.generateSeed(8);
// 口令与密钥
String password = "timliu";
PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHMD5andDES");
Key key = factory.generateSecret(pbeKeySpec);
// 加密
PBEParameterSpec pbeParameterSpac = new PBEParameterSpec(salt, 100);
Cipher cipher = Cipher.getInstance("PBEWITHMD5andDES");
cipher.init(Cipher.ENCRYPT_MODE, key, pbeParameterSpac);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("jdk pbe encrypt:" + Hex.encodeHexString(result));
// 解密
cipher.init(Cipher.DECRYPT_MODE, key, pbeParameterSpac);
result = cipher.doFinal(result);
System.out.println("jdk pbe decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
非对称性加密代码贴上:
package com.pica.cloud.health.sms.server.mapper.asymmetric_encryption;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* @Description RSA算法非对称性加密实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:17
* @ModifyDate 2019/7/29 15:17
* @Params
* @Return
*/
public class RSATest {
public static final String src = "rsa test";
public static void main(String[] args) {
jdkRSA();
}
/**
* @Description jdk实现RSA非对称性加解密
* @Author Chongwen.jiang
* @Date 2019/7/29 10:45
* @ModifyDate 2019/7/29 10:45
* @Params []
* @Return void
*/
public static void jdkRSA() {
try {
// 1.初始化发送方密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
System.out.println("Public Key:" + Base64.encodeBase64String(rsaPublicKey.getEncoded()));
System.out.println("Private Key:" + Base64.encodeBase64String(rsaPrivateKey.getEncoded()));
// 2.私钥加密、公钥解密 ---- 加密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("私钥加密、公钥解密 ---- 加密:" + Base64.encodeBase64String(result));
// 3.私钥加密、公钥解密 ---- 解密
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
result = cipher.doFinal(result);
System.out.println("私钥加密、公钥解密 ---- 解密:" + new String(result));
// 4.公钥加密、私钥解密 ---- 加密
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);
Cipher cipher2 = Cipher.getInstance("RSA");
cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
byte[] result2 = cipher2.doFinal(src.getBytes());
System.out.println("公钥加密、私钥解密 ---- 加密:" + Base64.encodeBase64String(result2));
// 5.私钥解密、公钥加密 ---- 解密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory5 = KeyFactory.getInstance("RSA");
PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher5 = Cipher.getInstance("RSA");
cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
byte[] result5 = cipher5.doFinal(result2);
System.out.println("公钥加密、私钥解密 ---- 解密:" + new String(result5));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.asymmetric_encryption;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
/**
* @Description RSA并发时间测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:18
* @ModifyDate 2019/7/29 15:18
* @Params
* @Return
*/
public class RSAConcurrencyTest {
public static final String src = "rsa test";
private static byte[] result;
public static void main(String[] args) throws Exception {
RSA();
}
/**
* @Description jdk实现:私钥加密、公钥解密: 并发时间测试
* @Author Chongwen.jiang
* @Date 2019/7/29 10:47
* @ModifyDate 2019/7/29 10:47
* @Params []
* @Return void
*/
public static void RSA() {
try {
long startTimes = System.currentTimeMillis();
// 1.初始化发送方密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
final RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
System.out.println("Public Key:" + Base64.encodeBase64String(rsaPublicKey.getEncoded()));
System.out.println("Private Key:" + Base64.encodeBase64String(rsaPrivateKey.getEncoded()));
// 2.公钥加密、私钥解密 ---- 加密
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
result = cipher.doFinal(src.getBytes());
System.out.println("公钥加密、私钥解密 ---- 加密:" + Base64.encodeBase64String(result));
long endEncryptTime = System.currentTimeMillis();
System.out.println("公钥加密、私钥解密 ---- 加密1个时间(单位毫秒):" + (endEncryptTime - startTimes));
int decryptTimes = 200000; // 并发解密的个数
//创建一个可重用固定线程数的线程池
ExecutorService pool = Executors.newCachedThreadPool(); // Executors.newFixedThreadPool(1000);
for (int i = 0; i < decryptTimes; i++) {
pool.execute(new Thread(new Runnable() {
@Override
public void run() {
try {
// 3.私钥解密、公钥加密 ---- 解密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec2 = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory2 = KeyFactory.getInstance("RSA");
PrivateKey privateKey2 = keyFactory2.generatePrivate(pkcs8EncodedKeySpec2);
Cipher cipher2 = Cipher.getInstance("RSA");
cipher2.init(Cipher.DECRYPT_MODE, privateKey2);
byte[] result2 = cipher2.doFinal(result);
// System.out.println("公钥加密、私钥解密 ---- 解密:" + new String(result2));
} catch (Exception e) {
e.printStackTrace();
}
}
}));
}
pool.shutdown();
while (true) {
if (pool.isTerminated()) {
System.out.println("结束了!");
long endDencryptTime = System.currentTimeMillis();
long totalTimes = (endDencryptTime - endEncryptTime) / 1000;
System.out.println("公钥加密、私钥解密 ---- 并发:" + decryptTimes + "个解密时间(单位秒):" + totalTimes);
break;
}
Thread.sleep(200);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.asymmetric_encryption;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
/**
* @Description DH算法测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:19
* @ModifyDate 2019/7/29 15:19
* @Params
* @Return
*/
public class DHTest {
public static final String src = "dh test";
public static void main(String[] args) {
jdkDH();
}
// jdk实现:
public static void jdkDH() {
try {
// 1.初始化发送方密钥
KeyPairGenerator senderKeyPairGenerator = KeyPairGenerator.getInstance("DH");
senderKeyPairGenerator.initialize(512);
KeyPair senderKeyPair = senderKeyPairGenerator.generateKeyPair();
// 发送方公钥,发送给接收方(网络、文件。。。)
byte[] senderPublicKeyEnc = senderKeyPair.getPublic().getEncoded();
// 2.初始化接收方密钥
KeyFactory receiverKeyFactory = KeyFactory.getInstance("DH");
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(senderPublicKeyEnc);
PublicKey receiverPublicKey = receiverKeyFactory.generatePublic(x509EncodedKeySpec);
DHParameterSpec dhParameterSpec = ((DHPublicKey) receiverPublicKey).getParams();
KeyPairGenerator receiverKeyPairGenerator = KeyPairGenerator.getInstance("DH");
receiverKeyPairGenerator.initialize(dhParameterSpec);
KeyPair receiverKeypair = receiverKeyPairGenerator.generateKeyPair();
PrivateKey receiverPrivateKey = receiverKeypair.getPrivate();
byte[] receiverPublicKeyEnc = receiverKeypair.getPublic().getEncoded();
// 3.密钥构建
KeyAgreement receiverKeyAgreement = KeyAgreement.getInstance("DH");
receiverKeyAgreement.init(receiverPrivateKey);
receiverKeyAgreement.doPhase(receiverPublicKey, true);
SecretKey receiverDesKey = receiverKeyAgreement.generateSecret("DES");
KeyFactory senderKeyFactory = KeyFactory.getInstance("DH");
x509EncodedKeySpec = new X509EncodedKeySpec(receiverPublicKeyEnc);
PublicKey senderPublicKey = senderKeyFactory.generatePublic(x509EncodedKeySpec);
KeyAgreement senderKeyAgreement = KeyAgreement.getInstance("DH");
senderKeyAgreement.init(senderKeyPair.getPrivate());
senderKeyAgreement.doPhase(senderPublicKey, true);
SecretKey senderDesKey = senderKeyAgreement.generateSecret("DES");
if (receiverDesKey.equals(senderDesKey)) {
System.out.println("双方密钥相同。");
}
// 4.加密
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, senderDesKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("bc dh encrypt:" + Base64.encodeBase64String(result));
// 5.解密
cipher.init(Cipher.DECRYPT_MODE, receiverDesKey);
result = cipher.doFinal(result);
System.out.println("bc dh decrypt:" + new String(result));
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.asymmetric_encryption;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import javax.crypto.spec.DHParameterSpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* @Description ElGamal算法测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:19
* @ModifyDate 2019/7/29 15:19
* @Params
* @Return
*/
public class ElGamalTest {
public static final String src = "Elgamal test";
public static void main(String[] args) {
jdkElgamal();
}
/**
* 对于:“Illegal key size or default parameters”异常,是因为美国的出口限制,Sun通过权限文件(local_policy.jar、US_export_policy.jar)做了相应限制。因此存在一些问题:
* Java 6 无政策限制文件:http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html
* Java 7 无政策限制文件:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
* 我的时java7,自己安装的。
* /Library/Java/JavaVirtualMachines/jdk1.7.0_71.jdk/Contents/Home/jre/lib/security目录下,对应覆盖local_policy.jar和US_export_policy.jar两个文件。
* <p>
* 切换到%JDK_Home%\jre\lib\security目录下,对应覆盖local_policy.jar和US_export_policy.jar两个文件。同时,你可能有必要在%JRE_Home%\lib\security目录下,也需要对应覆盖这两个文件。
*/
/**
* @Description jdk实现:“私钥解密、公钥加密” , 对于:“私钥加密、公钥解密”有问题,因为Elgamal不支持
* @Author Chongwen.jiang
* @Date 2019/7/29 10:49
* @ModifyDate 2019/7/29 10:49
* @Params []
* @Return void
*/
public static void jdkElgamal() {
try {
// 加入对BouncyCastle支持
Security.addProvider(new BouncyCastleProvider());
// 1.初始化发送方密钥
AlgorithmParameterGenerator algorithmParameterGenerator = AlgorithmParameterGenerator.getInstance("Elgamal");
// 初始化参数生成器
algorithmParameterGenerator.init(256);
// 生成算法参数
AlgorithmParameters algorithmParameters = algorithmParameterGenerator.generateParameters();
// 构建参数材料
DHParameterSpec dhParameterSpec = (DHParameterSpec) algorithmParameters.getParameterSpec(DHParameterSpec.class);
// 实例化密钥生成器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("Elgamal");
// 初始化密钥对生成器
keyPairGenerator.initialize(dhParameterSpec, new SecureRandom());
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// 公钥
PublicKey elGamalPublicKey = keyPair.getPublic();
// 私钥
PrivateKey elGamalPrivateKey = keyPair.getPrivate();
System.out.println("Public Key:" + Base64.encodeBase64String(elGamalPublicKey.getEncoded()));
System.out.println("Private Key:" + Base64.encodeBase64String(elGamalPrivateKey.getEncoded()));
// 2.私钥解密、公钥加密 ---- 加密
// 初始化公钥
// 密钥材料转换
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(elGamalPublicKey.getEncoded());
// 实例化密钥工厂
KeyFactory keyFactory2 = KeyFactory.getInstance("Elgamal");
// 产生公钥
PublicKey publicKey2 = keyFactory2.generatePublic(x509EncodedKeySpec2);
// 数据加密
// Cipher cipher2 = Cipher.getInstance("Elgamal");
Cipher cipher2 = Cipher.getInstance(keyFactory2.getAlgorithm());
cipher2.init(Cipher.ENCRYPT_MODE, publicKey2);
byte[] result2 = cipher2.doFinal(src.getBytes());
System.out.println("私钥加密、公钥解密 ---- 加密:" + Base64.encodeBase64String(result2));
// 3.私钥解密、公钥加密 ---- 解密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(elGamalPrivateKey.getEncoded());
KeyFactory keyFactory5 = KeyFactory.getInstance("Elgamal");
PrivateKey privateKey5 = keyFactory5.generatePrivate(pkcs8EncodedKeySpec5);
// Cipher cipher5 = Cipher.getInstance("Elgamal");
Cipher cipher5 = Cipher.getInstance(keyFactory5.getAlgorithm());
cipher5.init(Cipher.DECRYPT_MODE, privateKey5);
byte[] result5 = cipher5.doFinal(result2);
System.out.println("Elgamal 私钥加密、公钥解密 ---- 解密:" + new String(result5));
/*
// 私钥加密、公钥解密: 有问题
// 4.私钥加密、公钥解密 ---- 加密
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(elGamalPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("Elgamal");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Cipher cipher = Cipher.getInstance("Elgamal");
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
byte[] result = cipher.doFinal(src.getBytes());
System.out.println("私钥加密、公钥解密 ---- 加密:" + Base64.encodeBase64String(result));
// 5.私钥加密、公钥解密 ---- 解密
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(elGamalPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("Elgamal");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
cipher = Cipher.getInstance("Elgamal");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
result = cipher.doFinal(result);
System.out.println("Elgamal 私钥加密、公钥解密 ---- 解密:" + new String(result));
*/
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.pica.cloud.health.sms.server.mapper.asymmetric_encryption;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.interfaces.DHPrivateKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* @Description 非对称加密算法ElGamal算法组件
* 非对称算法一般是用来传送对称加密算法的密钥来使用的。相对于RSA算法,这个算法只支持私钥加密公钥解密
* @Author Chongwen.jiang
* @Date 2019/7/29 15:20
* @ModifyDate 2019/7/29 15:20
* @Params
* @Return
*/
public class ElGamalTest2 {
//非对称密钥算法
public static final String KEY_ALGORITHM="ElGamal";
/**
* 密钥长度,DH算法的默认密钥长度是1024
* 密钥长度必须是8的倍数,在160到16384位之间
* */
private static final int KEY_SIZE=256;
//公钥
private static final String PUBLIC_KEY="ElGamalPublicKey";
//私钥
private static final String PRIVATE_KEY="ElGamalPrivateKey";
/**
* 初始化密钥对
* @return Map 甲方密钥的Map
* */
public static Map<String,Object> initKey() throws Exception{
//加入对BouncyCastle支持
Security.addProvider(new BouncyCastleProvider());
AlgorithmParameterGenerator apg=AlgorithmParameterGenerator.getInstance(KEY_ALGORITHM);
//初始化参数生成器
apg.init(KEY_SIZE);
//生成算法参数
AlgorithmParameters params=apg.generateParameters();
//构建参数材料
DHParameterSpec elParams=(DHParameterSpec)params.getParameterSpec(DHParameterSpec.class);
//实例化密钥生成器
KeyPairGenerator kpg=KeyPairGenerator.getInstance(KEY_ALGORITHM) ;
//初始化密钥对生成器
kpg.initialize(elParams,new SecureRandom());
KeyPair keyPair=kpg.generateKeyPair();
//甲方公钥
PublicKey publicKey= keyPair.getPublic();
//甲方私钥
PrivateKey privateKey= keyPair.getPrivate();
//将密钥存储在map中
Map<String,Object> keyMap=new HashMap<String,Object>();
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
/**
* 公钥加密
* @param data 待加密数据
* @param key 密钥
* @return byte[] 加密数据
* */
public static byte[] encryptByPublicKey(byte[] data,byte[] key) throws Exception{
//实例化密钥工厂
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//初始化公钥
//密钥材料转换
X509EncodedKeySpec x509KeySpec=new X509EncodedKeySpec(key);
//产生公钥
PublicKey pubKey=keyFactory.generatePublic(x509KeySpec);
//数据加密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
return cipher.doFinal(data);
}
/**
* 私钥解密
* @param data 待解密数据
* @param key 密钥
* @return byte[] 解密数据
* */
public static byte[] decryptByPrivateKey(byte[] data,byte[] key) throws Exception{
//取得私钥
PKCS8EncodedKeySpec pkcs8KeySpec=new PKCS8EncodedKeySpec(key);
KeyFactory keyFactory=KeyFactory.getInstance(KEY_ALGORITHM);
//生成私钥
PrivateKey privateKey=keyFactory.generatePrivate(pkcs8KeySpec);
//数据解密
Cipher cipher=Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
/**
* 取得私钥
* @param keyMap 密钥map
* @return byte[] 私钥
* */
public static byte[] getPrivateKey(Map<String,Object> keyMap){
Key key=(Key)keyMap.get(PRIVATE_KEY);
return key.getEncoded();
}
/**
* 取得公钥
* @param keyMap 密钥map
* @return byte[] 公钥
* */
public static byte[] getPublicKey(Map<String,Object> keyMap) throws Exception{
Key key=(Key) keyMap.get(PUBLIC_KEY);
return key.getEncoded();
}
/** main方法测试
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//初始化密钥
//生成密钥对
Map<String,Object> keyMap=ElGamalTest2.initKey();
//公钥
byte[] publicKey=ElGamalTest2.getPublicKey(keyMap);
//私钥
byte[] privateKey=ElGamalTest2.getPrivateKey(keyMap);
System.out.println("公钥:/n"+Base64.encodeBase64String(publicKey));
System.out.println("私钥:/n"+Base64.encodeBase64String(privateKey));
System.out.println("================密钥对构造完毕,甲方将公钥公布给乙方,开始进行加密数据的传输=============");
String str="ElGamal密码交换算法";
System.out.println("/n===========甲方向乙方发送加密数据==============");
System.out.println("原文:"+str);
//乙方使用公钥对数据进行加密
byte[] code2=ElGamalTest2.encryptByPublicKey(str.getBytes(), publicKey);
System.out.println("===========乙方使用公钥对数据进行加密==============");
System.out.println("加密后的数据:"+Base64.encodeBase64String(code2));
//甲方使用私钥对数据进行解密
byte[] decode2=ElGamalTest2.decryptByPrivateKey(code2, privateKey);
System.out.println("甲方解密后的数据:"+new String(decode2));
}
}
2、单向加密
单向加密只是对信息进行了摘要计算,不能通过算法逆向生成明文。
单向加密技术采用单向散列函数(或称为哈希(Hash)函数/散列函数),可将任意长度的消息散列形成固定长度的散列值(即消息摘要),用于被用户私钥加密后生成数字签名,保证数据的完整性和不可否认性。
单向加密从严格意思上说不能算是加密的一种,而只是摘要算法,常见的单向加密技术有BASE64(一种编码形式)、MD5、SHA、HMAC(消息认证码)。
单向加密代码贴上:
package com.pica.cloud.health.sms.server.mapper.base64;
import org.apache.commons.codec.binary.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* @Description Base64加密测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 10:20
* @ModifyDate 2019/7/29 10:20
* @Params
* @Return
*/
public class Base64Test {
public static final String src = "巴啦啦能量 test";
public static void main(String[] args) {
jdkBase64();
commonsCodesBase64();
bouncyCastleBase64();
}
/**
* @Description 用jdk实现
* @Author Chongwen.jiang
* @Date 2019/7/29 10:18
* @ModifyDate 2019/7/29 10:18
* @Params []
* @Return void
*/
public static void jdkBase64() {
try
{
BASE64Encoder encoder = new BASE64Encoder();
String encode = encoder.encode(src.getBytes());
System.out.println("encode:" + encode);
BASE64Decoder decoder = new BASE64Decoder();
System.out.println("decode:" + new String(decoder.decodeBuffer(encode)));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用Apache的common codes实现
* @Author Chongwen.jiang
* @Date 2019/7/29 10:18
* @ModifyDate 2019/7/29 10:18
* @Params []
* @Return void
*/
public static void commonsCodesBase64() {
byte[] encodeBytes = Base64.encodeBase64(src.getBytes());
System.out.println("common codes encode:" + new String(encodeBytes));
byte[] dencodeBytes = Base64.decodeBase64(encodeBytes);
System.out.println("common codes decode:" + new String(dencodeBytes));
}
/**
* @Description 用bouncy castle实现
* @Author Chongwen.jiang
* @Date 2019/7/29 10:18
* @ModifyDate 2019/7/29 10:18
* @Params []
* @Return void
*/
public static void bouncyCastleBase64() {
byte[] encodeBytes = org.bouncycastle.util.encoders.Base64.encode(src.getBytes());
System.out.println("bouncy castle encode:" + new String(encodeBytes));
byte[] dencodeBytes = org.bouncycastle.util.encoders.Base64.decode(encodeBytes);
System.out.println("bouncy castle decode:" + new String(dencodeBytes));
}
}
package com.pica.cloud.health.sms.server.mapper.message_digest;
import java.security.MessageDigest;
import java.security.Security;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.digests.MD4Digest;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* @Description MD5算法实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:01
* @ModifyDate 2019/7/29 15:01
* @Params
* @Return
*/
public class MD5Test {
public static final String src = "md5 test";
public static void main(String[] args) {
jdkMD5();
jdkMD2();
bcMD4();
bcMD5();
bc2jdkMD4();
ccMD5();
ccMD2();
}
/**
* @Description 用jdk实现:MD5
* @Author Chongwen.jiang
* @Date 2019/7/29 10:57
* @ModifyDate 2019/7/29 10:57
* @Params []
* @Return void
*/
public static void jdkMD5() {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5Bytes = md.digest(src.getBytes());
System.out.println("JDK MD5:" + Hex.encodeHexString(md5Bytes));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用jdk实现:MD2
* @Author Chongwen.jiang
* @Date 2019/7/29 10:57
* @ModifyDate 2019/7/29 10:57
* @Params []
* @Return void
*/
public static void jdkMD2() {
try {
MessageDigest md = MessageDigest.getInstance("MD2");
byte[] md2Bytes = md.digest(src.getBytes());
System.out.println("JDK MD2:" + Hex.encodeHexString(md2Bytes));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用bouncy castle实现:MD5
* @Author Chongwen.jiang
* @Date 2019/7/29 10:58
* @ModifyDate 2019/7/29 10:58
* @Params []
* @Return void
*/
public static void bcMD5() {
MD5Digest digest = new MD5Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[] md5Bytes = new byte[digest.getDigestSize()];
digest.doFinal(md5Bytes, 0);
System.out.println("bouncy castle MD5:" + org.bouncycastle.util.encoders.Hex.toHexString(md5Bytes));
}
/**
* @Description 用bouncy castle实现:MD4
* @Author Chongwen.jiang
* @Date 2019/7/29 10:58
* @ModifyDate 2019/7/29 10:58
* @Params []
* @Return void
*/
public static void bcMD4() {
MD4Digest digest = new MD4Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[] md4Bytes = new byte[digest.getDigestSize()];
digest.doFinal(md4Bytes, 0);
System.out.println("bouncy castle MD4:" + org.bouncycastle.util.encoders.Hex.toHexString(md4Bytes));
}
/**
* @Description 用bouncy castle与jdk结合实现:MD4
* @Author Chongwen.jiang
* @Date 2019/7/29 10:58
* @ModifyDate 2019/7/29 10:58
* @Params []
* @Return void
*/
public static void bc2jdkMD4() {
try {
Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("MD4");
byte[] md4Bytes = md.digest(src.getBytes());
System.out.println("bc and JDK MD4:" + Hex.encodeHexString(md4Bytes));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用common codes实现实现:MD5
* @Author Chongwen.jiang
* @Date 2019/7/29 10:58
* @ModifyDate 2019/7/29 10:58
* @Params []
* @Return void
*/
public static void ccMD5() {
System.out.println("common codes MD5:" + DigestUtils.md5Hex(src.getBytes()));
}
/**
* @Description 用common codes实现实现:MD2
* @Author Chongwen.jiang
* @Date 2019/7/29 10:58
* @ModifyDate 2019/7/29 10:58
* @Params []
* @Return void
*/
public static void ccMD2() {
System.out.println("common codes MD2:" + DigestUtils.md2Hex(src.getBytes()));
}
}
package com.pica.cloud.health.sms.server.mapper.message_digest;
import java.security.MessageDigest;
import java.security.Security;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.digests.SHA224Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.math.BigInteger;
/**
* @Description SHA算法实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:04
* @ModifyDate 2019/7/29 15:04
* @Params
* @Return
*/
public class SHATest {
public static final String src = "sha test";
public static void main(String[] args) {
jdkSHA1();
bcSHA1();
bcSHA224();
bcSHA224b();
generateSha256();
ccSHA1();
}
/**
* @Description 用jdk实现:SHA1
* @Author Chongwen.jiang
* @Date 2019/7/29 10:56
* @ModifyDate 2019/7/29 10:56
* @Params []
* @Return void
*/
public static void jdkSHA1() {
try {
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(src.getBytes());
System.out.println("jdk sha-1:" + Hex.encodeHexString(md.digest()));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用bouncy castle实现:SHA1
* @Author Chongwen.jiang
* @Date 2019/7/29 10:56
* @ModifyDate 2019/7/29 10:56
* @Params []
* @Return void
*/
public static void bcSHA1() {
Digest digest = new SHA1Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[] sha1Bytes = new byte[digest.getDigestSize()];
digest.doFinal(sha1Bytes, 0);
System.out.println("bc sha-1:" + org.bouncycastle.util.encoders.Hex.toHexString(sha1Bytes));
}
/**
* @Description 用bouncy castle实现:SHA224
* @Author Chongwen.jiang
* @Date 2019/7/29 10:56
* @ModifyDate 2019/7/29 10:56
* @Params []
* @Return void
*/
public static void bcSHA224() {
Digest digest = new SHA224Digest();
digest.update(src.getBytes(), 0, src.getBytes().length);
byte[] sha224Bytes = new byte[digest.getDigestSize()];
digest.doFinal(sha224Bytes, 0);
System.out.println("bc sha-224:" + org.bouncycastle.util.encoders.Hex.toHexString(sha224Bytes));
}
/**
* @Description 用bouncy castle与jdk结合实现:SHA224
* @Author Chongwen.jiang
* @Date 2019/7/29 10:56
* @ModifyDate 2019/7/29 10:56
* @Params []
* @Return void
*/
public static void bcSHA224b() {
try {
Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("SHA224");
md.update(src.getBytes());
System.out.println("bc and JDK sha-224:" + Hex.encodeHexString(md.digest()));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void generateSha256() {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(src.getBytes("UTF-8")); // Change this to "UTF-16" if needed
byte[] digest = md.digest();
BigInteger bigInt = new BigInteger(1, digest);
System.out.println("Sha256 hash: " + bigInt.toString(16));
} catch (Exception e) {
System.out.println(e.toString());
}
}
/**
* @Description 用common codes实现实现:SHA1
* @Author Chongwen.jiang
* @Date 2019/7/29 10:57
* @ModifyDate 2019/7/29 10:57
* @Params []
* @Return void
*/
public static void ccSHA1() {
System.out.println("common codes SHA1 - 1 :" + DigestUtils.sha1Hex(src.getBytes()));
System.out.println("common codes SHA1 - 2 :" + DigestUtils.sha1Hex(src));
}
}
package com.pica.cloud.health.sms.server.mapper.message_digest;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
/**
* @Description HMAC算法实现测试类
* @Author Chongwen.jiang
* @Date 2019/7/29 15:04
* @ModifyDate 2019/7/29 15:04
* @Params
* @Return
*/
public class HMACTest {
public static final String src = "hmac test";
public static void main(String[] args) {
jdkHmacMD5();
bcHmacMD5();
}
/**
* @Description 用jdk实现:
* @Author Chongwen.jiang
* @Date 2019/7/29 10:59
* @ModifyDate 2019/7/29 10:59
* @Params []
* @Return void
*/
public static void jdkHmacMD5() {
try {
// 初始化KeyGenerator
KeyGenerator keyGenerator = KeyGenerator.getInstance("HmacMD5");
// 产生密钥
SecretKey secretKey = keyGenerator.generateKey();
// 获取密钥
// byte[] key = secretKey.getEncoded();
byte[] key = Hex.decodeHex(new char[]{'1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e'});
// 还原密钥
SecretKey restoreSecretKey = new SecretKeySpec(key, "HmacMD5");
// 实例化MAC
Mac mac = Mac.getInstance(restoreSecretKey.getAlgorithm());
// 初始化MAC
mac.init(restoreSecretKey);
// 执行摘要
byte[] hmacMD5Bytes = mac.doFinal(src.getBytes());
System.out.println("jdk hmacMD5:" + Hex.encodeHexString(hmacMD5Bytes));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 用bouncy castle实现
* @Author Chongwen.jiang
* @Date 2019/7/29 10:59
* @ModifyDate 2019/7/29 10:59
* @Params []
* @Return void
*/
public static void bcHmacMD5() {
HMac hmac = new HMac(new MD5Digest());
// 必须是16进制的字符,长度必须是2的倍数
hmac.init(new KeyParameter(org.bouncycastle.util.encoders.Hex.decode("123456789abcde")));
hmac.update(src.getBytes(), 0, src.getBytes().length);
// 执行摘要
byte[] hmacMD5Bytes = new byte[hmac.getMacSize()];
hmac.doFinal(hmacMD5Bytes, 0);
System.out.println("bc hmacMD5:" + org.bouncycastle.util.encoders.Hex.toHexString(hmacMD5Bytes));
}
}
3、数字签名证书
非对称加密已经灰常安全了,但是还有一个破绽:
服务器A公布了自己的公钥,我的电脑是用服务器A的公钥加密数据后再发给服务器A的;这时候服务器B侵入了我的电脑,把我用来加密的公钥换成了它的公钥,于是我发出去的数据就会被服务器B的私钥破解了。肿么防止公钥被篡改呢?
对,我们想到了前面的消息摘要,服务器A把公钥丢给我的时候,同时去CA申请一份数字证书,其实主要就是公钥的消息摘要,有了这份证书,当我再用公钥加密的时候,我就可以先验证一下当前的公钥是否确定是服务器A发送给我的。
数字签名代码贴上:
// Copyright 2016-2101 Pica.
package com.pica.cloud.health.sms.server.mapper.signature;
import org.apache.commons.codec.binary.Hex;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* @ClassName SignatureTest
* @Description 数字签名测试类(RSA、DSA、ECDSA)
* @Author Chongwen.jiang
* @Date 2019/7/29 10:26
* @ModifyDate 2019/7/29 10:26
* @Version 1.0
*/
public class SignatureTest {
public static final String SRC_RSA = "RSA security is security";
public static final String SRC_DSA = "DSA security is security";
public static final String SRC_ECDSA = "ECDSA security is security";
public static void main(String[] args) {
jdkRSA();
jdkDSA();
jdkECDSA();
}
/**
* @Description 用java的jdk里面相关方法实现rsa的签名及签名验证
* @Author Chongwen.jiang
* @Date 2019/7/29 10:29
* @ModifyDate 2019/7/29 10:29
* @Params []
* @Return void
*/
public static void jdkRSA() {
try {
// 1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();
// 2.进行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("MD5withRSA");
signature.initSign(privateKey);
signature.update(SRC_RSA.getBytes());
byte[] result = signature.sign();
System.out.println("jdk rsa sign:" + Hex.encodeHexString(result) );
// 3.验证签名
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("MD5withRSA");
signature.initVerify(publicKey);
signature.update(SRC_RSA.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk rsa verify:" + bool);
} catch (Exception e) {
System.out.println(e.toString());
}
}
/**
* @Description 用java的jdk里面相关方法实现dsa的签名及签名验证
* @Author Chongwen.jiang
* @Date 2019/7/29 10:34
* @ModifyDate 2019/7/29 10:34
* @Params []
* @Return void
*/
public static void jdkDSA () {
try {
// 1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
DSAPublicKey dsaPublicKey = (DSAPublicKey)keyPair.getPublic();
DSAPrivateKey dsaPrivateKey = (DSAPrivateKey)keyPair.getPrivate();
// 2.进行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(privateKey);
signature.update(SRC_DSA.getBytes());
byte[] result = signature.sign();
System.out.println("jdk dsa sign:" + Hex.encodeHexString(result) );
// 3.验证签名
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(dsaPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("DSA");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withDSA");
signature.initVerify(publicKey);
signature.update(SRC_DSA.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk dsa verify:" + bool);
} catch (Exception e) {
System.out.println(e.toString());
}
}
/**
* @Description 用java的jdk里面相关方法实现ECDSA的签名及签名验证,要jdk7.x以上,ECDSA:椭圆曲线数字签名算法
* @Author Chongwen.jiang
* @Date 2019/7/29 10:34
* @ModifyDate 2019/7/29 10:34
* @Params []
* @Return void
*/
public static void jdkECDSA () {
try {
// 1.初始化密钥
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");
keyPairGenerator.initialize(256);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();
ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate();
// 2.进行签名
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("EC");
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
Signature signature = Signature.getInstance("SHA1withECDSA");
signature.initSign(privateKey);
signature.update(SRC_ECDSA.getBytes());
byte[] result = signature.sign();
System.out.println("jdk ecdsa sign:" + Hex.encodeHexString(result) );
// 3.验证签名
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ecPublicKey.getEncoded());
keyFactory = KeyFactory.getInstance("EC");
PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
signature = Signature.getInstance("SHA1withECDSA");
signature.initVerify(publicKey);
signature.update(SRC_ECDSA.getBytes());
boolean bool = signature.verify(result);
System.out.println("jdk ecdsa verify:" + bool);
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
关于数字签名和非对称加密算法的使用,还看到一个非常棒的例子,分享给大家:
唉,这个月买了太多的书,到月底揭不开锅了。正巧在QQ上遇到了Clark:
1-2-3:“Clark,我需要200两纹银,能否借给我?”
Clark:“没问题。我这就给你转账。请给我一张借条。”
1-2-3:“太谢谢了,我这就用Word写一个借条给你。”
然后,我新建一个Word文档,写好借条,存盘。然后,然后怎么办呢?我不能直接把借条发送给Clark,原因有:
- 我无法保证Clark不会在收到借条后将“纹银200两”改为“纹银2000两”。
- 如果我赖账,Clark无法证明这个借条就是我写的。
- 普通的Word文档不能作为打官司的证据。
好在我早就申请了数字证书。我先用我的私钥对借条进行加密,然后将加密后的密文用QQ发送给Clark。Clark收到了借条的密文后,在数字证书认证中心的网站上下载我的公钥,然后使用我的公钥将密文解密,发现确实写的是“借纹银200两”,Clark就可以把银子放心的借给我了,我也不会担心Clark会篡改我的借条,原因是: - 由于我发给Clark的是密文,Clark无法进行修改。Clark倒是可以修改解密后的借条,但是Clark没有我的私钥,没法模仿我对借条进行加密。这就叫防篡改。
- 由于用我的私钥进行加密的借条,有且只有我的公钥可以解密。反过来讲,能用我的公钥解密的借条,一定是使用我的私钥加密的,而只有我才拥有我的私钥,这样Clark就可以证明这个借条就是我写的。这就叫防抵赖。
- 如果我一直赖着不还钱,Clark把我告上了法庭,这个用我的私钥加密过的Word文档就可以当作程堂证供。因为我国已经出台了《中华人民共和国电子签名法》,使数字签名具有了法律效力。
您一定已经注意到了,这个使用我的私钥进行了加密的借条,具有了防篡改、防抵赖的特性,并且可以作为程堂证供,就跟我对这个借条进行了“签名”的效果是一样的。对了,“使用我的私钥对借条进行加密”的过程就叫做数字签名。