MD5,全称为Message-Digest Algorithm 5,是一种广泛使用的加密哈希函数,由美国计算机科学家罗纳德·李维斯特(Ronald Linn Rivest)在1991年或1992年(不同来源有不同年份)设计并发布。MD5的主要作用是将任意长度的数据(如文本、文件等)通过一系列复杂的运算,生成一个128位(16字节)的哈希值(也称为散列值或杂凑值),这个哈希值通常用于确保信息传输的完整性和一致性。
MD5的工作原理
- 输入处理:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组。如果输入信息的长度不是512的倍数,则需要进行填充,填充方法是添加一个1和若干个0,直到长度对512求余的结果等于448,然后再用64位内存来存储填充前信息的长度。
- 循环运算:对每一分组进行四轮变换,每轮变换都基于特定的线性函数和位运算,最终输出由四个32位分组组成的128位散列值。
MD5的应用场景
- 文件完整性验证:在文件传输或存储过程中,发送方使用MD5对文件进行散列计算,并将生成的哈希值与文件一同发送给接收方。接收方再对收到的文件进行同样的MD5计算,比较两个哈希值是否相同,从而判断文件在传输过程中是否被篡改。
- 身份认证:通过预先为每个文件或数据块计算MD5摘要,并将其与文件或数据块一同存储或传输。在需要验证身份时,只需比较计算出的MD5摘要是否与预先存储的摘要相同,即可判断数据来源是否合法。
- 密码存储:尽管MD5在密码存储方面存在安全隐患(如碰撞现象),但在过去,许多系统会将用户的密码进行MD5散列后存储在数据库中,以防止直接看到明文密码。然而,随着密码学的发展,这种做法已经被更安全的加密算法所取代。
MD5的优缺点
优点:
- 计算速度快,加密速度快,不需要密钥。
- 可以有效地检查文件的完整性,防止文件被篡改。
- 具有一定的抗碰撞性,虽然存在碰撞现象,但在实际应用中仍然具有较高的可靠性。
缺点:
- 存在碰撞现象,即不同输入可能生成相同的哈希值。这意味着在某些情况下,MD5可能无法提供足够的安全性。
- 安全性较低,不适合直接用于密码存储等需要高安全性的场景。
综上所述,MD5作为一种经典的哈希函数,在文件完整性验证和身份认证等方面具有广泛的应用。然而,在追求更高安全性的今天,MD5已经逐渐被更安全的加密算法所取代。
代码演示
public class MD5Util {
/** MD5 */
private static final String hexDigIts[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
/** MD5加密 */
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (null == charsetname || "".equals(charsetname)) {
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
} else {
resultString = byteArrayToHexString(md.digest(resultString
.getBytes(charsetname)));
}
} catch (Exception e) {
}
return resultString;
}
public static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
public static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigIts[d1] + hexDigIts[d2];
}
}
在使用时会将密码进行加密以防止被人入侵,同时在用户想要进入主页面进行登录时,我们也需要将用户写入的密码进行加密与事先存入的加密密码进行比较,从而确保用户的安全。下面是注册和登录代码演示:
//注册功能
@WebServlet("/register")
public class RegisterServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String parameter = req.getParameter("confirm-password");
String md5 = MD5Util.MD5Encode(password,"UTF-8");
ConnDB connDB=new ConnDB();
if (parameter.equals(password)){
Connection connection = connDB.getConnection();
String sql1="select * from user where name='"+username+"' and password='"+md5+"'";
try {
ResultSet set = connDB.executeQuery(sql1);
if (!set.next()){
String sql="insert into user(name,password) values (?,?)";
try {
PreparedStatement pre = connection.prepareStatement(sql);
pre.setString(1,username);
pre.setString(2,md5);
pre.executeUpdate();
req.getRequestDispatcher("login.jsp").forward(req,resp);
} catch (SQLException e) {
e.printStackTrace();
}
}
else {
req.setAttribute("msg","当前用户已存在,请返回到登录页面进行登录");
req.getRequestDispatcher("register.jsp").forward(req,resp);
}
} catch (Exception e) {
e.printStackTrace();
}
}else {
req.setAttribute("msg","密码不一致!");
req.getRequestDispatcher("register.jsp").forward(req,resp);
}
try {
connDB.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//登录功能 其中还有验证码的内容 下一期将验证码的代码发布给大家
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String auto = req.getParameter("auto");
ConnDB connDB=new ConnDB();
connDB.getConnection();
String md5 = MD5Util.MD5Encode(password,"UTF-8");
String sql="select * from user where name='"+username+"'and password='"+md5+"'";
String userInputCaptcha = req.getParameter("captcha");
// 从Session中获取真正的验证码
HttpSession session = req.getSession();
String realCaptcha = (String) session.getAttribute("captcha");
// 比较用户输入的验证码和真正的验证码是否一致
// 设置响应类型为JSON
if (userInputCaptcha != null && userInputCaptcha.equalsIgnoreCase(realCaptcha)) {
try {
ResultSet set = connDB.executeQuery(sql);
if (set.next()){
User user= new User();
user.setId(set.getInt(1));
user.setUserName(set.getString(2));
user.setPassword(set.getString(3));
session.setAttribute("user",user);
Cookie cookie =new Cookie("ucookie",username);
//将String类型准换成int类型
if (auto!=null){
cookie.setMaxAge(Integer.parseInt(auto)*60*60);
}else {
cookie.setMaxAge(0);
}
resp.addCookie(cookie);
req.setAttribute("name",user.getUserName());
req.getRequestDispatcher("index").forward(req,resp);
}else {
req.setAttribute("msg","用户名或密码错误");
req.getRequestDispatcher("login.jsp").forward(req,resp);
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
req.getRequestDispatcher("login.jsp").forward(req,resp);
}
//out.write(json);
try {
connDB.close();
} catch (Exception e) {
e.printStackTrace();
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 创建验证码图片并返回图片上的文本
String captchaText = CaptchaUtils.createCaptchaImage(response);
// 将验证码文本保存到Session中
HttpSession session = request.getSession();
session.setAttribute("captcha", captchaText);
}
}
总之 MD5只是能保护用户的一种方法,还有很多比它更优秀的方法,等待我们去发现,既然看到这里了,不妨给我个关注支持一下吧!!