Python hash function and message authentication experiment

preface

Tip: the test run environment is Python 3.7.5 and the IDE is Pycharm2020.1. The article contains three questions: 1. Calculating hash value and message authentication; 2. Avalanche effect of hash function; 3. Brute force MD5. Copying the past source code may need to change the output format.

1, Calculate hash value and message authentication

Title Description: write a program that can calculate text MD5, SHA512 and hmac.

1. Import and storage

The code is as follows:

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

See the official documentation for the use of the Library:
hmac -- key based message authentication
hashlib - secure hash and message digest

2. Realization

Implementation – version 1:

# It was written at the beginning for the experimental version
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: the key used to calculate the message verification code
    # param str: string to calculate the message verification code
    # param mode: hash function used
    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)

In order to carry out the experiment, I wrote it smelly and long, unsightly and difficult to read, that is, to realize a function, so I went to refer to the code of BossXie. After reading it, I knew it was 666, which was not as concise as words, so I also wrote an improved version roughly according to my ideas:

# Improved version

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: the key used to calculate the message verification code
    # param str: string to calculate the message verification code
    # param mode: hash function used
    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)

Test the results:

It's really much more comfortable~

2, Avalanche effect of hash function

Title Description: write a program that can verify the avalanche effect of hash function MD5.
(secretly Tucao: this question should be the most annoying thing in this experiment. Although it is not difficult to write after finishing, there are really few hints on the title. There are not many materials to make complaints about, but it is difficult to write, and of course it is probably my dish.)

realization

The code is as follows:

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(' ')]])


# This function is used to calculate the number of different bits of two strings
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: string to calculate hash value
    # Param nbyte: the number of bytes of str (from low bit to high bit)
    # Parem Mbit: bit number of nbyte (from low bit to high bit)
    h1 = hashlib.md5(str.encode(encoding="utf-8"))  # Get MD5 of the original string
    h1 = h1.hexdigest()
    nbyte_place = len(str) - nbyte  # Gets the location of the target byte
    nbytes = str[nbyte_place]  # Get target byte
    nbyte_str = encode(nbytes)  # Convert target byte to binary

    mbit_place = len(nbyte_str) - mbit    # Get the target bit location and debug the error point for the first time
    mbits = nbyte_str[mbit_place]   # Get target bit
    # bit flip + byte binary restore
    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)   # Get modified bytes
    str1 = str[:nbyte_place] + nbyte_str + str[nbyte_place+1:]  # Gets the modified string
    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)


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

This question uses less library than the first question, so the reference library link is omitted. Let's talk about the precautions of this question:
1. The bytes are arranged from the lower bits. For example, the first byte in 'python' is' n ', the second byte is' o', and the bit bits are arranged in this way.

2. If the length of md5 encrypted binary string is less than 128 bits, you need to use zfill function to supplement. The use method is str.zfill(lenth), lenth is the number of bits to be filled in, and 128 bits are required for this problem, that is, str.zfill(128).

3. The conversion between binary and string refers to the code of a blogger, which is very nice! It looks very concise and moved to this program.

Others are basically written in the notes. If you don't understand, welcome to the comment area for discussion~

3, Brute force MD5

Title Description: write a program that can crack md5
I think the description is very concise. Let me add a little. Enter a string, md5 encrypt the string, and then compare the ciphertext through the full arrangement of letters, numbers and characters, and finally get the string before encryption. That's almost what it means.

1. Import and storage

The code is as follows:

from hashlib import md5
from string import ascii_letters, digits, punctuation   # Use the string module to get letters, numbers, and characters
from itertools import permutations  # For Full Permutation

In fact, the usage is very simple. You'll see the code later. Comments are also written, so I won't go into details

2. Realization

The code is as follows:

# Avalanche effect of hash function
# author:marxycj
# date:2021-10-29


from hashlib import md5
from string import ascii_letters, digits, punctuation   # Use the string module to get letters, numbers, and characters
from itertools import permutations  # For Full Permutation


def brute_md5(md5_value):
    if len(md5_value) != 32:
        print("Not valid md5 value")
        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)

Explain that allkind is a combination of letters, numbers and characters. Add up the three types, md5_test is used to receive full array strings and then conduct md5 brute force cracking test, perhaps called md5_try is more appropriate. There's nothing else to pay attention to~

summary

Summary:

You may not write the code quickly when you write it, and it's not as good as others. You can write it neatly, but you'd better write it yourself. After all, it's your own idea. After writing, you can modify it according to the boss. In this way, you may better improve your code ability. If you copy the code without thinking, you can learn more limited things. I'm willing to be down-to-earth, free from arrogance and impetuosity.

Tags: Python cryptology

Posted on Fri, 29 Oct 2021 04:11:29 -0400 by alsouno