MD5
什么是MD5
- 全称是Message Digest Algorithm 5,译为“消息摘要算法第5版”
- 效果:对输入信息生成唯一的128位散列值(32个字符)
MD5的特点
- 输入两个不同的明文不会得到相同的输出值
- 根据输出值,不能得到原始的明文,即其过程不可逆
MD5的应用
- 由于MD5加密算法具有较好的安全性,而且免费,因此该加密算法被广泛使用
- 主要运用在数字签名、文件完整性验证以及口令加密等方面
- MD5广泛用于加密和解密技术上,在很多操作系统中,用户的密码是以MD5值(或类似的其它算法)的方式保存的,用户Login的时候,系统是把用户输入的密码计算成MD5值,然后再去和系统中保存的MD5值进行比较,来验证该用户的合法性。
MD5解密网站:http://www.cmd5.com 记录超过24万亿条,共占用160T硬盘 的密码数据,通过对海量数据的搜索得到的结果!
提升MD5加密安全性,有两个解决办法
1.加"盐"(即对密码进行加盐后加密,加密后再通过Hibernate往数据库里存)
所谓加盐
例如:两个人或多个人的密码相同,通过md5加密后保存会得到相同的结果。破一个就可以破一片的密码。
如果名为李自成的用户可以查看数据库,那么他可以观察到自己的密码和别人的密码加密后的结果都是一样,那么,别人用的和自己就是同一个密码,这样,就可以利用别人的身份登录了。
那么我们以前的加密方法是否对这种行为失效了呢?其实只要稍微混淆一下就能防范住了,这在加密术语中称为“加盐”。具体来说就是在原有材料(用户自定义密码)中加入其它成分(一般是用户自有且不变的因素),以此来增加系统复杂度。当这种盐和用户密码相结合后,再通过摘要处理,就能得到隐蔽性更强的摘要值。下面请见代码:
// 对密码进行加盐后加密,加密后再通过Hibernate往数据库里存
String changedPswd=DigestUtils.md5Hex(name+pswd);
就是这样简单,上面代码中盐就是用户名,可以的话还可以用用户注册时的邮件,注册时间等非空信息(如果是空信息这个加盐处理会失效)。
下面是数据库中两个用户的记录,他们的实际登录密码都是123456,但光看用户记录是完全看不出来的。这下别有用心的人打开数据库看到的密码都完全不一样,他以前的手段就失效了。
因为密码是md5处理的密码加用户名,因为用户名都不相同,所以即使密码相同的用户,保存到数据库中密码也是不同的。
2.HMAC:给定一个"秘钥",对明文进行加密,并且做"两次散列"!-> 得到的结果,还是 32 个字符
MD5算法和DES算法是常见的两种加密算法。
MD5:MD5是一种不可逆的加密算法,按我的理解,所谓不可逆,就是不能解密,那么它有什么用的,它的用处大了,大多数的登录功能都会使用到这种算法。后面根据我的项目经验来介绍。
DES:一种使用密钥加密的块算法,所以,使用它加密时,需要一个密钥,加上一些设置和你需要加密的文段。
在IOS中,使用这两种加密算法非常简单,系统的
1、客户端向服务端请求密钥,请求的参数是双方约定好的一个MD5加密的字符串。我们可以通过下面的进行第一步加密:
- (NSString *)MD5Digest
{
//要进行UTF8的转码
const char* input = [self UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(input, (CC_LONG)strlen(input), result);
NSMutableString *digest = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[digest appendFormat:@"%02x", result[i]];
}
return digest;
}
通过这样的方法,我们可以很容易的得到一串MD5加密字符串,但是一定要和后台约定好,MD5加密的位数是16位还是32位,用上述方法加密出来的时32位,当然他们之间是有联系的,通过下面的方法可以将其转成16为:
+(NSString *)trransFromMD532ToMD516:(NSString *)MD532{
NSString * string;
for (int i=0; i<24; i++) {
string=[MD532 substringWithRange:NSMakeRange(8, 16)];
}
return string;
}
还有一点需要注意,加密后的大小写也要对应。
2、服务端将得到的MD5串和以约定好的MD5串进行对比,如果一致,可以放行,返回密钥。
3、客户端取到密钥,将密钥再进行一次MD5加密,然后通过DES将要传送的数据加密发给服务器。
这一步至关重要,我们先看DES的加密代码
+(NSString *) encryptUseDES:(NSString *)clearText key:(NSString *)key andiv:(NSString *)iv
{
//这个iv 是DES加密的初始化向量,可以用和密钥一样的MD5字符
NSData * date = [iv dataUsingEncoding:NSUTF8StringEncoding];
NSString *ciphertext = nil;
NSUInteger dataLength = [clearText length];
NSData *textData = [clearText dataUsingEncoding:NSUTF8StringEncoding];
unsigned char buffer[1024];
memset(buffer, 0, sizeof(char));
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,//加密模式 kCCDecrypt 代表解密
kCCAlgorithmDES,//加密方式
kCCOptionPKCS7Padding,//填充算法
[key UTF8String], //密钥字符串
kCCKeySizeDES,//加密位数
[date bytes],//初始化向量
[textData bytes] ,
dataLength,
buffer, 1024,
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
NSLog(@"DES加密成功");
NSData *data = [NSData dataWithBytes:buffer length:(NSUInteger)numBytesEncrypted];
Byte* bb = (Byte*)[data bytes];
ciphertext = [Base64 parseByteArray2HexString:bb];
}else{
NSLog(@"DES加密失败");
}
return ciphertext;
}
几点注意:
(1)加密方式,IOS官方提供的是如下几种
enum {
kCCAlgorithmAES128 = 0,
kCCAlgorithmAES = 0,
kCCAlgorithmDES,
kCCAlgorithm3DES,
kCCAlgorithmCAST,
kCCAlgorithmRC4,
kCCAlgorithmRC2,
kCCAlgorithmBlowfish
};
(2)填充算法
enum {
/* options for block ciphers */
kCCOptionPKCS7Padding = 0x0001,
kCCOptionECBMode = 0x0002
/* stream ciphers currently have no options */
};
我们可以发现,官方提供的只有这两种,然而JAVA使用的却是kCCOptionPKCS7Padding
但是不用担心,在密钥是8位的时候,这两种填充算法加密出来的结果试一模一样的。
4、服务器通过相同的方式,解密出密文,通配安卓端。