Hash概述
Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数
hash的特点
- 算法是公开的
- 对相同数据的运算,得到的结果是一样的
- 对不同的数据运算,如md5(一种hash,类似的还有sha1,sha256)得到的结果默认是128位二进制,128二进制一般不好识别所以一般显示为32位的十六进制(1位十六进制数就可以表示4位二进制数)
- hash算法无法逆运算
- 信息摘要,信息指纹,信息身份证,是用来做数据识别的
hash的用途
- 用户的密码加密
- 搜索引擎
- 版权
- 数字签名
hash用于用户的密码加密
网络上一般是不会传输用户的密码明文数据的,否则当用户的账号密码泄露之后,是会被追究法律责任的;现在市面上为什么没有找回密码的功能,就是因为用户的密码并不是以明文的形式保存在服务器上的;
我们先使用最简单方式,来对用户的密码进行加密处理:(本文基于iOS平台,使用到的第三方可以在这下载)
-
直接对密码进行MD5
可以使用终端来验证一下上面加密的结果是否正确,终端命令如下:
md5 -s "123456"
可以看到加密的结果是一致的;但是有一些网站,它专门记录了常用的密码对应的md5值,比如:www.cmd5.com;这样我们常用的密码,即使使用了md5加密,要破解出来也是太简单了…有什么更好的加密办法呢? -
MD5 + 盐(一段任意的字符串)
这样加密出来的结果,会比上面单纯的使用MD5会好一点,但是这个盐一旦泄露之后,要破解出密码来也是轻而易举,上面的那个网站依然可以很好的查询出来
-
HMAC加密方案
以用户注册为例,当用户把输入完账号的时候,现在很多APP或者网站都会让用户去检测账号的合法性,服务器验证合法就会生成这个账号对应的key,并发送给客户端;客户端将服务器返回的key记录在本地,并跟用户输入的密码进行一次hmac加密,将加密的结果发送给服务器记录并保存;这样就算是注册成功了!当用户下次登录的时候,客户端查找本地的账号对应的key,和用户输入的密码进行hmac运算之后,发送给服务器验证;这样相比较于上面的仅仅加盐的方式,安全性又高了一些;
在用户更换设备进行登录的时候,此时客户端没有账号对应的key了,那就需要在输入完账号密码登录的时候,先去请求服务器获取key值;服务器收到这个请求之后,可以查询当前账号是否开启了设备锁,如果开了设备锁,那么就去询问有key值的设备是否允许当前设备登录,不同意那么新设备就自然登录失败;同意的话,就将账号对应的key值返回给请求的设备,这样用户在新设备上进行登录所需的key也有了,再与密码进行hmac后发送给服务器验证登录;是不是在QQ,微信之类有设备锁的APP上见过 -
HMAC + 时间戳
使用上述的hmac加密方案之后,密码的安全性确实高了不少;但是还可以在安全一点,那就是再加上时间戳;在用户输入账号密码,点击登录之后,用生成的hmac密码,再拼接上一个到分钟的当前时间,比如202106120112,再进行一次MD5加密得到的结果发送给服务器;此时服务器也会用已经存起来的hmac密码拼接当前分钟的时间戳,进行一次MD5,和客户端发送过来的结果进行匹配,如果一致则登录成功;如果不一致,那么就使用上一分钟的时间戳,再进行一次MD5,再匹配客户端发送过来的结果(为什么再试一次上一分钟,因为有可能在发送的过程中,时间加了一分钟);这样用户登录的时候,密码的时效最多只有2分钟,过了这2分钟,密码又不一样了…黑客会很懵逼
hash用于搜索引擎
主要是用于拆词搜索,每个词语进行hash运算后的结果都是一样的,比如上海,iOS,程序员在百度上搜索,不论怎么样排列这三个词语,可能都会搜到同一条新闻,就是因为这三个词对应的hash值相加之后的结果,不论这三个词怎么排列,都是一样的;
hash用于版权
百度云上传电影的时候,有些电影会有秒传的功能;就是比对hash值是一样的,再比对一些额外的信息,就可以确定是同一部电影了,就不需要重复上传了;
视频网站YouTube之类的,会对用户上传的视频文件进行hash并记录,这样用户上传每个视频都有了一个身份证类似的id了
hash用户数字签名
什么是数字签名?老外喜欢用签名,刷信用卡消费之后有一个账单,需要信用卡持卡人签名确认;签名的目的就是表示被签名的东西是属于签名人的;数字签名的意思就是对一串二进制数据进行签名,用于确认是谁的二进制数据
举个例子:你在网上购买了一件100元的商品,你的消费信息发送给服务器,服务器收到了你的消费信息后,在你的账户下面扣除100元,然后把扣款结果返回给用户,这个世界本来是这么简单的;但是中间如果有不怀好意的黑客,他篡改了你发送给服务器的消费信息,改为你消费了1000元,然后服务器收到这条消息后,在你的账户里扣除了1000元,并将扣款结果返回,这个时候黑客再将服务器返回给你的扣款信息篡改,告诉你成功消费100元,大家都没察觉出什么问题,回过头你发现你不翼而飞了900元…所以服务器需要确认消费信息是由你发出的而且是没有经过第三方篡改的消费信息,怎么做到呢?
首先使用hash将消费信息进行加密得到一个128位的结果,然后使用RSA的公钥对结果进行加密,然后将消费信息,RSA公钥加密的消费信息hash值全发送给服务器,服务器收到结果后,使用RSA的私钥解密得到一个消费信息的hash值,再使用收到的消费信息进行一次hash加密,比较两个hash值是都相同,相同就代表消费信息没有被第三方修改,不相同就代表消费信息被修改过了;这里面被RSA加密的消费信息的hash值就叫作数字签名
对称加密算法
简介
对称加密(也叫私钥加密)指加密和解密使用相同密钥的加密算法。有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,同时解密密钥也可以从加密密钥中推算出来。而在大多数的对称算法中,加密密钥和解密密钥是相同的,所以也称这种加密算法为秘密密钥算法或单密钥算法。它要求发送方和接收方在安全通信之前,商定一个密钥。对称算法的安全性依赖于密钥,泄漏密钥就意味着任何人都可以对他们发送或接收的消息解密,所以密钥的保密性对通信的安全性至关重要。
特点
对称加密算法的特点是算法公开、计算量小、加密速度快、加密效率高。
常见的对称加密算法
DES
数据加密标准,现在用的少,因为强度低
3DES
使用3个密钥,对相同的数据执行三次加密
AES
高级加密标准,包括苹果的钥匙串访问,美国国家安全局都在使用的加密方式
应用模式
ECB:(Electronic Code Book),电子密码本模式,每一块数据独立加密;最基本的加密模式,也就是通常理解的加密,相同的明文将永远加密成相同的密文,无初始向量,容易受到密码本重放攻击,一般情况下很少用。
CBC:(Cipher Block Chainning),密码分组链接模式;明文被加密前要与前面的密文进行异或运算后再加密,因此只要选择不同的初始向量,相同的密文加密后会形成不同的密文,这是目前应用最广泛的模式。CBC加密后的密文是上下文相关的,但明文的错误不会传递到后续分组,但如果一个分组丢失,后面的分组将全部作废(同步错误)。CBC可以有效的保证秘闻的完整性,如果一个数据块在传递时丢失或者改变,后面的数据将无法正常解密。
还有一些模式,但不是很常见,比如Cipher Feedback Mode(CFB)加密反馈模式,Output Feedback Mode(OFB)输出反馈模式
对称加密的终端演练
明文message.txt内容如下:
使用DES算法ECB模式加密,key为abc:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg1.bin
将明文中的某个数字修改一下
再使用同样的加密方式,生成第二份密文msg2.bin:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg2.bin
对比一下生成的两份密文msg1.bin和msg2.bin,发现明文就只是改动了一个数字,对应的密文是一整块都修改了,这也形象的表示了ECB模式的原理
然后我们试一下CBC模式:
openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg3.bin
将明文内容修改回最初的样子后再使用CBC模式生成msg4.bin文件
openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg4.bin
对比msg3.bin和msg4.bin发现,CBC模式下改动了一处后,后面的整体都发生了改变,两次对比很形象的说明了ECB模式和CBC模式的区别
对称加密的代码演练
使用AES算法,ECB模式进行加密
再用终端来验证一下结果:echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
使用AES算法,CBC模式进行加密
终端验证结果:echo -n hello | openssl enc -aes-128-cbc -K 616263 -nosalt -iv 0102030405060708 | base64
终端验证解密结果:echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -K 616263 -iv 0102030405060708 -nosalt -d
[EncryptionTools sharedEncryptionTools]
单例默认使用的就是AES算法,如果想使用其他的算法,可以自行指定[EncryptionTools sharedEncryptionTools].algorithm = <#CCAlgorithm#>
iOS中对称加密底层函数CCCrypt()
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
复制代码
参数1: kCCEncrypt 代表加密,kCCDecrypt 代表解密
参数2: 加密算法,AES,DES…
参数3: 加密模式:ECB,CBC…
参数4: 加密所需的密钥
参数5: 密钥的长度
参数6: iv 初始化向量(如果是CBC模式需要传入,ECB不需要)
参数7: 加密的数据,也就是明文
参数8: 加密的数据的长度,明文的长度
参数9: 密文的内存地址
参数10: 密文缓冲区的大小
参数11: 加密结果的大小
在iOS中,使用对称加密的最终都会走到这个函数,如果有人对你开发的APP有些想法,就会调试你的应用,对这个CCCrypt下一个符号断点,就可以拿到这个函数的所有参数信息了,那用户的明文密码就泄露无疑了…
寄存器读这个函数的第七个参数就是register read x6
(x0是第一个)明文数据