密码学

·  阅读 481
密码学

密码学概述

密码学是研究编制密码和破译密码的技术科学。研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学;应用于破译密码以获取通信情报的,称为破译学,总称密码学。

密码学的历史大致可以追溯到两千年前,相传古罗马名将凯撒大帝为了防止敌方截获情报,用密码传送情报。凯撒的做法很简单,就是对二十几个罗马字母建立一张对应表。这样,如果不知道密码本,即使截获一段信息也看不懂。

image11.png

从凯撒大帝时代到上世纪70年代这段很长的时间里,密码学的发展非常的缓慢,因为设计者基本上靠经验。没有运用数学原理。

在1976年以前,所有的加密方法都是同一种模式:加密、解密使用同一种算法。在交互数据的时候,彼此通信的双方就必须将规则告诉对方,否则没法解密。那么加密和解密的规则(简称密钥),它保护就显得尤其重要。传递密钥就成为了最大的隐患。这种加密方式被成为对称加密算法(symmetric encryption algorithm)

1976年,两位美国计算机学家 迪菲(W.Diffie)、赫尔曼( M.Hellman ) 提出了一种崭新构思,可以在不直接传递密钥的情况下,完成密钥交换。这被称为“迪菲赫尔曼密钥交换”算法。开创了密码学研究的新方向,非对称加密算法(asymmetric cryptographic algorithm)

RSA概述

1977年三位麻省理工学院的数学家 罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起设计了一种算法,可以实现非对称加密。这个算法用他们三个人的名字命名,叫做RSA算法。

RSA的数学原理

离散对数问题

如果让你设计一个加密容易,破解很难的算法,会想到什么呢? 方案:3xmod17=123^x \mod 17 = 12,问x是多少? x可能的值为x=16k + 13,k为正整数,这样的x有多个,根本没法确定是哪个

迪菲赫尔曼密钥交换

image.png

欧拉函数

对正整数n,在小于n的正整数之中,与n构成互质关系的数有多少个? 对这个问题的首位研究者叫作欧拉,是一个神一样的厉害人物,所以把对这个问题的解答称作欧拉函数,用φ(n)来表示

如φ(8)表示计算8的欧拉函数,和8互质的数有,1,3,5,7所以φ(8) = 4; 如φ(7)表示计算7的欧拉函数,有1,2,3,4,5,6所以φ(7) = 6;

欧拉对这个问题进行研究之后,得到了欧拉函数的两个性质:

  1. 若n为质数,则φ(n) = n - 1
  2. 若A,B互质,则φ(A * B) = φ(A) * φ(B)

结合以上两条性质可得,若A,B都是质数,则φ(A * B) = φ(A) * φ(B) = (A - 1) * (B - 1)

欧拉定理

如果两个正整数m和n互质,那么m的φ(n)次方减去1,可以被n整除

mφ(n)modn1m^{φ(n)}\mod n \equiv 1

针对上面的欧拉定理,费马又来了个小定理如果两个正整数m和n互质,而且n为质数,那么m的n-1次方减去1,可以被n整除

m(n1)modn1m^{(n - 1)} \mod n \equiv 1

模反元素

如果两个正整数e和x互质,那么一定可以找到整数d,使e * d - 1被x整除,那么d就是e相对于x的模反元素

edmodx1e \ast d \mod x \equiv 1

把欧拉定理和模反元素结合起来推导

因为1 ^ k = 1,所以mφ(n)modn1m^{φ(n)} \mod n \equiv 1 两边同时k次方后得到mkφ(n)modn1m^{kφ(n)} \mod n \equiv 1

因为1 * m = m,所以上式两边同时乘上m后得到mkφ(n)+1modnmm^{kφ(n) + 1} \mod n \equiv m

将模反元素edmodx1e \ast d \mod x \equiv 1变形后得到edkx+1e \ast d \equiv k * x + 1

再结合上述两个式子就可以得到

medmodnmm^{e * d} \mod n \equiv m

其中m,n互质,e与φ(n)互质,满足条件的d一定可以找到,我们可以举几个例子验证一下

令m = 3,n = 17,e = 5,m,n互质,e和φ(17)互质,根据模反元素求的可能的d = 16k+15\frac{16k + 1}{5},k取4的时候,d为13,代入上式中验证3513mod173 ^ {5 * 13} \mod 17结果确定等于3

