1 背景
最近在一个项目中遇到这样一种情况,服务器(JAVA)后台需要校验用户名和密码,采用的方式是md5(base64)的加密方式,例如:将字符串"zhangsan:123456"采用md5(base64)加密,目标结果如下
md5(base64)实际上就是将String型的字符串先经过md5摘要加密,得到byte[]型的数据,再将byte[]型的数据以base64的编码输出。其JAVA实现方式如下:
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import sun.misc.BASE64Encoder;
import java.security.MessageDigest;
public class java_md5_base64 {
public static String md5_base64(String data) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(data.getBytes());
byte[] pass = md.digest();
BASE64Encoder encoder = new BASE64Encoder();
String encryData = encoder.encode(pass);
return encryData;
}
}
现在客户端要用C++的方式来实现,乍一看md5(base64)无非就是先md5加密再base64编码输出嘛,很简单,算法网上都有,直接参考。可结果咋总不对呢?原因是忽略了一个细节,“md5摘要加密,得到byte[]型的数据”,而不是字符串。网上诸多在线md5加密工具,或者是md5加密算法源码,得到的是字符串,而且有16位、32位、大写小写之分,再进行base64编码,固然与目标结果千差万别。
- 16位小写Base64编码:ODJhYjI5NGVhNjE5ZDJmNQ==
- 16位大写Base64编码:ODJBQjI5NEVBNjE5RDJGNQ==
- 32位小写Base64编码:NGNhOGFlZTE4MmFiMjk0ZWE2MTlkMmY1YTAyNTdjZDk=
- 32位大写Base64编码:NENBOEFFRTE4MkFCMjk0RUE2MTlEMkY1QTAyNTdDRDk=
在这里,为简化操作本文直接采用强大的OpenSSL库来实现。
2 VC++使用OpenSSL库
2.1 OpenSSL库下载安装
从http://slproweb.com/products/Win32OpenSSL.html下载Win32 OpenSSL v1.1.1,并安装,这里直接默认安装路径为C:\Program Files (x86)\OpenSSL-Win32。
2.2 VS加入OpenSSL库
工程目录新建文件夹openssl,openssl下新建目录include和lib目录。
将lib\VC下的库文件拷贝到工程目录openssl\lib。
将include\openssl下的所有头文件拷贝到工程目录openssl\include。
将bin下的libcrypto-1_1.dll拷贝到工程运行程序下。
库文件和头文件添加到工程源码这里就不做赘述了,直接上码。
2.3 md5(base64)加密字符串
包含OpenSSL头文件
#include "md5.h"
#include "evp.h"
#include "bio.h"
#include "buffer.h"
base64编码
std::string base64Encode(const char * input, int length, bool with_new_line)
{
BIO * bmem = NULL;
BIO * b64 = NULL;
BUF_MEM * bptr = NULL;
b64 = BIO_new(BIO_f_base64());
if(!with_new_line) {
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
}
bmem = BIO_new(BIO_s_mem());
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
char * buff = (char *)malloc(bptr->length + 1);
memcpy(buff, bptr->data, bptr->length);
buff[bptr->length] = 0;
BIO_free_all(b64);
return buff;
}
md5(base64)加密
void md5Base64(std::string &str)
{
std::string md5Str;
md5Str.clear();
MD5_CTX ctx;
unsigned char md[MD5_DIGEST_LENGTH];
memset(&ctx,0,sizeof(MD5_CTX));
memset(md,0,sizeof(md));
MD5_Init(&ctx);
MD5_Update(&ctx,str.c_str(),str.size());
MD5_Final(md,&ctx);
md5Str = (char*)md;
str = base64Encode(md5Str.c_str(), md5Str.size(), false);
}