哈希与加密解密

哈希与加密解密

一、哈希函数

1、概念

哈希,英文叫做hash

哈希函数(hash function)可以把任意长度的数据(字符串)计算出一个固定长度的结果数据。

我们习惯把要计算的数据称之为源数据,计算后的数据结果称之为哈希值(hash value)

有好几种常用哈希函数,对应不同的算法,常见的有MD5,SHA1,SHA224,SHA384,SHA512

2、特点

  • 相同的源数据,采用相同的哈希算法,计算出来的哈希值一定相同
  • 不管源数据有多大,相同的哈希算法,计算出来的哈希值长度都是一样长的
算法哈希值长度
MD516字节
SHA120字节
SHA22428字节
SHA25632字节
SHA38448字节
SHA51264字节
  • 算法不可逆

    也就是说,不能通过哈希值反过来计算出源数据。所以哈希和我们常说的加密解密不同

  • 不同的源数据 使用同样的哈希算法,可能会产生相同的 哈希值,这被称之为碰撞率(collision rate)

    各种哈希算法,计算的结果长度越长,碰撞率越低,通常耗费的计算时长也越长。

    即使是 MD5 算法, 碰撞率也 非常小,小到几乎可以忽略不计。大约是 1.47*10的负29次方

3、应用场景

那哈希函数到底有什么用呢?

  1. 校验下载文件

    相信大家都在网上下载过数据量较大的文件,比如高达几十G的游戏,电影,Gho镜像文件等等。

    这些文件,在传输过程中,是有可能出错的;而一旦出错,整个文件就不可用。怎么快速的校验我下载的文件是不是对的呢?这时候,就可以使用哈希算法

    在下载的网站上,会提供源文件的哈希值,下载完后,在我们的电脑上,把哈希值计算出来,进行比对,如果两者相等,那么久可以认为下载没有问题。

  2. 校验信息的有效性

    如果你经营一个学校,每年开学时,学生要到 管理部 交学费, 一个交完学费,工作人员给他们的手机上发一条信息 张三,学费已交

    张三带着这个手机信息到 教学部 领书, 教学部工作人员,看到手机上 有 张三,学费已交 就给他发书。

    这个流程,有一个问题: 教学部的人 怎么知道 学生已交学费的短信 是不是自己伪造的?

    一种解决方法,就是, 管理部和教学部 共享一个密钥,也就是一串字符串,比如 13ty8ffbs2v ,

    管理部的人,收到费用,并且给学生发的 短信,除了 张三,学费已交 之外, 用哈希算法,对如下字符串进行哈希计算

    张三,学费已交|13ty8ffbs2v
    

    这个字符串里面包含了密钥, 如果使用MD5算法,产生这样的哈希值 ccdcb2e80ee2cbf2520844498e4169b0

    给学生发的短信不仅有 张三,学费已交 ,还要包括哈希值 ccdcb2e80ee2cbf2520844498e4169b0

    到了 教学部, 发书的老师,也使用 哈希算法,对如下字符串进行哈希计算

    张三,学费已交|13ty8ffbs2v
    

    如果计算的结果 和学生提供的短信里面的哈希值一致,说明没有捏造信息。

    注意,密钥 13ty8ffbs2v 只有 教学部 和管理部的老师知道,学生是不知道的。所以学生没有办法产生 管理部们才能制作出来的 哈希值。

二、Python计算哈希值

1、hashlib

那么我们怎么使用python来创建哈希值呢?

使用Python内置库hashlib即可

import hashlib

# 使用 md5 算法
m = hashlib.md5()

# 要计算的源数据必须是字节串格式
# 字符串对象需要encode转化为字节串对象
m.update("张三,学费已交|13ty8ffbs2v".encode())

# 产生哈希值对应的bytes对象
resultBytes = m.digest()  
# 产生哈希值的十六进制表示
resultHex   = m.hexdigest()
print(resultHex)

结果为 ccdcb2e80ee2cbf2520844498e4169b0 ,这就是哈希字节串的十六进制表示。

如果你想用别的哈希算法,比如,sha256算法,只需要修改对应的函数sha256()即可

如下

import hashlib
m = hashlib.sha256()

2、盐(salt)

在上一节,我们已经使用了md5算法对一串字符串进行哈希值的运算。但现在有个问题,不考虑哈希碰撞的情况,我们可以理解为每一串字符串都有唯一对应的哈希值。那么就会产生下面的情况:

比如我的密码是qwe123456,对其进行md5加密后的哈希值是2569d419bfea999ff13fd1f7f4498b89

而在经过穷举的方法,可以将大多数简单的明文密文直接查询出来,如www.cmd5.com

在这里插入图片描述

这样,我们可以采用一种加盐的方法,进一步加强我们的算法,如下

import hashlib

# md5()里的参数"125hash241"就是我们所加的盐
m = hashlib.md5(b'125hash241')
m.update('qwe123456'.encode())

resultBytes = m.digest() # 摘要
resultHex = m.hexdigest()
print(resultHex) # 十六进制哈希值:ebb1f8065437f033661b6613033da7f4

这样,就很难再被穷举破解了。使用这种方法,盐一定不能被泄露出去~~

在这里插入图片描述

三、加密与解密

加解密算法,是对源数据进行运算产生加密数据,以及反向过程,对加密数据反算出源数据。

加解密算法和hash算法不同点有:

  • 加解密算法是可逆的,hash算法是不可逆的
  • hash算法可以对很大的数据产生比较小的哈希值,而加密算法源数据很大,加密后的数据也会很大

加解密算法可以分为对称加密非对称加密

1、对称加密

常见的对称加密算法有:AES,RC4,DES,3DES,IDEA等。

其中安全等级较高的是AES

cryptography是python的一个加密库

from cryptography.fernet import Fernet

# 产生密钥, 密钥是加密解密必须的
key = Fernet.generate_key()
f = Fernet(key)

src = "明天晚上6点组织进攻"
# 源信息,必须是字节串对象
# 字符串对象需要encode一下
srcBytes = src.encode()
# 生成加密字节串
token = f.encrypt(srcBytes)
print(token)

# 解密,返回值是字节串对象
sb = f.decrypt(token)
print(sb.decode())

2、非对称加密

最知名的非对称加密系统就是RSA(Rivest–Shamir–Adleman)

早期的加密方法(1976年前),所有加密方法都是对称加密,这种加密模式有一个最大弱点,甲方和乙方都必须知道具体的加密规则,否则无法解密。

1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。

这种算法非常可靠,密钥越长,它就越难破解。根据已经披露的文献,目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

步骤说明描述备注
1找出质数P、Q-
2计算公共模数N = P * Q-
3欧拉函数φ(N) = (P-1)(Q-1)-
4计算公钥E1 < E < φ(N)E的取值必须是整数
E 和 φ(N) 必须是互质数
5计算私钥DE * D % φ(N) = 1-
6加密C = M E mod NC:密文 M:明文
7解密M =C D mod NC:密文 M:明文

具体的算法原理推荐两篇文章:

RSA算法原理(一)

RSA算法原理(二)

  • 14
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区。在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做。 一、应用 共享内存的使用,主要有以下几个API:ftok()、shmget()、shmat()、shmdt()及shmctl()。 1)用ftok()函数获得一个ID号. 应用说明: 在IPC中,我们经常用用key_t的值来创建或者打开信号量,共享内存和消息队列。 函数原型: key_t ftok(const char *pathname, int proj_id); Keys: 1)pathname一定要在系统中存在并且进程能够访问的 3)proj_id是一个1-255之间的一个整数值,典型的值是一个ASCII值。 当成功执行的时候,一个key_t值将会被返回,否则-1被返回。我们可以使用strerror(errno)来确定具体的错误信息。 考虑到应用系统可能在不同的主机上应用,可以直接定义一个key,而不用ftok获得: #define IPCKEY 0x344378 2)shmget()用来开辟/指向一块共享内存的函数 应用说明: shmget()用来获得共享内存区域的ID,如果不存在指定的共享区域就创建相应的区域。 函数原型: int shmget(key_t key, size_t size, int shmflg); key_t key 是这块共享内存的标识符。如果是父子关系的进程间通信的话,这个标识符用IPC_PRIVATE来代替。如果两个进程没有任何关系,所以就用ftok()算出来一个标识符(或者自己定义一个)使用了。 int size 是这块内存的大小. int flag 是这块内存的模式(mode)以及权限标识。 模式可取如下值: IPC_CREAT 新建(如果已创建则返回目前共享内存的id) IPC_EXCL 与IPC_CREAT结合使用,如果已创建则则返回错误 然后将“模式” 和“权限标识”进行“或”运算,做为第三个参数。 如: IPC_CREAT | IPC_EXCL | 0640 例子中的0666为权限标识,4/2/1 分别表示读/写/执行3种权限,第一个0是UID,第一个6(4+2)表示拥有者的权限,第二个4表示同组权限,第3个0表示他人的权限。 这个函数成功时返回共享内存的ID,失败时返回-1。 关于这个函数,要多说两句。 创建共享内存时,shmflg参数至少需要 IPC_CREAT | 权限标识,如果只有IPC_CREAT 则申请的地址都是k=0xffffffff,不能使用; 获取已创建的共享内存时,shmflg不要用IPC_CREAT(只能用创建共享内存时的权限标识,如0640),否则在某些情况下,比如用ipcrm删除共享内存后,用该函数并用IPC_CREAT参数获取一次共享内存(当然,获取失败),则即使再次创建共享内存也不能成功,此时必须更改key来重建共享内存。 3) shmat()将这个内存区映射到本进程的虚拟地址空间。 函数原型: void *shmat( int shmid , char *shmaddr , int shmflag ); shmat()是用来允许本进程访问一块共享内存的函数。 int shmid是那块共享内存的ID。 char *shmaddr是共享内存的起始地址,如果shmaddr为0,内核会把共享内存映像到调用进程的地址空间中选定位置;如果shmaddr不为0,内核会把共享内存映像到shmaddr指定的位置。所以一般把shmaddr设为0。 int shmflag是本进程对该内存的操作模式。如果是SHM_RDONLY的话,就是只读模式。其它的是读写模式 成功时,这个函数返回共享内存的起始地址。失败时返回-1。 4) shmdt()函数删除本进程对这块内存的使用,shmdt()与shmat()相反,是用来禁止本进程访问一块共享内存的函数。 函数原型: int shmdt( char *shmaddr ); 参数char *shmaddr是那块共享内存的起始地址。 成功时返回0。失败时返回-1。 5) shmctl() 控制对这块共享内存的使用 函数原型: int shmctl( int shmid , int cmd , struct shmid_ds *buf ); int shmid是共享内存的ID。 int cmd是控制命令,可取值如下: IPC_STAT 得到共享内存的状态 IPC_SET 改变共享内存的状态 IPC_RMID 删除共享内存 struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。 返回值: 成功:0 失败:-1

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梓沫1119

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值