多试几个m,n之后会发现,只要m < n,上面的等式就一直成立,不再需要互质了...至于为什么,俺也搞不明白,知道就好了,如果有大神知道的,还请不吝赐教

medmodnmm^{e * d} \mod n \equiv m

此时,m<n,e与φ(n)互质,d = kφ(n)+1e\frac{k * φ(n) + 1}{e}

RSA算法说明

其实得到medmodnmm^{e * d} \mod n \equiv m之后,离我们实际使用RSA算法非常接近了,实际使用中memodnCm^e \mod n \equiv C,这个过程叫作加密,再求CdmodnC^d \mod n会发现结果还是m,这个过程叫作解密,其中公钥就是n和e,私钥就是n和d,m代表明文,c代表密文

说明:

  1. n会非常大,长度一般为1024个二进制位。(目前人类已经分解的最大整数,232个十进制位,768个二进制位)
  2. 由于需要求出φ(n),所以根据欧函数特点,最简单的方式n 由两个质数相乘得到: 质数:p1、p2 Φ(n) = (p1 -1) * (p2 - 1)
  3. 最终由φ(n)得到e 和 d

总共生成6个数字:p1、p2、n、φ(n)、e、d,除了公钥用到了n和e其余的4个数字是不公开的,目前皮杰RSA得到d的方式如下:

  1. 要想求出私钥d,由于e * d = k * φ(n) + 1,要知道e和φ(n);
  2. e是公开的,但是要得到φ(n),必须知道p1和p2;
  3. 由于n = p1 * p2,只有将n因数分解才能算出;

RSA的终端演练

Mac电脑的终端可以直接使用OpenSSL进行RSA的命令运行。由于Mac系统内置OpenSSL(开源加密库),所以我们可以直接在终端上使用命令来玩RSA. OpenSSL中RSA算法常用指令主要有三个: image.png

  1. 生成RSA私钥,密钥长度为1024bit:openssl genrsa -out private.pem 1024Snip20210609_1.png

  2. 从私钥中提取公钥:openssl rsa -in private.pem -pubout -out public.pemSnip20210609_2.png可以查看一下公钥和私钥的内容image.png

  3. 还可以使用命令openssl rsa -in private.pem -text -out private.txt将私钥转成文本,并查看里面的内容Snip20210609_6.png

  4. 接下来我们使用公钥对一段文本进行加密:openssl rsautl -encrypt -in message.txt -inkey public.pem -pubin -out enc.txtSnip20210609_7.png可以看到message.txt的内容由密码123456已经变成了一堆乱码,(没使用过vim编辑器的同学也可以直接创建一个txt文件)

  5. 使用私钥进行解密:openssl rsautl -decrypt -in enc.txt -inkey private.pem -out dec.txtSnip20210609_8.png

在macOS中我们是不能直接使用pem文件的,需要使用的der格式和p12格式的文件

  1. 首先需要一个证书请求文件,这个做过iOS开发的同学应该都很熟悉了openssl req -new -key private.pem -out rsacert.csrSnip20210609_9.png

  2. 一般我们配置证书的时候,是使用上面生成的证书请求文件去苹果服务器签名后得到证书,但是现在我们只是演示,就自己签名了:openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crtSnip20210609_10.png

  3. 通过crt文件生成p12文件:openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt设置密码并再次确认之后得到p12文件Snip20210609_11.png

其实在平时日常开发中,证书这些东西,我们iOS开发者直接使用就行了,基本是不会需要我们iOS开发来生成配置

RSA的代码代码演练

在iOS系统中,crt文件也不能直接使用,需要转成der文件,命令如下:
openssl x509 -outform der -in rsacert.crt -out rsacert.derSnip20210609_12.png

  1. 加载公钥和私钥Snip20210609_14.png其中RSACryptor是已经封装好的RSA工具类,有需要的可以自己去下载

  2. 加密hello world并输出加密结果Snip20210609_15.png

  3. 解密过程Snip20210609_16.png

Hash概述

Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入通过散列算法变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数

hash的特点

  1. 算法是公开的
  2. 对相同数据的运算,得到的结果是一样的
  3. 对不同的数据运算,如md5(一种hash,类似的还有sha1,sha256)得到的结果默认是128位二进制,128二进制一般不好识别所以一般显示为32位的十六进制(1位十六进制数就可以表示4位二进制数)
  4. hash算法无法逆运算
  5. 信息摘要,信息指纹,信息身份证,是用来做数据识别的

hash的用途

  1. 用户的密码加密
  2. 搜索引擎
  3. 版权
  4. 数字签名

hash用于用户的密码加密

网络上一般是不会传输用户的密码明文数据的,否则当用户的账号密码泄露之后,是会被追究法律责任的;现在市面上为什么没有找回密码的功能,就是因为用户的密码并不是以明文的形式保存在服务器上的;

我们先使用最简单方式,来对用户的密码进行加密处理:(本文基于iOS平台,使用到的第三方可以在这下载)

  1. 直接对密码进行MD5Snip20210611_4.png可以使用终端来验证一下上面加密的结果是否正确,终端命令如下:md5 -s "123456"Snip20210611_5.png
    可以看到加密的结果是一致的;但是有一些网站,它专门记录了常用的密码对应的md5值,比如:www.cmd5.com;这样我们常用的密码,即使使用了md5加密,要破解出来也是太简单了...有什么更好的加密办法呢?

  2. MD5 + 盐(一段任意的字符串)Snip20210611_6.png这样加密出来的结果,会比上面单纯的使用MD5会好一点,但是这个盐一旦泄露之后,要破解出密码来也是轻而易举,上面的那个网站依然可以很好的查询出来

  3. HMAC加密方案
    以用户注册为例,当用户把输入完账号的时候,现在很多APP或者网站都会让用户去检测账号的合法性,服务器验证合法就会生成这个账号对应的key,并发送给客户端;客户端将服务器返回的key记录在本地,并跟用户输入的密码进行一次hmac加密,将加密的结果发送给服务器记录并保存;这样就算是注册成功了!当用户下次登录的时候,客户端查找本地的账号对应的key,和用户输入的密码进行hmac运算之后,发送给服务器验证;这样相比较于上面的仅仅加盐的方式,安全性又高了一些;
    在用户更换设备进行登录的时候,此时客户端没有账号对应的key了,那就需要在输入完账号密码登录的时候,先去请求服务器获取key值;服务器收到这个请求之后,可以查询当前账号是否开启了设备锁,如果开了设备锁,那么就去询问有key值的设备是否允许当前设备登录,不同意那么新设备就自然登录失败;同意的话,就将账号对应的key值返回给请求的设备,这样用户在新设备上进行登录所需的key也有了,再与密码进行hmac后发送给服务器验证登录;是不是在QQ,微信之类有设备锁的APP上见过

  4. 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内容如下: Snip20210612_7.png

使用DES算法ECB模式加密,key为abc:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg1.binSnip20210612_9.png

将明文中的某个数字修改一下 Snip20210612_10.png

再使用同样的加密方式,生成第二份密文msg2.bin:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg2.bin Snip20210612_11.png

对比一下生成的两份密文msg1.bin和msg2.bin,发现明文就只是改动了一个数字,对应的密文是一整块都修改了,这也形象的表示了ECB模式的原理 Snip20210612_12.png

然后我们试一下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模式的区别 Snip20210612_13.png

对称加密的代码演练

使用AES算法,ECB模式进行加密(EncryptionTools下载) Snip20210612_14.png 再用终端来验证一下结果:echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64 Snip20210613_15.png

使用AES算法,CBC模式进行加密 Snip20210613_16.png 终端验证结果:echo -n hello | openssl enc -aes-128-cbc -K 616263 -nosalt -iv 0102030405060708 | base64 image.png 终端验证解密结果:echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -K 616263 -iv 0102030405060708 -nosalt -d Snip20210613_18.png

[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下一个符号断点,就可以拿到这个函数的所有参数信息了,那用户的明文密码就泄露无疑了... image.png 寄存器读这个函数的第七个参数就是register read x6(x0是第一个)明文数据

分类:
iOS
标签:
分类:
iOS
标签:
收藏成功!
已添加到「」, 点击更改