第一部分介绍加密解密算法,
第二部分介绍我小组成功应用的RSA、MD5两种加密解密算法,以及心得体会。
1、加密解密算法介绍
应用的开发中安全很重要,所以信息加密技术显得尤为重要。我们需要对应用中的多项数据进行加密处理,从而来保证应用上线后的安全性,给用户一个安全保障。我们组主要对一下三种常见的加密方式进行介绍。
1.1对称加密
简介:需要对加密和解密使用相同密钥的加密算法。由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。对称性加密也称为密钥加密。所谓对称,就是采用这种加密方法的双方使用方式用同样的密钥进行加密和解密。
加密解密过程:明文->密钥加密->密文,密文->密钥解密->明文。
示例:
密钥:X
加密算法:每个字符+X
明文:Hello
密钥为 1时加密结果:Ifmmp
密钥为 2时加密结果:Jgnnq
优点:算法公开、计算量小、加密速度快、加密效率高。
缺点:在数据传送前,发送方和接收方必须商定好秘钥,然后使双方都能保存好秘钥。其次如果一方的秘钥被泄露,那么加密信息也就不安全了。另外,每对用户每次使用对称加密算法时,都需要使用其他人不知道的独一秘钥,这会使得收、发双方所拥有的钥匙数量巨大,密钥管理成为双方的负担。
经典加密算法有三种:
- DES:数据加密标准(现在用的比较少,因为它的加密强度不够,能够暴力破解)
- 3DES:原理和DES几乎是一样的,只是使用3个密钥,对相同的数据执行三次加密,增强加密强度。(缺点:要维护3个密钥,大大增加了维护成本)
- AES:高级加密标准,目前美国国家安全局使用的,苹果的钥匙串访问采用的就AES加密。是现在公认的最安全的加密方式,是对称密钥加密中最流行的算法。
加密模式:
ECB:电子密码本,就是每个块都是独立加密
CBC:密码块链,使用一个密钥和一个初始化向量(IV)对数据执行加密转换
只要是对称加密都有 ECB和 CBC模式,加密模式是加密过程对独立数据块的处理。对于较长的明文进行加密需要进行分块加密,在实际开发中,推荐使用CBC的,ECB的要少用。
1.2非对称加密
简介:
- 对称加密算法又称现代加密算法。
- 非对称加密是计算机通信安全的基石,保证了加密数据不会被破解。
- 非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密(privatekey)
- 公开密钥和私有密钥是一对
如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密。
如果用私有密钥对数据进行加密,只有用对应的公开密钥才能解密。
常用算法:RSA、DSA(数字签名算法)、ECDSA(椭圆曲线签名算法)
特点:
算法强度复杂,安全性依赖于算法与密钥。
加密解密速度慢。
与对称加密算法的对比:
对称加密只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。
非对称加密有两种密钥,其中一个是公开的。
应用场景:
一、非对称算法在手机短信传输中的使用
二、非对称算法在视频会议中的使用
1.3哈希HASH
MD5加密的特点:
1、不可逆运算
2、对不同的数据加密的结果是定长的32位字符(不管文件多大都一样)
3、对相同的数据加密,得到的结果是一样的(也就是复制)。
4、抗修改性 : 信息“指纹”,对原数据进行任何改动,哪怕只修改一个字节,所得到的 MD5 值都有很大区别.
5、弱抗碰撞 : 已知原数据和其 MD5 值,想找到一个具有相同 MD5 值的数据(即伪造数据)是非常困难的.
6、强抗碰撞: 想找到两个不同数据,使他们具有相同的 MD5 值,是非常困难的
MD5 应用:
一致性验证:MD5将整个文件当做一个大文本信息,通过不可逆的字符串变换算法,产生一个唯一的MD5信息摘要,就像每个人都有自己独一无二的指纹,MD5对任何文件产生一个独一无二的数字指纹。
加“盐”操作
“盐”就是一串比较复杂的字符串。加盐的目的是加强加密的复杂度,这么破解起来就更加麻烦,当然这个“盐”越长越复杂,加密后破解起来就越麻烦。
2、加密解密应用于实训项目
我小组实现了MD5加密解密、java非对称加密RSA和js非对称加密三种方式。本文档主要对RSA非对称加密方式进行详细介绍,对MD5进行简单介绍。
1、首先介绍java非对称RSA加密方式,后端加密。(含操作截图)
代码如下所示(代码来自老师学习通提供链接,稍作调试即可)
package com.atguigu.Util;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
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;
public class RSAEncrypt {
private static Map<Integer, String> keyMap = new HashMap<Integer, String>(); //用于封装随机产生的公钥与私钥
public static String R(String plainText) throws Exception {
genKeyPair();
String messageEn = encrypt(plainText,keyMap.get(0));
return messageEn;
}
public static String RR(String plainText) throws Exception {
//genKeyPair();
String messageEn = decrypt(plainText,keyMap.get(1));
return messageEn;
}
public static void main(String[] args) throws Exception {
//生成公钥和私钥
genKeyPair();
//加密字符串
String message = "123";
System.out.println("随机生成的公钥为:" + keyMap.get(0));
System.out.println("随机生成的私钥为:" + keyMap.get(1));
String messageEn = encrypt(message,keyMap.get(0));
System.out.println(message + "\t加密后的字符串为:" + messageEn);
String messageDe = decrypt(messageEn,keyMap.get(1));
System.out.println("还原后的字符串为:" + messageDe);
}
RSAEncrypt(String me) throws Exception{
String messageEn = encrypt(me,keyMap.get(0));
}
/**
* 随机生成密钥对
* @throws NoSuchAlgorithmException
*/
public static void genKeyPair() throws NoSuchAlgorithmException {
// KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(1024,new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); // 得到私钥
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); // 得到公钥
String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
// 得到私钥字符串
String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));
// 将公钥和私钥保存到Map
keyMap.put(0,publicKeyString); //0表示公钥
keyMap.put(1,privateKeyString); //1表示私钥
}
public static String encrypt( String str, String publicKey ) throws Exception{
//base64编码的公钥
byte[] decoded = Base64.decodeBase64(publicKey);
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
//RSA加密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
return outStr;
}
/**
* RSA私钥解密
* @param str
* 加密字符串
* @param privateKey
* 私钥
* @return 铭文
* @throws Exception
* 解密过程中的异常信息
*/
public static String decrypt(String str, String privateKey) throws Exception{
//64位解码加密后的字符串
byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
//base64编码的私钥
byte[] decoded = Base64.decodeBase64(privateKey);
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
//RSA解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
String outStr = new String(cipher.doFinal(inputByte));
return outStr;}}
在controller进行调用,如图所示。
代码:yuangong.setPwd(RSAEncrypt.R(yuangong.getPwd()));
此时实现了RSA加密方式,下面介绍RSA解密,如图所示。
代码:String s=RSAEncrypt.RR(yuangong.getPwd());
此时实现了RSA解密方式。下面进行功能演示。
首先进行车主注册,选中车主,点击注册。
输入车主信息,点击确认注册。
提示注册成功
到数据库中进行查看,如图所示,数据已经成功添加到数据库,且密码已经加密。
小提示 RAS加密方式生成字符串较长,设计表时,pwd对应类型应该设置较大,否则会报错,我设置的是255。
如图所示,对应密码是1234,加密后字符串较长,实现安全加密功能。
下面展示车主登录。此时需要前面步骤的车牌和密码,向上查找即可,如图所示进行登录。
如下如所示,成功登录(箭头所示)
至此,完成了RSA加密解密功能,展示了代码以及功能使用。
以上是在后端进行加密,实际上这样做是很不安全的,所以需要进行改进,于是我组在前端JS中进行加密。
下图为RSA加密解密的时序图
1、创建RSA加密js文档(代码较长,仅展示部分,见附件)
调用加密函数代码如下所示(login.jsp)
function liu(){
//公钥
var PUBLIC_KEY ="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8HMr2CBpoZPm3t9tCVlrKtTmI4jNJc7/HhxjIEiDjC8czP4PV+44LjXvLYcSV0fwi6nE4LH2c5PBPEnPfqp0g8TZeX+bYGvd70cXee9d8wHgBqi4k0J0X33c0ZnW7JruftPyvJo9OelYSofBXQTcwI+3uIl/YvrgQRv6A5mW01QIDAQAB";
//使用公钥加密
var encrypt = new JSEncrypt();
encrypt.setPublicKey('-----BEGIN PUBLIC KEY-----' + PUBLIC_KEY + '-----END PUBLIC KEY-----');
var encrypted = encrypt.encrypt(t.value);
t.value=encrypted;
}
其中私钥和公钥,存储在Info.xml文件里,(Info.xml文件放在login.jsp通一个文件目录下)
通过使用document.getElementById(“password”)语句来获取到登录框中的密码并且进行加密操作。登录界面如下:
登录的解密操作,利用前面java写好的RR()解密函数对前端传过来的password进行解密。
@RequestMapping(value="/adminlogin.action",method=RequestMethod.POST)
@ResponseBody
public ModelAndView getLogin(HttpServletRequest request) throws Exception{
ModelAndView model = new ModelAndView();
int role = Integer.parseInt(request.getParameter("role"));
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(password);
password =RSAEncrypt.RR(password);
登录验证,通过对数据库中的pwd保存的密码进行解密并且与上述解密后的字符串进行对比来实现登录验证。
public boolean checkUserAndPsw(String teacherID,String password) throws Exception {
// TODO Auto-generated method stub
Teacher teacher=teacherMapper.selectByPrimaryKey(teacherID);
if(teacher==null)
return false;
else
{
String s=RSAEncrypt.RR(teacher.getPassword());
if(s.compareTo(password)==0)
{
return true;
}
else
return false;
}
}
心得体会:要学会如何进行代码调试,网上的代码大部分无法直接应用,贴到ssm里面总是不能完成加密功能,我们因此也进行了很多努力,包括通过观看网上的视频资源、向老师求助。我们进行代码调试修改,才可以完成加密解密功能。另外我小组一开始完成的是MD5加密解密算法,因为此算法较为基础,所以之后又进行了RSA加密解密算法的应用,终于得以成功,下面本文档对MD5进行简单介绍。
2、介绍MD5如何进行使用并且成功运行。
附上链接https://www.likecs.com/show-415759.html
使用java自带jar工具MessageDigest实现。
(1)首先新建一个MD5Util方法,粘贴调试过的代码,如下所示。
package com.atguigu.Util;
import java.math.BigInteger;
import org.apache.commons.codec.binary.Base64;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Util {
public static String md5(String plainText) {
byte[] secretBytes = null;
try {
secretBytes = MessageDigest.getInstance("md5").digest(
plainText.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
public static String decode(byte[] bytes) {
return new String(Base64.decodeBase64(bytes));
}
public static String encode(byte[] bytes) {
return new String(Base64.encodeBase64(bytes));
}
}
(2)在USerController.Java中调用函数。(你对应的controller层进行)
如图中标记的一段代码。
运行效果图展示
此时进行登录系统管理员,账号为1102 密码为789可进行登录
此时成功进行登录