目录
一、加密方式和区别
二、对称加密
2.1 DES加密
2.2 3DES加密
三、非对称加密
3.1 RSA加密
四、移动APP安全接口设计
4.1 非对称加密解密
4.2 对称加密解密
一般金融类的产品,涉及前端和后端交互的时候,都会都严格的数据安全保证。防止黑客攻击,信息篡改。
加密方式有很多,总的来说,分为2种:对称和非对称。我们先来看一下,这两种加密方式分别是什么?他们有什么区别?
对称加密:对称加密是最快速、最简单的一种加密方式,加密(encryption)与解密(decryption)用的是同样的密钥(secret key)
非对称加密:数据的加密与解密提供了一个非常安全的方法,它使用了一对密钥,公钥(public key)和私钥(private key)。私钥只能由一方安全保管,不能外泄,而公钥则可以发给任何请求它的人。因此安全性大大提高。
所谓对称加密算法即:加密和解密使用相同密钥的算法。常见的有DES、3DES、AES、PBE等加密算法,这几种算法安全性依次是逐渐增强的。
常见的对称加密算法有DES、3DES、Blowfish、IDEA、RC4、RC5、RC6和AES。对称加密算法使用起来简单快捷,密钥较短,且破译困难。
但是对称秘钥在使用过程中存在以下问题:
1、对称加密算法一般不能提供信息完整性的鉴别。它无法验证发送者和接受者的身份;
2、对称密钥的管理和分发工作是一件具有潜在危险的和烦琐的过程。如何防止秘钥泄露是一个难点。
DES是一种对称加密算法,是一种非常简便的加密算法,但是密钥长度比较短。DES加密算法出自IBM的研究,后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法.简单的DES加密算法实现:
先引入jar包的依赖
org.springframework.security
spring-security-rsa
1.0.8.RELEASE
public class DESUtil {
private static final String KEY_ALGORITHM = "DES";
private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";//默认的加密算法
/**
* DES 加密操作
* @param content 待加密内容
* @param key 加密密钥
* @return 返回Base64转码后的加密数据
*/
public static String encrypt(String content, String key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return Base64.encodeBase64String(result);//通过Base64转码返回
} catch (Exception ex) {
Logger.getLogger(DESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* DES 解密操作
* @param content
* @param key
* @return
*/
public static String decrypt(String content, String key) {
try {
//实例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
//执行操作
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result, "utf-8");
} catch (Exception ex) {
Logger.getLogger(DESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* 生成加密秘钥
*
* @return
*/
private static SecretKeySpec getSecretKey(final String key) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//DES 要求密钥长度为 56
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kg.init(56, random);
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为DES专用密钥
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(DESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static void main(String[] args) {
String content = "hello,您好";
String key = "sde@5f98H*^hsff%dfs$r344&df8543*er";
System.out.println("content:" + content);
String s1 = DESUtil.encrypt(content, key);
System.out.println("s1:" + s1);
System.out.println("s2:"+ DESUtil.decrypt(s1, key));
}
}
3DES是一种对称加密算法,在 DES 的基础上,使用三重数据加密算法,对数据进行加密,它相当于是对每个数据块应用三次 DES 加密算法。由于计算机运算能力的增强,原版 DES 密码的密钥长度变得容易被暴力破解;3DES 即是设计用来提供一种相对简单的方法,即通过增加 DES 的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法这样来说,破解的概率就小了很多。缺点由于使用了三重数据加密算法,可能会比较耗性能。简单的3DES加密算法实现:
public class TripDESUtil {
private static final String KEY_ALGORITHM = "DESede";
private static final String DEFAULT_CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";//默认的加密算法
/**
* DESede 加密操作
* @param content 待加密内容
* @param key 加密密钥
* @return 返回Base64转码后的加密数据
*/
public static String encrypt(String content, String key) {
try {
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);// 创建密码器
byte[] byteContent = content.getBytes("utf-8");
cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));// 初始化为加密模式的密码器
byte[] result = cipher.doFinal(byteContent);// 加密
return Base64.encodeBase64String(result);//通过Base64转码返回
} catch (Exception ex) {
Logger.getLogger(TripDESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* DESede 解密操作
*
* @param content
* @param key
* @return
*/
public static String decrypt(String content, String key) {
try {
//实例化
Cipher cipher = Cipher.getInstance(DEFAULT_CIPHER_ALGORITHM);
//使用密钥初始化,设置为解密模式
cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
//执行操作
byte[] result = cipher.doFinal(Base64.decodeBase64(content));
return new String(result, "utf-8");
} catch (Exception ex) {
Logger.getLogger(TripDESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
/**
* 生成加密秘钥
* @return
*/
private static SecretKeySpec getSecretKey(final String key) {
//返回生成指定算法密钥生成器的 KeyGenerator 对象
KeyGenerator kg = null;
try {
kg = KeyGenerator.getInstance(KEY_ALGORITHM);
//DES 要求密钥长度为 56
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(key.getBytes());
kg.init(168, random);
//生成一个密钥
SecretKey secretKey = kg.generateKey();
return new SecretKeySpec(secretKey.getEncoded(), KEY_ALGORITHM);// 转换为DESede专用密钥
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(TripDESUtil.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
public static void main(String[] args) {
String content = "hello,您好";
String key = "sde@5f98H*^hsff%dfs$r344&df8543*er";
System.out.println("content:" + content);
String s1 = TripDESUtil.encrypt(content, key);
System.out.println("s1:" + s1);
System.out.println("s2:"+ TripDESUtil.decrypt(s1, key));
}
}
非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)。公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。一般公钥是公开的,私钥是自己保存。因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。安全性相对对称加密来说更高,是一种高级加密方式。
RSA是一种非对称加密算法.RSA有两个密钥,一个是公开的,称为公开密钥;一个是私密的,称为私密密钥。公开密钥是对大众公开的,私密密钥是服务器私有的,两者不能互推得出。用公开密钥对数据进行加密,私密密钥可解密;私密密钥对数据加密,公开密钥可解密。速度较对称加密慢。简单的RSA加密算法实现:
public class RSAUtil {
public static String publicKey; // 公钥
public static String privateKey; // 私钥
/**
* 生成公钥和私钥
*/
public static void generateKey() {
// 1.初始化秘钥
KeyPairGenerator keyPairGenerator;
try {
keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom sr = new SecureRandom(); // 随机数生成器
keyPairGenerator.initialize(512, sr); // 设置512位长的秘钥
KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 开始创建
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
// 进行转码
publicKey = Base64.encodeBase64String(rsaPublicKey.getEncoded());
// 进行转码
privateKey = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/**
* 私钥匙加密或解密
*
* @param content
* @param privateKeyStr
* @return
*/
public static String encryptByprivateKey(String content, String privateKeyStr, int opmode) {
// 私钥要用PKCS8进行处理
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyStr));
KeyFactory keyFactory;
PrivateKey privateKey;
Cipher cipher;
String text = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
// 还原Key对象
privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
cipher = Cipher.getInstance("RSA");
cipher.init(opmode, privateKey);
//加密解密操作
text = encryptTxt(opmode,cipher,content);
} catch (Exception e) {
e.printStackTrace();
}
return text;
}
public static String encryptTxt(int opmode, Cipher cipher, String content){
byte[] result;
String text = null;
try{
if (opmode == Cipher.ENCRYPT_MODE) { // 加密
result = cipher.doFinal(content.getBytes());
text = Base64.encodeBase64String(result);
} else if (opmode == Cipher.DECRYPT_MODE) { // 解密
result = cipher.doFinal(Base64.decodeBase64(content));
text = new String(result, "UTF-8");
}
}catch (Exception e){
e.printStackTrace();
}
return text;
}
/**
* 公钥匙加密或解密
*
* @param content
* @return
*/
public static String encryptByPublicKey(String content, String publicKeyStr, int opmode) {
// 公钥要用X509进行处理
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyStr));
KeyFactory keyFactory;
PublicKey publicKey;
Cipher cipher;
String text = null;
try {
keyFactory = KeyFactory.getInstance("RSA");
// 还原Key对象
publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
cipher = Cipher.getInstance("RSA");
cipher.init(opmode, publicKey);
//加密解密操作
text = encryptTxt(opmode,cipher,content);
} catch (Exception e) {
e.printStackTrace();
}
return text;
}
public static void main(String[] args) {
// 1. 生成(公钥和私钥)密钥对
RSAUtil.generateKey();
System.out.println("公钥:" + RSAUtil.publicKey);
System.out.println("私钥:" + RSAUtil.privateKey);
System.out.println("----------公钥加密私钥解密(推荐),非对称加密,公钥保存在客户端,私钥保存在服务端-------------");
// 使用 公钥加密,私钥解密
String textsr = "irish";
String encryptByPublic = RSAUtil.encryptByPublicKey(textsr, RSAUtil.publicKey, Cipher.ENCRYPT_MODE);
System.out.println("公钥加密:" + encryptByPublic);
String text = RSAUtil.encryptByprivateKey(encryptByPublic, RSAUtil.privateKey, Cipher.DECRYPT_MODE);
System.out.println("私钥解密:" + text);
System.out.println("----------私钥加密公钥解密(不推荐),因为这样会把私钥暴露出来-------------");
// 使用 私钥加密
String body = "{\n" +
" \"loginName\":\"1+1\",\n" +
" \"password\":\"pass\"\n" +
"}";
String txtByPrivate = RSAUtil.encryptByprivateKey(body, RSAUtil.privateKey, Cipher.ENCRYPT_MODE);
System.out.println("私钥加密:" + txtByPrivate);
String txtByPublic = RSAUtil.encryptByPublicKey(txtByPrivate, RSAUtil.publicKey, Cipher.DECRYPT_MODE);
System.out.println("公钥解密:" + txtByPublic);
}
}
输出结果:
非对称加密算法实现机密信息交换的基本过程是:甲方生成一对密钥并将公钥公开,需要向甲方发送信息的其他角色(乙方)使用该密钥(甲方的公钥)对机密信息进行加密后再发送给甲方;甲方再用自己私钥对加密后的信息进行解密。甲方想要回复乙方时正好相反,使用乙方的公钥对数据进行加密,同理,乙方使用自己的私钥来进行解密。简单的原理图,如下:
先生成秘钥对
// 1. 生成(公钥和私钥)密钥对
RSAUtil.generateKey();
System.out.println("公钥:" + RSAUtil.publicKey);
System.out.println("私钥:" + RSAUtil.privateKey);
客户端代码:
然后将公钥保存在客户端进行加密使用,私钥放在服务端进行解密使用
因为我是模拟客户端的请求,所以可以直接运行项目中的RSAUtil.java文件获得密钥对和加密的报文
服务端代码:
首先定义拦截器和需要拦截的请求,并且将私钥放到服务端(因为是demo,所以我就将私钥变量,直接放到拦截器了,正式开发需要分开定义)
服务端接收加密的请求,并通过私钥解密,将解密之后的明文,放入到业务方法
业务方法:
最终输出结果:
未解密的报文参数:{ "param":"ApIKo00FX5YmB/vRjTssCUpaug5sGudt1B2zoubIuBTrxhSXXL6oxMEy3j98M4R+VT/XRTNNsQQQ+mLmXHjqgWljHdpBY9OHdO23jQZW//17ozQgKY9ahsXXf1lBWvzZigglbTs7HaCHaIdDkieTKNVdzyWuVTFWZQVbx+BBc0d4XA2JbRPj18p3jtI8GIRKrITuxPHOhLGLrmEIrOL683w8rZHsE9iWp3CvDe25MnB+Zwx3DV39K06aqWGFC6sktqqdbUdzQmmUn8Yanz+MkYFPG5FiUV57tLcD+huh1caohflPRvQMImdqS5UGrREn7hZuPNTm4XFli/1TjXaFEZAl8tpy/ENhEq2vhwrGqY6zU137jKV1IB9taJUI2JuURi1fSUbkYmutIUak6voqwGkP9pyz3JETmKqxSScksBT4Jn6/PCFqwYBWpK52n2HkcB8RHk4+jzGeX8ZLxpuANWhFmF533GOToLMBKsKpSqLAwCPxyQLdehcf1y+iJisAKJQ/3PM2kQWZqhp90xe9w8qFLPsrDaL5qjuxvasy7NO7YcBkM5XbrUfa6z5A/PFuchm126UkS7ddNd5xy4InOSAyJK5PTSIlrFa7VhgxFFO1lO+JnnimsO4CESvUulzXoXXoAabqVmIIcp3pEyOb3wzSP77U3Uv7Oemj9MdjKr0="}
已解密的报文参数:{
"base":{
"uid":12,
"name":"李四2"
},
"sex":"男"
}
===========================我是业务方法=========================
uid=12
name=李四2
性别是:男
项目代码地址:
https://github.com/loafer7423/signature
它的原理是客户端和服务端公用一把秘钥,这把秘钥既可以用作加密,也可以用作解密。代码逻辑和上面的案例基本一致,只是加密解密的形式不一样。代码就不做了,逻辑如下: