基本的bai单向加密算法:
复杂的对称加密(DES、PBE)、非对称加密算法:
加密大全
私钥,公钥,会话密钥,数字签名
maven依赖:
commons-codec
commons-codec
1.14
Java代码:
import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64;
public class BASE64Test {
public static void main(String[] args) {
String str = "Hello World";
try{
byte[] encodeBase64 = Base64.encodeBase64(str.getBytes("UTF-8"));
System.out.println("Result: " + new String(encodeBase64));
} catch(UnsupportedEncodingException e){
e.printStackTrace();
}
}
}
打印结果:
Result: SGVsbG8gV29ybGQ=
maven依赖:
org.springframework
spring-context
5.2.7.RELEASE
Java代码:
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.springframework.util.DigestUtils;
public class MD5Test {
public static void main(String[] args) {
String str1 = getMD5Str("tianming");
String str2 = getMD5str2("tianming");
System.out.println(str1);
System.out.println(str2);
}
/**
* @Description MD5加密方式1:使用JDK自带MessageDigest
* @author yiguang
* @date 2020-08-11
*/
public static String getMD5Str(String str) {
byte[] digest = null;
try {
MessageDigest md5 = MessageDigest.getInstance("md5");
digest = md5.digest(str.getBytes("utf-8"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
//16是表示转换为16进制数
String md5Str = new BigInteger(1, digest).toString(16);
return md5Str;
}
/**
* @Description MD5加密方式2:使用spring自带工具包DigestUtils
* @author yiguang
* @date 2020-08-11
*/
public static String getMD5str2(String str) {
String md5Str = DigestUtils.md5DigestAsHex("原串".getBytes());
return md5Str;
}
}
打印结果:
注意:
maven依赖:
commons-codec
commons-codec
1.14
javax.xml.rpc
javax.xml.rpc-api
1.1.1
Java代码:
import java.io.IOException;
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.IvParameterSpec;
import org.apache.commons.codec.binary.Base64;
public class DESTest {
public static void main(String[] args) throws IOException {
String deskey = "password";//des密钥//长度8位
String content = "真香警告!"; //内容
System.out.println("DES原始加密内容为:"+content);
//加密
byte[] encryptbyte = desEncrypt(content, deskey); //加密后返回为字节数组
System.out.println("DES加密后内容为:"+ new String(encryptbyte));
System.out.println("DES加密后内容为:"+ Base64.encodeBase64String(encryptbyte));
//解密
byte[] decryptbyte = desDecrypt(encryptbyte, deskey); //将加密后返回的字节数组进行解密
System.out.println("DES解密后内容为:"+ new String(decryptbyte));
}
/**
* @Description 加密
* @author yiguang
* @date 2020-08-11
*/
public static byte[] desEncrypt(String context, String key) {
try {
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey conventSecretKey = secretKeyFactory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, conventSecretKey, new IvParameterSpec(key.getBytes("UTF-8")));
return cipher.doFinal(context.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/**
* @Description 解密
* @author yiguang
* @date 2020-08-11
*/
public static byte[] desDecrypt(byte[] context, String key) {
try {
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey conventSecretKey = secretKeyFactory.generateSecret(desKeySpec);
// 解密
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, conventSecretKey, new IvParameterSpec(key.getBytes("UTF-8")));
return cipher.doFinal(context);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
打印结果:
DES问题:如果将DES加密后的字符串作为url中的参数,那么可能会在获取这些参数的时候,会失败,因为加密后的字符串存在“+ 、=”这种特殊符号。
如:如果companyId是DES加密后的字符串,那么在后端获取该参数的时候,就无法完整获取到。那么可以如下解决:
第一步:创建UrlUtil类进行url转换
import java.io.UnsupportedEncodingException;
/**
* @Title: UrlUtil.java
* @Package cn.rntd.pc.shop.utils
* @ClassName: UrlUtil
* @Description: url加密
* @author yiguang
* @date 2020-08-12
*/
public class UrlUtil {
private final static String ENCODE = "GBK";
public static String getURLDecoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLDecoder.decode(str, ENCODE);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
public static String getURLEncoderString(String str) {
String result = "";
if (null == str) {
return "";
}
try {
result = java.net.URLEncoder.encode(str, ENCODE);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return result;
}
public static void main(String[] args) {
String str = "测试1";
System.out.println(getURLEncoderString(str));
System.out.println(getURLDecoderString(str));
}
}
第二步:先加密,再url转码
import java.io.IOException;
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.IvParameterSpec;
import org.apache.commons.codec.binary.Base64;
public class DESEncryption {
public static void main(String[] args) throws IOException {
String deskey = "password";//des密钥//长度8位
String content = "真香警告!"; //内容
System.out.println("DES原始加密内容为:"+content);
//加密
byte[] encryptbyte = desEncrypt(content, deskey); //加密后返回为字节数组
System.out.println("DES加密后内容为(字节数组):"+ new String(encryptbyte));
String url0=Base64.encodeBase64String(encryptbyte);
System.out.println("DES加密后通过base64转换内容为(字符串):"+ url0);
String url1=UrlUtil.getURLEncoderString(url0);
System.out.println("前端传参 (经过url转换) :"+url1);
System.out.println("---------------");
//解密
System.out.println("后端接收:"+url1);
String url3 = UrlUtil.getURLDecoderString(url1);
System.out.println("经过url解析:"+url3);
byte[] decoderbyte=Base64.decodeBase64(url3);
System.out.println("DES加密后通过base64解析内容为(字节数组):"+ decoderbyte);
byte[] decryptbyte = desDecrypt(encryptbyte, deskey); //将加密后返回的字节数组进行解密
System.out.println("DES解密后内容为:"+ new String(decryptbyte));
}
/**
* @Title: desEncrypt
* @Description: 加密
* @param context
* @param key
* @return byte[] (这里描述输出参数的作用)
* @throws
* @author yiguang
* @date 2020-08-11
*/
public static byte[] desEncrypt(String context, String key) {
try {
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey conventSecretKey = secretKeyFactory.generateSecret(desKeySpec);
// 加密
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, conventSecretKey, new IvParameterSpec(key.getBytes("UTF-8")));
return cipher.doFinal(context.getBytes("UTF-8"));
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
/**
* @Title: desDecrypt
* @Description: 解密
* @param context
* @param key
* @return byte[] (这里描述输出参数的作用)
* @throws
* @author yiguang
* @date 2020-08-11
*/
public static byte[] desDecrypt(byte[] context, String key) {
try {
// KEY转换
DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("DES");
SecretKey conventSecretKey = secretKeyFactory.generateSecret(desKeySpec);
// 解密
Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, conventSecretKey, new IvParameterSpec(key.getBytes("UTF-8")));
return cipher.doFinal(context);
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
}
打印结果:经过url解析后就可以作为参数传递了
DSA(Digital Signature Algorithm)是Schnorr和ElGamal签名算法的变种,被美国NIST作为DSS(DigitalSignature Standard)。
DSA加密算法主要依赖于整数有限域离散对数难题,素数P必须足够大,且p-1至少包含一个大素数因子以抵抗Pohlig &Hellman算法的攻击。M一般都应采用信息的HASH值。DSA加密算法的安全性主要依赖于p和g,若选取不当则签名容易伪造,应保证g对于p-1的大素数因子不可约。其安全性与RSA相比差不多。
DSA 一般用于数字签名和认证。在DSA数字签名和认证中,发送者使用自己的私钥对文件或消息进行签名,接受者收到消息后使用发送者的公钥来验证签名的真实性。DSA只是一种算法,和RSA不同之处在于它不能用作加密和解密,也不能进行密钥交换,只用于签名,它比RSA要快很多.
1. DSA签名及验证
DSA算法中应用了下述参数:
p:L bits长的素数。L是64的倍数,范围是512到1024;
q:p – 1的160bits的素因子;
g:g = h^((p-1)/q) mod p,h满足h < p – 1, h^((p-1)/q) mod p > 1;
x:x < q,x为私钥 ;
y:y = g^x mod p ,( p, q, g, y )为公钥;
H( x ):One-Way Hash函数。DSS中选用SHA( Secure Hash Algorithm )。
p, q, g可由一组用户共享,但在实际应用中,使用公共模数可能会带来一定的威胁。
签名及验证协议:
举例:B 发消息给A,使用DSA算法进行签名
1.生成素数p=59、素数q=29、h=11、私钥x=7,临时密钥k=10,消息摘要H(M)=26
2.生成g:
g=h^(p-1)/qmod p → g=11^2 mod 59 → g=3
3.计算公钥y
y=g^xmod p → y=3^7 mod 59 →y=2187 mod 59 →y=4
4.进行签名计算
r = (g^k mod p) mod q → r=(59049 mod 59) mod 29 →r=20
s = [k^-1 (H(M) + xr) ] mod q → s=3·(26+140)mod 29 → s=5
5.A收到消息后进行签名验证
w=(s’)^-1mod q → w=6 mod 29 =6
u1=[H(M’)w] mod q → u1=156 mod 29 = 11
u2=(r’)wmod q → u2=120 mod 29=4
v=[(g^u1 · y^u2) mod p] mod q → v= (45349632 mod 59) mod 29 =20
v=r=20
6.验证成功;
2.DSA使用过程
过程:
构建密钥对:
发送方: 1.构建密钥对
2.公布密钥
发送数据 :
发送方: 1.使用私钥对数据签名
2.发送签名,数据
3.使用公钥,签名验证数据
3. Java实现DSA生成公私钥并加解密
3.1代码如下
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.*;
/**
* Created by cuiran on 19/1/11.
* 生成一对文件 publicKey.key 和 privateKey.key ,
* 公钥要用户发送 ( 文件 , 网络等方法 ) 给其它用户 , 私钥保存在本地
* 1.生成秘钥对
* 2.使用私钥进行签名
* 3.使用公钥校验签名
* 意义上的加密解密 非内容型的加密解密
*/
public class DSA {
public static void main(String[] args) {
//初始化秘钥对写入到文件 生成的是X.509编码格式的 生成的私钥是PKCS#8编码格式
getKeyPairs();
//明文签名
SignatureData("我是cayden,银行账户为622XXXX");
//校验签名文件
checkSignature();
}
/**
* 生成秘钥对写入到文件
* @return
*/
public static boolean getKeyPairs() {
try {
//初始化秘钥管理器
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DSA");
keyPairGenerator.initialize(512);
KeyPair keyPair = keyPairGenerator.genKeyPair();
//获取秘钥对
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
//直接写入公钥
ObjectOutputStream out_pub = new ObjectOutputStream(new FileOutputStream("publicKey.key"));
out_pub.writeObject(publicKey);
out_pub.close();
System.out.println("生成的公钥内容为_____:\n "+publicKey);
//直接写入私钥
ObjectOutputStream out_pri = new ObjectOutputStream(new FileOutputStream("privateKey.key"));
out_pri.writeObject(privateKey);
out_pri.close();
System.out.println("生成的私钥内容为_____:\n "+privateKey);
System.out.println("\n生成密钥对成功...");
return true;
} catch (java.lang.Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 使用私钥进行签名
* @return
*/
public static boolean SignatureData(String info){
try {
//1.读取生成的私钥对明文进行签名
ObjectInputStream in_pri = new ObjectInputStream(new java.io.FileInputStream("privateKey.key"));
PrivateKey privateKey = (PrivateKey) in_pri.readObject();
in_pri.close();
//初始化签名 对明文开始签名
Signature signature = Signature.getInstance("DSA");
signature.initSign(privateKey);
signature.update(info.getBytes());
// 对信息的数字签名
byte[] signedbytes = signature.sign();
System.out.println("签名为_____:"+signedbytes);
//把签名的密文存到文件中
ObjectOutputStream out_signature =new ObjectOutputStream(new FileOutputStream("signature.data"));
//把明文和签名一起写入 也可以分别写入
out_signature.writeObject(info);
out_signature.writeObject(signedbytes);
out_signature.close();
System.out.println("秘钥签名完成.......");
} catch (Exception e) {
e.printStackTrace();
System.out.println("私钥签名失败....");
}
return false;
}
/**
* 用公钥进行校验
* @return
*/
public static boolean checkSignature(){
try {
//读取公钥
ObjectInputStream in_pub=new ObjectInputStream(new FileInputStream("publicKey.key"));
PublicKey publicKey = (PublicKey) in_pub.readObject();
//读取签名文件
ObjectInputStream in_signature=new ObjectInputStream(new FileInputStream("signature.data"));
//读取签名信息
String info = (String) in_signature.readObject();
//用公钥进行校验
byte[] signedbytes = (byte[]) in_signature.readObject();
Signature signature = Signature.getInstance("DSA");
signature.initVerify(publicKey);
signature.update(info.getBytes());
//签名信息校验
if (signature.verify(signedbytes)) {
System.out.println("签名的内容为____:" + info);
System.out.println("签名文件校验正常....");
return true;
} else{
System.out.println("签名校验失败");
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
打印结果: