Python 哈希函数与消息认证实验


前言

提示:测试运行环境为 python3.7.5,IDE为Pycharm2020.1,文章包含三道题,分别是:1.计算哈希值和消息认证;2.哈希函数的雪崩效应;3.暴力破解MD5。复制过去的源码可能要改一下输出格式嗷。

一、计算哈希值和消息认证

题目描述:编写一个能计算文本MD5、SHA512和hmac的程序。

1.引入库

代码如下:

import hashlib
import hmac
from hashlib import md5, sha256, sha512

关于库的使用可见官方文档:
hmac — 基于密钥的消息验证
hashlib — 安全哈希与消息摘要

2.实现

实现–版本一:

# 一开始写的,为了过实验的版本
import hashlib
import hmac
from hashlib import md5, sha256, sha512

def myhash(str):
    res = hashlib.md5(str.encode(encoding="utf-8"))
    print(res.hexdigest())


def myhmac(key, str, mode):
    # param key:计算消息验证码的用到的密钥
    # param str:计算消息验证码的字符串
    # param mode: 使用的哈希函数
    key = key.encode(encoding="utf-8")
    str = str.encode(encoding="utf-8")
    if mode == 'md5':
        my_hmac = hmac.new(key, str, digestmod=md5)
        res1 = sha512(str)
        print(res1.hexdigest())
        print(my_hmac.hexdigest())

    elif mode == 'sha256':
        res1 = sha512(str)
        print(res1.hexdigest())
        my_hmac = hmac.new(key, str, digestmod=sha256)
        print(my_hmac.hexdigest())

    elif mode == 'sha512':
        res1 = sha512(str)
        print(res1.hexdigest())
        my_hmac = hmac.new(key, str, digestmod=sha512)
        print(my_hmac.hexdigest())

if __name__ == "__main__":
    str = input()
    key = input()
    mode = input()
    myhash(str)
    myhmac(key, str, mode)

那会为了过实验,写的又臭又长,不美观也不好读,也就是实现个功能罢了,于是又跑去参考了BossXie同学的代码,看完之后直呼666,简洁得不像话,于是我也大致照着思路又写了一个改良版:

# 改良版

import hashlib
import hmac
from hashlib import md5, sha256, sha512

def myhash(str):
    res = hashlib.md5(str.encode(encoding="utf-8"))
    print("md5: " + res.hexdigest())

def myhmac(key, str, mode):
    # param key:计算消息验证码的用到的密钥
    # param str:计算消息验证码的字符串
    # param mode: 使用的哈希函数
    key = key.encode(encoding="utf-8")
    str = str.encode(encoding="utf-8")
    my_hmac = hmac.new(key, str, mode)
    res1 = sha512(str)
    print("sha512 " + res1.hexdigest())
    print("hmac: " + my_hmac.hexdigest())


if __name__ == "__main__":
    str = input()
    key = input()
    mode = input()
    myhash(str)
    myhmac(key, str, mode)

测试一下结果:
在这里插入图片描述

看着确实是要舒服很多呀~

二、哈希函数的雪崩效应

题目描述:编写一个能验证哈希函数MD5雪崩效应的程序。
(偷偷吐槽:这道题应该是本次实验最烦人的了,虽然说写完之后确实感觉不难,但是题目的提示真的太少了!可以查的资料也不多,是比较难写的,当然也可能是我太菜了)

实现

代码如下:

import hashlib

def encode(s):
    return ' '.join([bin(ord(c)).replace('0b', '') for c in s])


def decode(s):
    return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]])


# 该函数用于计算两个字符串不同的位数
def cmpcount(str1, str2):
    count = 0
    for i in range(0, len(str1)):
        times += 1
        if str1[i] != str2[i]:
            count += 1
    return count


def avalanche(str, nbyte, mbit):
    # param str:计算哈希值的字符串
    # param nbyte:str的第几个字节(从低位到高位数)
    # parem mbit: nbyte的第几个bit位(从低位到高位数)
    h1 = hashlib.md5(str.encode(encoding="utf-8"))  # 获取原字符串的MD5
    h1 = h1.hexdigest()
    nbyte_place = len(str) - nbyte  # 获取目标字节所在位置
    nbytes = str[nbyte_place]  # 获取目标字节
    nbyte_str = encode(nbytes)  # 目标字节转换为二进制

    mbit_place = len(nbyte_str) - mbit    # 获取目标bit位置,第一次调试出错点
    mbits = nbyte_str[mbit_place]   # 获取目标bit
    # bit位翻转+字节二进制还原
    if mbits == '0':
        nbyte_str = nbyte_str[:mbit_place] + '1' + nbyte_str[mbit_place+1:]
    elif mbits == '1':
        nbyte_str = nbyte_str[:mbit_place] + '0' + nbyte_str[mbit_place+1:]
    nbyte_str = decode(nbyte_str)   # 获取修改后的字节
    str1 = str[:nbyte_place] + nbyte_str + str[nbyte_place+1:]  # 获取修改后的字符串
    print("str1: " + str1)
    h2 = hashlib.md5(str1.encode(encoding="utf-8"))
    h2 = h2.hexdigest()
    h1 = bin(int(h1, 16))[2:]
    h2 = bin(int(h2, 16))[2:]
    if len(h1) != 128:
        h1 = h1.zfill(128)
    else:
        pass
    if len(h2) != 128:
        h2 = h2.zfill(128)
    else:
        pass
    print("h1: " + h1)
    print("h2: " + h2)
    cout_different = cmpcount(h1, h2)
    print(cout_different)


# 测试:python 2 1
if __name__ == "__main__":
    str, nbyte, mbit = input().split()
    nbyte = int(nbyte)
    mbit = int(mbit)
    avalanche(str, nbyte, mbit)

本题用到的库比第一题少一些,所以就省略了引用库环节,说一下本题的注意事项:
1.字节是按照从低位数排列的,比如 ‘python’ 中的的第一个字节为 ‘n’,第二个字节为 ‘o’,bit位也是按照这样的方式排列的。

2.若是md5加密后的二进制字符串长度不足128位,则需要使用 zfill 函数函数进行补齐,使用方法为str.zfill(lenth),lenth 为需要填充到的位数,本题需要128位,也就是 str.zfill(128)。

3.二进制和字符串之间的相互转换是参照了一位博主的代码,写的很非常nice!看着很简洁就搬到了本程序中。

其他的基本都写在注释里啦,不懂的话欢迎评论区讨论喔~

三、暴力破解MD5

题目描述:编写一个能破解md5的程序
感觉描述的很简洁,我来补充一点点,输入一个字符串,对该字符串进行md5加密,再通过字母、数字、字符的全排列来对照密文,最终得到加密之前的字符串,差不多就是这个意思啦。

1.引入库

代码如下:

from hashlib import md5
from string import ascii_letters, digits, punctuation   # 用string模块获得字母、数字和字符
from itertools import permutations  # 用于全排列

用法其实很简单的,待会看代码就知道了,注释也有写的,所以就不多赘述啦

2.实现

代码如下:

# 哈希函数的雪崩效应
# author:marxycj
# date:2021-10-29


from hashlib import md5
from string import ascii_letters, digits, punctuation   # 用string模块获得字母、数字和字符
from itertools import permutations  # 用于全排列


def brute_md5(md5_value):
    if len(md5_value) != 32:
        print("不是有效的md5值")
        return
    else:
        allkind = ascii_letters + digits + punctuation
        for i in range(5, 10):
            for j in permutations(allkind, i):
                md5_test = ''.join(j)
                md5_testmd5 = md5(md5_test.encode(encoding="utf-8"))
                md5_testhex = md5_testmd5.hexdigest()
                if md5_testhex == md5_value:
                    print(md5_test)
                    return


if __name__ == '__main__':
    md5_value = input()
    brute_md5(md5_value)

解释一下,allkind就是 字母、数字、字符的组合啦,把三种类型加起来, md5_test用来接收全排列字符串然后进行md5暴力破解测试的,或许叫md5_try合适些,别的也没有啥要注意的啦~

总结

总结:

可能写代码的时候自己写的不快,也不如别人写的好,写的整洁,但是最好还是自己写一遍,毕竟是自己的思路,写完之后再去对照大佬的进行修改,这样或许可以更好地提升自己的代码能力,没有经过思考就照搬代码,能学的东西就比较有限,愿脚踏实地,不骄不躁。

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值