├── event └── configuration.py ├── test_file ├── key_export.txt ├── ecc_private_key.txt ├── key_import.txt ├── rsa_private_key.txt ├── to_encrypt_test.txt └── to_encrypt_test.docx ├── algorithm ├── stream_cipher │ ├── 加密密钥.txt │ ├── 明文.txt │ ├── 密文.txt │ ├── ca │ │ ├── ca_file.py │ │ └── ca_string.py │ └── rc4_cipher.py ├── public_cipher │ ├── ecc │ │ ├── test.rar │ │ ├── func.py │ │ ├── sm3.py │ │ ├── verifyrandom.py │ │ └── ecc.py │ └── rsa │ │ └── rsa.py ├── classical_cipher │ ├── caesar_cipher.py │ ├── permutation_cipher.py │ ├── keyword_cipher.py │ ├── affine_cipher.py │ ├── column_permutation_cipher.py │ ├── vigenere_cipher.py │ ├── playfair_cipher.py │ ├── autokey_plaintext_cipher.py │ ├── multilateral_cipher.py │ ├── double_transposition_cipher.py │ └── autokey_ciphertext_cipher.py ├── hash_algorithm │ ├── md5_file.py │ ├── md5_string.py │ └── md5.py └── block_cipher │ ├── des_cipher.py │ └── aes │ ├── aes_file.py │ └── aes_string.py ├── requirements.txt ├── assets ├── icons │ ├── close.png │ ├── undock.png │ ├── checkbox.png │ ├── sizegrip.png │ ├── up_arrow.png │ ├── PentestBox.ico │ ├── branch_open.png │ ├── down_arrow.png │ ├── left_arrow.png │ ├── right_arrow.png │ ├── transparent.png │ ├── Hmovetoolbar.png │ ├── Hsepartoolbar.png │ ├── Vmovetoolbar.png │ ├── Vsepartoolbar.png │ ├── branch_closed.png │ ├── branch_closed-on.png │ ├── branch_open-on.png │ ├── stylesheet-vline.png │ ├── up_arrow_disabled.png │ ├── down_arrow_disabled.png │ ├── left_arrow_disabled.png │ ├── right_arrow_disabled.png │ ├── stylesheet-branch-end.png │ └── stylesheet-branch-more.png ├── python │ └── qss_reader.py └── qss │ └── darkstyle.qss ├── pyproject.toml ├── main.py ├── .gitignore ├── README_CN.md ├── uv.lock └── README.md /event/configuration.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test_file/key_export.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test_file/ecc_private_key.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test_file/key_import.txt: -------------------------------------------------------------------------------- 1 | hello -------------------------------------------------------------------------------- /test_file/rsa_private_key.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test_file/to_encrypt_test.txt: -------------------------------------------------------------------------------- 1 | test -------------------------------------------------------------------------------- /algorithm/stream_cipher/加密密钥.txt: -------------------------------------------------------------------------------- 1 | my-rc4-key -------------------------------------------------------------------------------- /algorithm/stream_cipher/明文.txt: -------------------------------------------------------------------------------- 1 | An apple a day keeps the doctor away 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pyqt5==5.15.11 2 | pyqt5-qt5==5.15.18 3 | pyqt5-sip==12.17.1 4 | -------------------------------------------------------------------------------- /algorithm/stream_cipher/密文.txt: -------------------------------------------------------------------------------- 1 | E5159BC460605C14A499887EA184698AE3A4F723F69B3C064ED964F2838F92E3FB698D53 2 | -------------------------------------------------------------------------------- /assets/icons/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/close.png -------------------------------------------------------------------------------- /assets/icons/undock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/undock.png -------------------------------------------------------------------------------- /assets/icons/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/checkbox.png -------------------------------------------------------------------------------- /assets/icons/sizegrip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/sizegrip.png -------------------------------------------------------------------------------- /assets/icons/up_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/up_arrow.png -------------------------------------------------------------------------------- /assets/icons/PentestBox.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/PentestBox.ico -------------------------------------------------------------------------------- /assets/icons/branch_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/branch_open.png -------------------------------------------------------------------------------- /assets/icons/down_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/down_arrow.png -------------------------------------------------------------------------------- /assets/icons/left_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/left_arrow.png -------------------------------------------------------------------------------- /assets/icons/right_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/right_arrow.png -------------------------------------------------------------------------------- /assets/icons/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/transparent.png -------------------------------------------------------------------------------- /assets/icons/Hmovetoolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/Hmovetoolbar.png -------------------------------------------------------------------------------- /assets/icons/Hsepartoolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/Hsepartoolbar.png -------------------------------------------------------------------------------- /assets/icons/Vmovetoolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/Vmovetoolbar.png -------------------------------------------------------------------------------- /assets/icons/Vsepartoolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/Vsepartoolbar.png -------------------------------------------------------------------------------- /assets/icons/branch_closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/branch_closed.png -------------------------------------------------------------------------------- /test_file/to_encrypt_test.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/test_file/to_encrypt_test.docx -------------------------------------------------------------------------------- /assets/icons/branch_closed-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/branch_closed-on.png -------------------------------------------------------------------------------- /assets/icons/branch_open-on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/branch_open-on.png -------------------------------------------------------------------------------- /assets/icons/stylesheet-vline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/stylesheet-vline.png -------------------------------------------------------------------------------- /assets/icons/up_arrow_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/up_arrow_disabled.png -------------------------------------------------------------------------------- /algorithm/public_cipher/ecc/test.rar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/algorithm/public_cipher/ecc/test.rar -------------------------------------------------------------------------------- /assets/icons/down_arrow_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/down_arrow_disabled.png -------------------------------------------------------------------------------- /assets/icons/left_arrow_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/left_arrow_disabled.png -------------------------------------------------------------------------------- /assets/icons/right_arrow_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/right_arrow_disabled.png -------------------------------------------------------------------------------- /assets/icons/stylesheet-branch-end.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/stylesheet-branch-end.png -------------------------------------------------------------------------------- /assets/icons/stylesheet-branch-more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/morsuning/cryptography-gui-tool/HEAD/assets/icons/stylesheet-branch-more.png -------------------------------------------------------------------------------- /assets/python/qss_reader.py: -------------------------------------------------------------------------------- 1 | class QssReader: 2 | def __init__(self): 3 | pass 4 | 5 | # @staticmethod 6 | def read_qss(style): 7 | with open(style, 'r') as f: 8 | return f.read() 9 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "cryptography-gui-tool" 3 | version = "0.1.0" 4 | description = "Add your description here" 5 | readme = "README.md" 6 | requires-python = ">=3.13" 7 | dependencies = [ 8 | "pyqt5>=5.15.11", 9 | ] 10 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from PyQt5.QtWidgets import QApplication, QMainWindow 4 | 5 | from event import event 6 | 7 | if __name__ == '__main__': 8 | app = QApplication(sys.argv) 9 | MainWindow = QMainWindow() 10 | ui = event.Event(MainWindow) 11 | MainWindow.show() 12 | sys.exit(app.exec_()) 13 | -------------------------------------------------------------------------------- /algorithm/public_cipher/ecc/func.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | 3 | xor = lambda a, b: list(map(lambda x, y: x ^ y, a, b)) 4 | 5 | rotl = lambda x, n: ((x << n) & 0xffffffff) | ((x >> (32 - n)) & 0xffffffff) 6 | 7 | get_uint32_be = lambda key_data: ((key_data[0] << 24) | (key_data[1] << 16) | (key_data[2] << 8) | (key_data[3])) 8 | 9 | put_uint32_be = lambda n: [((n >> 24) & 0xff), ((n >> 16) & 0xff), ((n >> 8) & 0xff), ((n) & 0xff)] 10 | 11 | padding = lambda data, block=16: data + [(16 - len(data) % block) for _ in range(16 - len(data) % block)] 12 | 13 | unpadding = lambda data: data[:-data[-1]] 14 | 15 | list_to_bytes = lambda data: b''.join([bytes((i,)) for i in data]) 16 | 17 | bytes_to_list = lambda data: [i for i in data] 18 | 19 | random_hex = lambda x: ''.join([choice('0123456789abcdef') for _ in range(x)]) 20 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/caesar_cipher.py: -------------------------------------------------------------------------------- 1 | def caesar_encrypt(x, k=3): 2 | """第一个参数为明文字符串,第二个参数为向后移位的位数""" 3 | result = '' 4 | move = k % 26 5 | for i in x: 6 | pass 7 | # 如果是大写 8 | if i.isupper(): 9 | result = result + chr(65 + (ord(i) + move - 65) % 26) 10 | elif i.islower(): 11 | result = result + chr(97 + (ord(i) + move - 97) % 26) 12 | return result 13 | 14 | def caesar_decrypt(x, k=3): 15 | """第一个参数为明文字符串,第二个参数为向后移位的位数""" 16 | result = '' 17 | move = k % 26 18 | for i in x: 19 | # 如果是大写 20 | if i.isupper(): 21 | result = result + chr(65 + (ord(i) - move - 65) % 26) 22 | elif i.islower(): 23 | result = result + chr(97 + (ord(i) - move - 97) % 26) 24 | return result 25 | 26 | def main(): 27 | print('Abcd凯撒加密的密文是:', caesar_encrypt('Abcd', 3)) 28 | print('Defg凯撒加密的明文是:', caesar_decrypt('Defg', 3)) 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/permutation_cipher.py: -------------------------------------------------------------------------------- 1 | def msgToChunks(msg, key): 2 | msg = msg.replace(' ', '') 3 | while len(msg) % len(key) != 0: 4 | msg += ' ' 5 | chunks = [] 6 | for i in range(0, len(msg), len(key)): 7 | chunks.append(msg[i:i + len(key)]) 8 | return chunks 9 | 10 | def transpose(chunks, order): 11 | result = '' 12 | for x in chunks: 13 | for pos in order: 14 | result += x[pos] 15 | return result.replace(' ', '') 16 | 17 | def keyToEncrptyOrder(key): 18 | order = [0] * len(key) 19 | sorted_key = ''.join(sorted(key)) 20 | for i, x in enumerate(key): 21 | order[sorted_key.find(x)] = i 22 | # print(order) 23 | return order 24 | 25 | def keyToDecrptyOrder(key): 26 | order = [0] * len(key) 27 | sorted_key = ''.join(sorted(key)) 28 | for i, x in enumerate(key): 29 | order[i] = sorted_key.find(x) 30 | # print(order) 31 | return order 32 | 33 | def encrypt(msg, key): 34 | msg = msg.replace(' ', '') 35 | chunks = msgToChunks(msg, key) 36 | order = keyToEncrptyOrder(key) 37 | return transpose(chunks, order) 38 | 39 | def decrypt(msg, key): 40 | msg = msg.replace(' ', '') 41 | chunks = msgToChunks(msg, key) 42 | order = keyToDecrptyOrder(key) 43 | return transpose(chunks, order) 44 | 45 | def test(): 46 | print(encrypt('get the ball', '34152')) 47 | print(decrypt('thgetalebl', '34152')) 48 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/keyword_cipher.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | def encrypt(plaintext, ci_key): 4 | plaintext = list(plaintext.lower()) 5 | ciphertext = list(string.ascii_lowercase) 6 | ci_key = list(ci_key.lower()) 7 | key = [] 8 | for i in ci_key: 9 | if i not in key: 10 | key.append(i) 11 | for i in ciphertext: 12 | if i not in key: 13 | key.append(i) 14 | all_letter = list(string.ascii_lowercase) 15 | ciphertext = [] 16 | for i in plaintext: 17 | for j in range(26): 18 | if i == all_letter[j]: 19 | ciphertext.append(key[j]) 20 | return "".join(list(ciphertext)), "".join(list(key)) 21 | 22 | def decrypt(ciphertext, ci_key): 23 | str_ciphertext = list(string.ascii_lowercase) 24 | ci_key = list(ci_key.lower()) 25 | key = [] 26 | for i in ci_key: 27 | if i not in key: 28 | key.append(i) 29 | for i in str_ciphertext: 30 | if i not in key: 31 | key.append(i) 32 | all_letter = string.ascii_lowercase 33 | plaintext = [] 34 | ciphertext = list(ciphertext) 35 | for i in ciphertext: 36 | for j in range(26): 37 | if i == key[j]: 38 | plaintext.append(all_letter[j]) 39 | return "".join(list(plaintext)) 40 | 41 | def main(): 42 | plaintext = input("请输入明文") 43 | ci_key = input("请输入密匙") 44 | ciphertext, key = encrypt(plaintext, ci_key) 45 | plaintext = decrypt(ciphertext, ci_key) 46 | print("解密结果" + plaintext) 47 | 48 | if __name__ == '__main__': 49 | main() 50 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/affine_cipher.py: -------------------------------------------------------------------------------- 1 | dic = {1: 1, 3: 9, 5: 21, 7: 15, 9: 3, 11: 19, 15: 7, 17: 23, 19: 11, 21: 5, 23: 17, 25: 25} # 模逆 2 | table_encrypt = {'a': 0, 'b': 1, 'c': 2, 'd': 3, 'e': 4, 'f': 5, 3 | 'g': 6, 'h': 7, 'i': 8, 'j': 9, 'k': 10, 'l': 11, 'm': 12, 4 | 'n': 13, 'o': 14, 'p': 15, 'q': 16, 'r': 17, 's': 18, 't': 19, 5 | 'u': 20, 'v': 21, 'w': 22, 'x': 23, 'y': 24, 'z': 25} 6 | table_decrypt = {0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7 | 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 8 | 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z'} 9 | 10 | # 加密 11 | def encrypt(clear_content, key_a, key_b): 12 | key_a = key_a % 26 13 | key_b = key_b % 26 14 | result = "" 15 | for i in clear_content: 16 | result += table_decrypt.get((key_a * (table_encrypt.get(i)) + key_b) % 26) 17 | return result 18 | 19 | # 解密 20 | def decrypt(cipher, key_a, key_b): 21 | key_a = key_a % 26 22 | key_b = key_b % 26 23 | result = "" 24 | for i in cipher: 25 | result += table_decrypt.get((dic.get(key_a) * table_encrypt.get(i) - (dic.get(key_a) * key_b) % 26) % 26) 26 | return result 27 | 28 | def filter_clear(clear): 29 | result = "" 30 | clear = clear.lower() 31 | for i in clear: 32 | if 97 <= ord(i) <= 122: 33 | result += i 34 | return result 35 | 36 | def main(): 37 | a = 25 38 | b = 13 39 | plaintext = "heljfowejklfg" 40 | ciphertext = encrypt(plaintext, a, b) 41 | print(ciphertext) 42 | print(decrypt(ciphertext, a, b)) 43 | 44 | if __name__ == '__main__': 45 | main() 46 | -------------------------------------------------------------------------------- /algorithm/stream_cipher/ca/ca_file.py: -------------------------------------------------------------------------------- 1 | cell = "00010100" 2 | 3 | 4 | def encrypt(filename, rule, newfilename): 5 | if rule < 0 or rule > 255: 6 | return "rule超过范围" 7 | rule = bin(rule)[2:].zfill(8) 8 | f1 = open(filename, "rb") 9 | Plaintext = f1.read() 10 | f1.close() 11 | key = [] 12 | key.append(int(cell, 2)) 13 | for i in range(len(Plaintext)): 14 | new_key = "" 15 | old_key = bin(key[-1])[2:].zfill(8) 16 | for i in range(0, len(old_key)): 17 | tmp = "" 18 | tmp += old_key[i - 1] + old_key[i] 19 | if i == len(old_key) - 1: 20 | tmp += old_key[0] 21 | else: 22 | tmp += old_key[i + 1] 23 | new_key += str(rule[int(tmp, 2)]) 24 | key.append(int(new_key, 2)) 25 | result = [] 26 | for i, j in zip(Plaintext, key): 27 | result.append(i ^ j) 28 | f2 = open(newfilename, "wb") 29 | f2.write(bytes(result)) 30 | f2.close() 31 | 32 | 33 | def decrypt(filename, rule, newfilename): 34 | if rule < 0 or rule > 255: 35 | return "rule超过范围" 36 | rule = bin(rule)[2:].zfill(8) 37 | f1 = open(filename, "rb") 38 | Plaintext = f1.read() 39 | f1.close() 40 | key = [int(cell, 2)] 41 | for i in range(len(Plaintext)): 42 | new_key = "" 43 | old_key = bin(key[-1])[2:].zfill(8) 44 | for i in range(0, len(old_key)): 45 | tmp = "" 46 | tmp += old_key[i - 1] + old_key[i] 47 | if i == len(old_key) - 1: 48 | tmp += old_key[0] 49 | else: 50 | tmp += old_key[i + 1] 51 | new_key += str(rule[int(tmp, 2)]) 52 | key.append(int(new_key, 2)) 53 | result = [] 54 | for i, j in zip(Plaintext, key): 55 | result.append(i ^ j) 56 | f2 = open(newfilename, "wb") 57 | f2.write(bytes(result)) 58 | f2.close() 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | **.pytest_cache/ 8 | venv/ 9 | 10 | # C extensions 11 | *.so 12 | 13 | # Distribution / packaging 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # pyenv 80 | .python-version 81 | 82 | # celery beat schedule file 83 | celerybeat-schedule 84 | 85 | # SageMath parsed files 86 | *.sage.py 87 | 88 | # Environments 89 | .env 90 | .venv 91 | env/ 92 | **venv/ 93 | ENV/ 94 | env.bak/ 95 | venv.bak/ 96 | .idea 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | 111 | **.DS_Store -------------------------------------------------------------------------------- /algorithm/stream_cipher/ca/ca_string.py: -------------------------------------------------------------------------------- 1 | cell = "00010100" 2 | 3 | 4 | def encrypt(Plaintext, rule): 5 | if rule < 0 or rule > 255: 6 | return "rule超过范围" 7 | Plaintext = Plaintext.encode('utf-8') 8 | rule = bin(rule)[2:].zfill(8) 9 | key = [int(cell, 2)] 10 | for i in range(len(Plaintext)): 11 | new_key = "" 12 | old_key = bin(key[-1])[2:].zfill(8) 13 | for i in range(0, len(old_key)): 14 | tmp = "" 15 | tmp += old_key[i - 1] + old_key[i] 16 | if i == len(old_key) - 1: 17 | tmp += old_key[0] 18 | else: 19 | tmp += old_key[i + 1] 20 | new_key += str(rule[int(tmp, 2)]) 21 | key.append(int(new_key, 2)) 22 | result = [] 23 | for i, j in zip(Plaintext, key): 24 | result.append(i ^ j) 25 | ciphertext = "0x" 26 | for i in result: 27 | ciphertext += hex(i)[2:].zfill(2) 28 | return ciphertext[2:] 29 | 30 | 31 | def decrypt(ciphertext, rule): 32 | if rule < 0 or rule > 255: 33 | return "rule超过范围" 34 | rule = bin(rule)[2:].zfill(8) 35 | if "0x" in ciphertext: 36 | ciphertext = ciphertext[2:] 37 | blk = [] 38 | i = 0 39 | while i + 2 <= len(ciphertext): 40 | blk.append(int(ciphertext[i:i + 2], 16)) 41 | i = i + 2 42 | ciphertext = blk 43 | key = [int(cell, 2)] 44 | for i in range(len(ciphertext)): 45 | new_key = "" 46 | old_key = bin(key[-1])[2:].zfill(8) 47 | for i in range(0, len(old_key)): 48 | tmp = "" 49 | tmp += old_key[i - 1] + old_key[i] 50 | if i == len(old_key) - 1: 51 | tmp += old_key[0] 52 | else: 53 | tmp += old_key[i + 1] 54 | new_key += str(rule[int(tmp, 2)]) 55 | key.append(int(new_key, 2)) 56 | result = [] 57 | for i, j in zip(ciphertext, key): 58 | result.append(i ^ j) 59 | return bytes(result).decode("utf-8") 60 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/column_permutation_cipher.py: -------------------------------------------------------------------------------- 1 | # 获得读取顺序,返回一个读取列号的列表 2 | def getOrder(key): 3 | result = [] 4 | tmp = [] 5 | for i in key: 6 | tmp.append(ord(i)) 7 | order = tmp.copy() 8 | order.sort() 9 | tmporder = set(order) 10 | for i in tmporder: 11 | if order.count(i) == 1: 12 | result.append(tmp.index(i)) 13 | else: 14 | uniqueindex = unique_index(tmp, i) 15 | for j in uniqueindex: 16 | result.append(j) 17 | return result 18 | 19 | # 输入列表和元素,返回列表中和该元素相等的元素的序号的列表 20 | def unique_index(L, e): 21 | return [i for (i, j) in enumerate(L) if j == e] 22 | 23 | # 向明文尾部填充字符e 24 | def padding(plaintext, m): 25 | while len(plaintext) % m != 0: 26 | plaintext += "e" 27 | return plaintext 28 | 29 | # 加密 30 | def encrypt(plaintext, key): 31 | ciphertext = "" 32 | m = len(key) 33 | Plaintext = padding(plaintext, m) 34 | n = len(Plaintext) // m 35 | order = getOrder(key) 36 | for i in order: 37 | excursion = 0 38 | for j in range(n): 39 | ciphertext += Plaintext[i + excursion] 40 | excursion += m 41 | return ciphertext 42 | 43 | # 解密 44 | def decrypt(ciphertext, key): 45 | plaintext = "" 46 | m = len(key) 47 | Ciphertext = padding(ciphertext, m) 48 | n = len(ciphertext) // m 49 | order = getOrder(key) 50 | readorder = [] 51 | for i in range(len(order)): 52 | readorder.append(order.index(i)) 53 | for i in range(n): 54 | for j in readorder: 55 | plaintext += Ciphertext[i + j * n] 56 | return plaintext 57 | 58 | def main(): 59 | plaintext = input("请输入要加密的密文:\n") 60 | key = input("请输入密钥:\n") 61 | ciphertext = encrypt(plaintext.replace(" ", ""), key) 62 | print("加密后的结果是(明文长模密钥长不为零则用e补充):\n%s" % ciphertext) 63 | choice = input("请输入d解密:\n") 64 | if choice == 'd': 65 | key = input("请输入密钥(如果密钥错误将解出错误的结果):\n") 66 | plain = decrypt(ciphertext, key) 67 | print("原文是(省略所有空格):\n%s" % plain) 68 | else: 69 | print("已退出") 70 | 71 | if __name__ == "__main__": 72 | main() 73 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/vigenere_cipher.py: -------------------------------------------------------------------------------- 1 | # 将字母A-Z转化成0-26的数 2 | def str2ascii2mirr26(str): 3 | if len(str) == 1: 4 | return ord(str) - 65 5 | else: 6 | tmpstr = [] 7 | for i in range(len(str)): 8 | tmpstr.append(ord(str[i]) - 65) 9 | return tmpstr 10 | 11 | # 将0-26的数转化为字母A-Z 12 | def mirr262str(str): 13 | tmpstr = "" 14 | for i in str: 15 | tmpstr += chr(i + 65) 16 | return tmpstr 17 | 18 | # 转化为大写 19 | def strupper(str): 20 | s = "" 21 | s += str 22 | return s.upper() 23 | 24 | # 使得密钥长度和明文一致 25 | def expendkey(key, length): 26 | if len(key) > length: 27 | return key[:length] 28 | elif len(key) == length: 29 | return key 30 | else: 31 | while len(key) < length: 32 | key += key 33 | if len(key) != length: 34 | return key[:length] 35 | else: 36 | return key 37 | 38 | # 加密 39 | def encrypt(plaintext, key): 40 | plaintext = strupper(plaintext) 41 | tmpkey = strupper(key) 42 | Key = expendkey(tmpkey, len(plaintext)) 43 | tmpciphertext = [] 44 | for index, item in enumerate(plaintext): 45 | tmpciphertext.append(((str2ascii2mirr26(Key[index]) + str2ascii2mirr26(item)) % 26)) 46 | return mirr262str(tmpciphertext) 47 | 48 | # 解密 49 | def decrypt(ciphertext, key): 50 | tmpkey = strupper(key) 51 | Key = expendkey(tmpkey, len(ciphertext)) 52 | tmpplaintext = [] 53 | for index, item in enumerate(ciphertext): 54 | tmpplaintext.append(((str2ascii2mirr26(item) - str2ascii2mirr26(Key[index])) % 26)) 55 | return mirr262str(tmpplaintext) 56 | 57 | # 实验主流程 58 | def main(): 59 | print("-------------------------") 60 | print("-----Vigenère Cipher-----") 61 | print("-------------------------") 62 | plaintext = input("请输入要加密的密文:\n") 63 | key = input("请输入密钥:\n") 64 | ciphertext = encrypt(plaintext, key) 65 | print("加密后的结果是:\n%s" % ciphertext) 66 | choice = input("请输入d解密:\n") 67 | if choice == 'd': 68 | key = input("请输入密钥(如果密钥错误将解出错误的结果):\n") 69 | plain = decrypt(ciphertext, key) 70 | print("原文是(全部以小写形式给出):\n%s" % (plain.lower())) 71 | else: 72 | print("已退出") 73 | 74 | if __name__ == "__main__": 75 | main() 76 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/playfair_cipher.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | def playfair(key, remaining, encrypting=True): 4 | key = key.lower() 5 | remaining = remaining.lower() 6 | def pos(row, col): # given a row/column, get the position in the table string 7 | return row * 5 + col 8 | def cell(position): # given a position in the table string, get the row/column 9 | row = int(position / 5) 10 | col = position % 5 11 | return row, col 12 | table = "" 13 | # add the key & alphabet to the matrix; ignore duplicates 14 | for c in key.lower() + string.ascii_lowercase: 15 | if c in ['i', 'j']: # treat i/j as the same char 16 | if ('i' not in table) and ('j' not in table): 17 | table = table + 'i' 18 | elif c not in table: 19 | table = table + c 20 | cipher = "" 21 | while remaining != "": 22 | # if only 1 character is left 23 | if len(remaining) == 1: 24 | a = remaining[0] 25 | b = "x" 26 | remaining = "" 27 | # duplicate letter 28 | elif remaining[0] == remaining[1]: 29 | a = remaining[0] 30 | b = "x" 31 | remaining = remaining[1:] 32 | else: 33 | a = remaining[0] 34 | b = remaining[1] 35 | remaining = remaining[2:] 36 | # replace j's with i's 37 | a = "i" if a == "j" else a 38 | b = "i" if b == "j" else b 39 | c1 = cell(table.find(a)) 40 | c2 = cell(table.find(b)) 41 | shift = 1 if encrypting else -1 # for same column/row; if encrypting shift +1, else shift -1 42 | if c1[0] == c2[0]: # same row 43 | cipher = cipher + table[pos(c1[0], (c1[1] + shift) % 5)] + table[pos(c2[0], (c2[1] + shift) % 5)] 44 | elif c1[1] == c2[1]: # same column 45 | cipher = cipher + table[pos((c1[0] + shift) % 5, c1[1])] + table[pos((c2[0] + shift) % 5, c2[1])] 46 | else: 47 | cipher = cipher + table[pos(c1[0], c2[1])] + table[pos(c2[0], c1[1])] 48 | return cipher 49 | 50 | def main(): 51 | # Encrypt foo.txt -> cipher.txt 52 | key = input("请输入key") 53 | plaintext = input("输入明文") 54 | print(playfair(key, plaintext, True).upper()) 55 | key = input("请输入密钥") 56 | ciphertext = input("请输入密文") 57 | print(playfair(key, ciphertext, False).upper()) 58 | 59 | if __name__ == '__main__': 60 | main() 61 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/autokey_plaintext_cipher.py: -------------------------------------------------------------------------------- 1 | def encrypt(plainText, key): 2 | alphabet = [chr(65 + x) for x in range(26)] 3 | cipherTable = [] 4 | count1 = 0 5 | for x in range(26): 6 | row = alphabet[count1:] + alphabet[:count1] 7 | cipherTable.append(row) 8 | count1 += 1 9 | plainTextList = [x.upper() for x in plainText if 10 | (ord(x) >= ord("a") and ord(x) <= ord("z")) or (ord(x) >= ord("A") and ord(x) <= ord("Z"))] 11 | keyList = [x.upper() for x in key] 12 | count2 = 0 13 | 14 | cipherTextList, cipherTextPartList = [], [] 15 | for x in plainTextList: 16 | cipherTextPartList.append(cipherTable[ord(keyList[count2]) - ord("A")][ord(x) - ord("A")]) 17 | 18 | count2 += 1 19 | if count2 == len(keyList): 20 | for y in cipherTextPartList: 21 | cipherTextList.append(y) 22 | keyList = [x for x in cipherTextPartList] 23 | cipherTextPartList = [] 24 | count2 = 0 25 | 26 | if count2 != 0: 27 | for x in cipherTextPartList: 28 | cipherTextList.append(x) 29 | else: 30 | pass 31 | cipherText = "" 32 | for x in cipherTextList: 33 | cipherText += x 34 | return cipherText 35 | 36 | def decrypt(cipherText, key): 37 | alphabet = [chr(65 + x) for x in range(26)] 38 | cipherTable = [] 39 | count1 = 0 40 | for x in range(26): 41 | row = alphabet[count1:] + alphabet[:count1] 42 | cipherTable.append(row) 43 | count1 += 1 44 | keyList = [x.upper() for x in key] 45 | cipherTextList = [x.upper() for x in cipherText] 46 | cipherTextList.reverse() 47 | keyList.reverse() 48 | plainTextList, count2 = [], 0 49 | 50 | for x in range(len(cipherTextList)): 51 | plainTextList.append( 52 | chr((cipherTable[ord(cipherTextList[x + len(keyList)]) - ord("A")].index(cipherTextList[x])) + ord("A"))) 53 | count2 += 1 54 | if count2 >= len(cipherTextList) - len(keyList): 55 | break 56 | 57 | for x, y in zip(keyList, cipherTextList[len(cipherTextList) - len(keyList):]): 58 | plainTextList.append(chr(cipherTable[ord(x) - ord("A")].index(y) + ord("A"))) 59 | plainTextList.reverse() 60 | 61 | plainText = "" 62 | for x in plainTextList: 63 | plainText += x 64 | return plainText 65 | 66 | def main(): 67 | plaintext = "hello" 68 | key = "eii" 69 | ciphertext = encrypt(plaintext, key) 70 | print(ciphertext) 71 | print(decrypt(ciphertext, key)) 72 | 73 | if __name__ == "__main__": 74 | main() 75 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/multilateral_cipher.py: -------------------------------------------------------------------------------- 1 | import collections 2 | 3 | def encrypt(pla, key): 4 | pla = pla.lower() 5 | key = key.lower() 6 | cip = [] 7 | # 定义好矩阵 8 | table = [['', key[0], key[1], key[2], key[3], key[4]], [key[0], 'a', 'b', 'c', 'd', 'e'], 9 | [key[1], 'f', 'g', 'h', 'i', 'k'], [key[2], 'l', 'm', 'n', 'o', 'p'], [key[3], 'q', 'r', 's', 't', 'u'], 10 | [key[4], 'v', 'w', 'x', 'y', 'z']] 11 | for k in pla: 12 | # 当明文中有“j”的时候,当做“i”进行处理 13 | if k == 'j': 14 | k = 'i' 15 | for i in range(1, 6): 16 | for j in range(1, 6): 17 | if k == table[i][j] and k != 'j': 18 | cip.append(table[i][0]) 19 | cip.append(table[0][j]) 20 | cipertext = ''.join(cip) 21 | return cipertext 22 | 23 | 24 | def decrypt(cip, key): 25 | # 将密文拆分,两个两个一组存放 26 | cip = cip.lower() 27 | key = key.lower() 28 | temp = key 29 | cip_res = [] 30 | for i in range(0, len(cip), 2): 31 | cip_res.append(cip[i:i + 2]) 32 | # 存放密文的所有组合 33 | key_res = [] 34 | pla = [] 35 | # 去除重复字母 36 | key = ''.join(collections.OrderedDict.fromkeys(cip)) 37 | for i1 in key: 38 | for i2 in key: 39 | for i3 in key: 40 | for i4 in key: 41 | for i5 in key: 42 | if i1 not in (i2 + i3 + i4 + i5) and i2 not in (i1 + i3 + i4 + i5) and i3 not in ( 43 | i1 + i2 + i4 + i5) and i4 not in (i1 + i2 + i3 + i5) and i5 not in (i1 + i2 + i3 + i4): 44 | key_res.append(i1 + i2 + i3 + i4 + i5) 45 | for z in range(len(key_res)): 46 | key = key_res[z] 47 | table = [['', key[0], key[1], key[2], key[3], key[4]], [key[0], 'a', 'b', 'c', 'd', 'e'], 48 | [key[1], 'f', 'g', 'h', 'i', 'k'], [key[2], 'l', 'm', 'n', 'o', 'p'], 49 | [key[3], 'q', 'r', 's', 't', 'u'], [key[4], 'v', 'w', 'x', 'y', 'z']] 50 | for i in cip_res: 51 | for j in range(len(table[0])): 52 | # 记录第一个下标 53 | if i[0] == table[0][j]: 54 | a = j 55 | # 记录第二个下标 56 | if i[1] == table[0][j]: 57 | b = j 58 | s = table[a][b] 59 | pla.append(s) 60 | j = 0 61 | for i in range(0, len(pla), len(cip_res)): 62 | # f.write("秘钥:" + key_res[j] + " ") 63 | # print(key_res[j]) 64 | flag = ''.join(pla[i:i + len(cip_res)]) 65 | # f.write("明文:" + ''.join(pla[i:i + len(cip_res)])) 66 | if temp == key_res[j]: 67 | break 68 | # f.write('\n') 69 | j = j + 1 70 | return flag 71 | 72 | def main(): 73 | # 只能有英文 74 | pla = input("请输入需要加密的字符串:") 75 | key = input("请输入秘钥:") 76 | # 密钥只能有5位,英文 77 | print(encrypt(pla, key)) 78 | cip = input("请输入需要解密的密文:") 79 | print(decrypt(cip, key)) 80 | 81 | if __name__ == '__main__': 82 | main() 83 | -------------------------------------------------------------------------------- /algorithm/stream_cipher/rc4_cipher.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import codecs 4 | 5 | 6 | class RC4: 7 | 8 | def KSA(self, key): 9 | # Key Scheduling Algorithm 10 | len_key = len(key) 11 | S = list(range(256)) 12 | # S = [0,1,2, ... , 255] 13 | j = 0 14 | for i in range(256): 15 | j = (j + S[i] + key[i % len_key]) % 256 16 | S[i], S[j] = S[j], S[i] 17 | return S 18 | 19 | def PRGA(self, S): 20 | i = 0 21 | j = 0 22 | K = [] 23 | while True: 24 | i = (i + 1) % 256 25 | j = (j + S[i]) % 256 26 | S[i], S[j] = S[j], S[i] 27 | K = S[(S[i] + S[j]) % 256] 28 | yield K 29 | 30 | def get_keystream(self, key): 31 | S = self.KSA(key) 32 | return self.PRGA(S) 33 | 34 | def encrypt_logic(self, key, text): 35 | key = [ord(c) for c in key] 36 | keystream = self.get_keystream(key) 37 | res = [] 38 | for c in text: 39 | val = ("%02X" % (c ^ next(keystream))) 40 | res.append(val) 41 | return ''.join(res) 42 | 43 | def encrypt(self, key, plaintext): 44 | plaintext = [ord(c) for c in plaintext] 45 | return self.encrypt_logic(key, plaintext) 46 | 47 | def decrypt(self, key, ciphertext): 48 | ciphertext = codecs.decode(ciphertext, 'hex_codec') 49 | res = self.encrypt_logic(key, ciphertext) 50 | return codecs.decode(res, 'hex_codec').decode('utf-8') 51 | 52 | def encrypt_file(self, file_plain, file_ciphered, key): 53 | with open(file_plain, 'r') as myfile: 54 | lines = myfile.readlines() 55 | with open(file_ciphered, 'w') as myfile: 56 | for plaintext in lines: 57 | plaintext = [ord(c) for c in plaintext.replace('\n', '')] 58 | ciphertext = self.encrypt_logic(key, plaintext) 59 | myfile.write(ciphertext + '\n') 60 | 61 | def decrypt_file(self, file_plain, file_ciphered, key): 62 | with open(file_ciphered, 'r') as myfile: 63 | lines = myfile.readlines() 64 | with open(file_plain, 'w') as myfile: 65 | for ciphertext in lines: 66 | ciphertext = codecs.decode(ciphertext.replace('\n', ''), 'hex_codec') 67 | res = self.encrypt_logic(key, ciphertext) 68 | decrptedtext = codecs.decode(res, 'hex_codec').decode('utf-8') 69 | myfile.write(decrptedtext + '\n') 70 | 71 | 72 | def main(): 73 | rc_instance = RC4() 74 | key = 'my-rc4-key' 75 | plaintext = 'An apple a day keeps the doctor away' 76 | ciphertext = rc_instance.encrypt(key, plaintext) 77 | print('明文:', plaintext) 78 | print('加密后的密文:', ciphertext) 79 | print('重新解密得到的明文:', rc_instance.decrypt(key, ciphertext)) 80 | print('从明文.txt开始加密') 81 | rc_instance.encrypt_file('明文.txt', '密文.txt', key) 82 | print('密文.txt生成成功') 83 | print('从密文.txt开始解密') 84 | rc_instance.decrypt_file('明文.txt', '密文.txt', key) 85 | print('明文.txt生成成功') 86 | 87 | 88 | if __name__ == '__main__': 89 | main() 90 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/double_transposition_cipher.py: -------------------------------------------------------------------------------- 1 | def single_transposition(plaintext, key): # 单次置换(双重置换由两次单次置换组成) 2 | col_count = len(key) 3 | sorted_index = [0 for _ in range(col_count)] 4 | plain_len = len(plaintext) 5 | rem = plain_len % col_count 6 | # 计算行数 7 | if rem == 0: 8 | row_count = int(plain_len / col_count) 9 | else: 10 | row_count = int(plain_len / col_count) + 1 11 | matrix = [([0] * col_count) for _ in range(row_count)] 12 | t = 0 # 矩阵填充游标 13 | for x in range(row_count): 14 | for y in range(col_count): 15 | if t < plain_len: 16 | matrix[x][y] = plaintext[t] 17 | t += 1 18 | else: 19 | matrix[x][y] = '+' 20 | # 按密钥字符大小排序得到列序 21 | for x in range(col_count): 22 | for y in range(col_count): 23 | if x == y: 24 | sorted_index[x] += 1 25 | continue 26 | if ord(key[x]) > ord(key[y]): 27 | sorted_index[x] += 1 28 | if ord(key[x]) < ord(key[y]): 29 | continue 30 | if (ord(key[x]) == ord(key[y])) and (x > y): 31 | sorted_index[x] += 1 32 | # 读取按列序排列的密文 33 | column_buffer = [0 for _ in range(row_count * col_count)] 34 | t = 0 35 | for i in range(col_count): 36 | for j in range(row_count): 37 | column_buffer[t] = matrix[j][sorted_index[i] - 1] 38 | t += 1 39 | ciphertext_str = '' 40 | for i in range(len(column_buffer)): 41 | ciphertext_str += str(column_buffer[i]) 42 | return ciphertext_str 43 | 44 | def single_transposition_decrypt(ciphertext, key): # 单次置换解密 45 | col_count = len(key) 46 | sorted_index = [0 for _ in range(col_count)] 47 | plain_len = len(ciphertext) 48 | rem = plain_len % col_count 49 | if rem == 0: 50 | row_count = int(plain_len / col_count) 51 | else: 52 | row_count = int(plain_len / col_count) + 1 53 | # 计算列序 54 | for x in range(col_count): 55 | for y in range(col_count): 56 | if x == y: 57 | sorted_index[x] += 1 58 | continue 59 | if ord(key[x]) > ord(key[y]): 60 | sorted_index[x] += 1 61 | if ord(key[x]) < ord(key[y]): 62 | continue 63 | if (ord(key[x]) == ord(key[y])) and (x > y): 64 | sorted_index[x] += 1 65 | column_buffer = [0 for _ in range(row_count * col_count)] 66 | for i in range(len(ciphertext)): 67 | column_buffer[i] = ciphertext[i] 68 | # 回填矩阵以恢复原列序 69 | matrix_dec = [([0] * col_count) for _ in range(row_count)] 70 | t = 0 71 | for i in range(col_count): 72 | for j in range(row_count): 73 | matrix_dec[j][sorted_index[i] - 1] = column_buffer[t] 74 | t += 1 75 | plaintext_str = '' 76 | for i in range(row_count): 77 | for j in range(col_count): 78 | plaintext_str += str(matrix_dec[i][j]) 79 | return plaintext_str 80 | 81 | def encrypt(plaintext, key1, key2): 82 | first_pass = single_transposition(plaintext, key1) 83 | second_pass = single_transposition(first_pass, key2) 84 | return second_pass 85 | 86 | def decrypt(ciphertext, key2, key1): 87 | first_pass = single_transposition_decrypt(ciphertext, key2) 88 | t = 0 89 | lens = len(first_pass) 90 | for i in range(lens): 91 | if first_pass[lens - 1 - i] == '0': 92 | t += 1 93 | else: 94 | break 95 | trimmed = first_pass[0:lens - t] 96 | second_pass = single_transposition_decrypt(trimmed, key1) 97 | return second_pass.replace('0', '') 98 | 99 | def main(): 100 | print(encrypt("encryptionalgorithms", "dbaasdfc", "abcd")) 101 | print(decrypt("yatio0gmni0r0en0tlcohprs", "abcd", "dbaasdfc")) 102 | 103 | if __name__ == "__main__": 104 | main() 105 | -------------------------------------------------------------------------------- /algorithm/classical_cipher/autokey_ciphertext_cipher.py: -------------------------------------------------------------------------------- 1 | def vigenere_encrypt(plaintext, key): 2 | # 生成 A-Z 的 26×26 维吉尼亚矩阵,用于按行列索引查找替换字符 3 | matrix = [([0] * 26) for _ in range(26)] 4 | for x in range(26): 5 | for y in range(26): 6 | t = 65 + y + x 7 | if t > 90: 8 | matrix[x][y] = chr(t - 26) 9 | else: 10 | matrix[x][y] = chr(t) 11 | 12 | # for x in range(26): # 矩阵输出 13 | # for y in range(26): 14 | # print(matrix[x][y], end='') 15 | # if y == 25: 16 | # print(' ') 17 | uppercase_key = '' # 将密钥规范为大写形式 18 | for ch in key: 19 | if ord(ch) >= 97: 20 | ch = chr(ord(ch) - 32) 21 | uppercase_key += ch 22 | # print("明文为:" + plaintext) 23 | # print("密钥为:" + key1) 24 | textsize = len(plaintext) 25 | keysize = len(key) 26 | pair_matrix = [([0] * 2) for _ in range(textsize)] # 明文与密钥逐字符配对 27 | 28 | keytext = '' 29 | t = 0 # 逐字符配对游标 30 | for i in range(textsize): 31 | t = t % keysize 32 | pair_matrix[i][0] = plaintext[i] 33 | pair_matrix[i][1] = uppercase_key[t] 34 | t = t + 1 35 | # print("加密一对一矩阵: ", end='') 36 | # print(pkmat) # 至此,对照表完成,接下来进行转换 37 | for i in range(textsize): 38 | if ord(pair_matrix[i][0]) >= 97: # 明文为小写 39 | t = ord(pair_matrix[i][0]) - 97 40 | x = ord(pair_matrix[i][1]) - 65 41 | keytext += chr(ord(matrix[t][x]) + 32) 42 | else: # 明文为大写 43 | t = ord(pair_matrix[i][0]) - 65 44 | x = ord(pair_matrix[i][1]) - 65 45 | keytext += chr(ord(matrix[t][x])) 46 | return keytext 47 | 48 | def vigenere_decrypt(ciphertext, key): 49 | # 生成 A-Z 的 26×26 维吉尼亚矩阵 50 | matrix = [([0] * 26) for _ in range(26)] 51 | for x in range(26): 52 | for y in range(26): 53 | t = 65 + y + x 54 | if t > 90: 55 | matrix[x][y] = chr(t - 26) 56 | else: 57 | matrix[x][y] = chr(t) 58 | keysize = len(key) 59 | textsize = len(ciphertext) 60 | pair_matrix = [([0] * 2) for _ in range(textsize)] # 密文与密钥逐字符配对 61 | t = 0 # 逐字符配对游标 62 | for i in range(textsize): 63 | t = t % keysize 64 | pair_matrix[i][0] = ciphertext[i] 65 | pair_matrix[i][1] = key[t] 66 | t = t + 1 67 | plaintext_out = '' 68 | for i in range(textsize): # 解密过程,区分大小写 69 | for x in range(26): 70 | if ord(pair_matrix[i][0]) < 97: # 密文为大写 71 | if ord(pair_matrix[i][1]) <= 90: 72 | y = ord(pair_matrix[i][1]) - 65 73 | else: 74 | y = ord(pair_matrix[i][1]) - 97 75 | if matrix[y][x] == pair_matrix[i][0]: 76 | plaintext_out += chr(x + 65) 77 | break 78 | else: # 密文为小写 79 | if ord(pair_matrix[i][1]) <= 90: 80 | y = ord(pair_matrix[i][1]) - 65 81 | else: 82 | y = ord(pair_matrix[i][1]) - 97 83 | if matrix[y][x] == chr(ord(pair_matrix[i][0]) - 32): 84 | plaintext_out += chr(x + 97) 85 | break 86 | return plaintext_out 87 | 88 | def encrypt(plaintext, key): 89 | # Autokey(密文模式):扩展密钥为 key + 明文前段,使长度匹配 90 | len1 = len(plaintext) 91 | len2 = len(key) 92 | extended_key = key + plaintext[0:len1 - len2] 93 | ciphertext = vigenere_encrypt(plaintext, extended_key) 94 | return ciphertext 95 | 96 | def decrypt(ciphertext, key): 97 | # Autokey(密文模式)解密:分段生成明文并逐步扩展密钥 98 | len1 = len(ciphertext) 99 | len2 = len(key) 100 | t = int(len1 / len2) 101 | z = len1 % len2 102 | plaintext = '' 103 | current_key = key 104 | for i in range(t): 105 | current_key = vigenere_decrypt(ciphertext[i * len2:(i + 1) * len2], current_key) 106 | print(current_key) 107 | plaintext += current_key 108 | tail = vigenere_decrypt(ciphertext[len1 - z:len1], current_key[:z]) 109 | plaintext += tail 110 | return plaintext 111 | 112 | def main(): 113 | # 示例: 114 | print(encrypt("anautokeycipherprovidedesalongkeyword", "cap")) 115 | print(decrypt("cnpugoexmmmnjmgwvfkzrzlhwdpgnryregspz", "cap")) 116 | 117 | if __name__ == "__main__": 118 | main() 119 | -------------------------------------------------------------------------------- /algorithm/public_cipher/ecc/sm3.py: -------------------------------------------------------------------------------- 1 | import binascii 2 | from math import ceil 3 | 4 | from algorithm.public_cipher.ecc.func import rotl 5 | 6 | IV = [ 7 | 1937774191, 1226093241, 388252375, 3666478592, 8 | 2842636476, 372324522, 3817729613, 2969243214, 9 | ] 10 | 11 | T_j = [ 12 | 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 13 | 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 2043430169, 14 | 2043430169, 2043430169, 2043430169, 2043430169, 2055708042, 2055708042, 15 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 16 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 17 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 18 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 19 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 20 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 21 | 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 2055708042, 22 | 2055708042, 2055708042, 2055708042, 2055708042 23 | ] 24 | 25 | 26 | def sm3_ff_j(x, y, z, j): 27 | if 0 <= j < 16: 28 | ret = x ^ y ^ z 29 | elif 16 <= j < 64: 30 | ret = (x & y) | (x & z) | (y & z) 31 | return ret 32 | 33 | 34 | def sm3_gg_j(x, y, z, j): 35 | if 0 <= j < 16: 36 | ret = x ^ y ^ z 37 | elif 16 <= j < 64: 38 | # ret = (X | Y) & ((2 ** 32 - 1 - X) | Z) 39 | ret = (x & y) | ((~ x) & z) 40 | return ret 41 | 42 | 43 | def sm3_p_0(x): 44 | return x ^ (rotl(x, 9 % 32)) ^ (rotl(x, 17 % 32)) 45 | 46 | 47 | def sm3_p_1(x): 48 | return x ^ (rotl(x, 15 % 32)) ^ (rotl(x, 23 % 32)) 49 | 50 | 51 | def sm3_cf(v_i, b_i): 52 | w = [] 53 | for i in range(16): 54 | weight = 0x1000000 55 | data = 0 56 | for k in range(i * 4, (i + 1) * 4): 57 | data = data + b_i[k] * weight 58 | weight = int(weight / 0x100) 59 | w.append(data) 60 | 61 | for j in range(16, 68): 62 | w.append(0) 63 | w[j] = sm3_p_1(w[j - 16] ^ w[j - 9] ^ (rotl(w[j - 3], 15 % 32))) ^ (rotl(w[j - 13], 7 % 32)) ^ w[j - 6] 64 | str1 = "%08x" % w[j] 65 | w_1 = [] 66 | for j in range(0, 64): 67 | w_1.append(0) 68 | w_1[j] = w[j] ^ w[j + 4] 69 | str1 = "%08x" % w_1[j] 70 | 71 | a, b, c, d, e, f, g, h = v_i 72 | 73 | for j in range(0, 64): 74 | ss_1 = rotl( 75 | ((rotl(a, 12 % 32)) + 76 | e + 77 | (rotl(T_j[j], j % 32))) & 0xffffffff, 7 % 32 78 | ) 79 | ss_2 = ss_1 ^ (rotl(a, 12 % 32)) 80 | tt_1 = (sm3_ff_j(a, b, c, j) + d + ss_2 + w_1[j]) & 0xffffffff 81 | tt_2 = (sm3_gg_j(e, f, g, j) + h + ss_1 + w[j]) & 0xffffffff 82 | d = c 83 | c = rotl(b, 9 % 32) 84 | b = a 85 | a = tt_1 86 | h = g 87 | g = rotl(f, 19 % 32) 88 | f = e 89 | e = sm3_p_0(tt_2) 90 | 91 | a, b, c, d, e, f, g, h = map( 92 | lambda x: x & 0xFFFFFFFF, [a, b, c, d, e, f, g, h]) 93 | 94 | v_j = [a, b, c, d, e, f, g, h] 95 | return [v_j[i] ^ v_i[i] for i in range(8)] 96 | 97 | 98 | def sm3_hash(msg): 99 | # print(msg) 100 | len1 = len(msg) 101 | reserve1 = len1 % 64 102 | msg.append(0x80) 103 | reserve1 = reserve1 + 1 104 | # 56-64, add 64 byte 105 | range_end = 56 106 | if reserve1 > range_end: 107 | range_end = range_end + 64 108 | 109 | for i in range(reserve1, range_end): 110 | msg.append(0x00) 111 | 112 | bit_length = len1 * 8 113 | bit_length_str = [bit_length % 0x100] 114 | for i in range(7): 115 | bit_length = int(bit_length / 0x100) 116 | bit_length_str.append(bit_length % 0x100) 117 | for i in range(8): 118 | msg.append(bit_length_str[7 - i]) 119 | 120 | group_count = round(len(msg) / 64) 121 | 122 | B = [] 123 | for i in range(0, group_count): 124 | B.append(msg[i * 64:(i + 1) * 64]) 125 | 126 | V = [IV] 127 | for i in range(0, group_count): 128 | V.append(sm3_cf(V[i], B[i])) 129 | 130 | y = V[i + 1] 131 | result = "" 132 | for i in y: 133 | result = '%s%08x' % (result, i) 134 | return result 135 | 136 | 137 | def sm3_kdf(z, klen): # z为16进制表示的比特串(str),klen为密钥长度(单位byte) 138 | klen = int(klen) 139 | ct = 0x00000001 140 | rcnt = ceil(klen / 32) 141 | zin = [i for i in bytes.fromhex(z.decode('utf8'))] 142 | ha = "" 143 | for i in range(rcnt): 144 | msg = zin + [i for i in binascii.a2b_hex(('%08x' % ct).encode('utf8'))] 145 | ha = ha + sm3_hash(msg) 146 | ct += 1 147 | return ha[0: klen * 2] 148 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # 密码学图形界面工具(cryptography-gui-tool) 2 | 3 | 英文版:[English README](README.md) 4 | 5 | > 没有进行性能优化,加密大于1MB的文件可能会导致界面长时间冻结。 6 | 7 | ## 简介 8 | 9 | - 一个基于 PyQt5 的图形化密码学工具,支持字符串与文件的加密、解密,以及 MD5 摘要。 10 | - 算法库与 GUI 解耦,`algorithm` 目录下的实现可单独作为库使用。 11 | - 当前版本未做性能优化,处理大文件时界面可能卡顿;建议用于演示与教学或小型数据。 12 | 13 | ## 功能特性 14 | 15 | - 覆盖 11 种经典密码、2 种流密码、2 种分组密码、2 种公钥密码、1 种哈希算法。 16 | - 同时支持“字符串模式”和“文件模式”的加/解密。 17 | - 提供密钥导入/导出、明文导入、密文导出、密钥显示切换、默认输出路径等实用功能。 18 | 19 | ### 支持的算法与密钥要求 20 | 21 | 经典密码(字符串): 22 | 23 | - 凯撒(Caesar):密钥为整数偏移量。 24 | - 关键词(Keyword):密钥为字符串关键词。 25 | - 仿射(Affine):密钥为两个整数 `a b`(用空格分隔),且 `a` 与 26 互素(不可为偶数或 13 的倍数)。 26 | - 多表(Multilateral):密钥为字符串。 27 | - 维吉尼亚(Vigenere):密钥为字符串。 28 | - 自动密钥·密文(Autokey Ciphertext):密钥为字符串;推荐密钥长度大于明文长度。 29 | - 自动密钥·明文(Autokey Plaintext):密钥为字符串。 30 | - 普莱菲尔(Playfair):密钥为字符串。 31 | - 置换(Permutation):密钥为字符串。 32 | - 列置换(Column Permutation):密钥为字符串;加密前会去除明文中的空格。 33 | - 双重置换(Double-Transposition):密钥为两个字符串,用一个空格分隔。 34 | 35 | 流密码(字符串与文件): 36 | 37 | - RC4:密钥为字符串。 38 | - CA:密钥为整数,范围 `0-255`。 39 | 40 | 分组密码(字符串与文件): 41 | 42 | - DES-64:密钥长度需为 8 个字符。 43 | - AES-64:密钥长度需为 8 个字符(当前实现如此要求)。 44 | 45 | 公钥密码(字符串与文件): 46 | 47 | - RSA:支持生成密钥对;公钥文件保存为 `rsa_public_key_<随机>.txt`(两行:`e` 与 `n`),私钥(`d`)显示在界面并可导出。 48 | - ECC:支持生成密钥对;公钥文件保存为 `ecc_public_key_<随机>.txt`(两行:椭圆曲线点 `x`、`y`),私钥显示在界面并可导出。 49 | 50 | 哈希算法: 51 | 52 | - MD5:支持对字符串或文件生成 MD5;同一时刻仅能选择其一。 53 | 54 | ## 运行环境 55 | 56 | - Python 3.x 57 | - 依赖见 `requirements.txt`:`pyqt5`、`pyqt5-qt5`、`pyqt5-sip` 58 | 59 | ## 安装与启动 60 | 61 | 推荐使用虚拟环境: 62 | 63 | ```bash 64 | # 1) 创建虚拟环境 65 | python -m venv .env 66 | 67 | # 2) 激活虚拟环境 68 | # Windows (cmd) 69 | .\.env\Scripts\activate.bat 70 | # Windows (PowerShell) 71 | .\.env\Scripts\Activate.ps1 72 | # Linux / macOS 73 | source ./.env/bin/activate 74 | 75 | # 3) 安装依赖并启动 76 | pip install -r requirements.txt 77 | python3 main.py 78 | ``` 79 | 80 | 使用 `uv`(推荐): 81 | 82 | ```bash 83 | # 安装(macOS 推荐) 84 | brew install uv 85 | # 或通用脚本 86 | curl -LsSf https://astral.sh/uv/install.sh | sh 87 | 88 | # 创建虚拟环境并安装依赖 89 | uv venv 90 | source .venv/bin/activate 91 | uv pip install -r requirements.txt 92 | 93 | # 运行 GUI 程序(可不激活环境直接运行) 94 | uv run python main.py 95 | ``` 96 | 97 | ## 图形界面使用指南 98 | 99 | 界面布局: 100 | 101 | - 左侧为算法分类切换(经典密码、流密码、分组密码、公钥密码、哈希、关于)。 102 | - 右侧包含“有密钥/字符串/文件”等页签和输入框、按钮、状态栏提示。 103 | 104 | 通用操作: 105 | 106 | - 密钥显示:勾选“显示密钥”复选框可切换密钥明文显示与隐藏。 107 | - 明文导入:点击“导入明文”选择 UTF-8 文本文件,内容将填入对应文本框。 108 | - 密文导出:点击“导出密文”选择目标文件,密文将追加写入。 109 | - 文件输入:点击“导入文件”选择待处理文件。 110 | - 输出路径:点击“保存至”选择输出文件;未设置时,程序将自动在输入文件路径后追加后缀并保存:加密为 `.encrypted`,解密为 `.decrypted`。 111 | - 状态信息:操作完成或失败时,底部状态栏会显示提示信息。 112 | 113 | 示例流程: 114 | 115 | - 字符串加密/解密(以 RC4 为例) 116 | 1. 左侧选择“流密码”→“RC4”。 117 | 2. 在密钥输入框填入字符串密钥。 118 | 3. 在明文框输入内容,点击“加密”;密文将显示在右侧框。 119 | 4. 将密文粘贴至密文框,填入相同密钥,点击“解密”可还原明文。 120 | - 文件加密/解密(以 DES 为例) 121 | 1. 左侧选择“分组密码”→“DES”。 122 | 2. 填入 8 位密钥。 123 | 3. 点击“导入文件”选择输入文件;可选“保存至”指定输出。 124 | 4. 点击“加密”或“解密”;未设置输出时将自动以 `.encrypted` 或 `.decrypted` 后缀保存。 125 | - 公钥密码(以 RSA 为例) 126 | 1. 左侧选择“公钥密码”→“RSA”。 127 | 2. 点击“生成密钥对”;公钥写入 `rsa_public_key_<随机>.txt`,私钥显示在界面。 128 | 3. 字符串模式:在明文框输入内容,点击“加密”;解密时在密文框粘贴密文,保持私钥文本框有值即可。 129 | 4. 文件模式:同理选择输入/输出路径后执行加/解密。 130 | - MD5 131 | 1. 在“哈希”页签下,输入字符串或选择文件(同一时刻仅能选其一)。 132 | 2. 点击“生成 MD5”,结果显示在界面。 133 | 134 | 注意事项: 135 | 136 | - 大文件性能:加密/解密 >1MB 的文件可能导致界面长时间冻结。 137 | - 文本编码:明文文件需为 UTF-8 文本;导入非文本或其他编码将提示失败。 138 | - 密钥规范: 139 | - DES/AES:8 位密钥。 140 | - CA:整数 0-255。 141 | - 仿射:`a b` 且 `a` 与 26 互素。 142 | - 双重置换:两个密钥以空格分隔。 143 | 144 | ## 目录结构 145 | 146 | ``` 147 | . 148 | ├── algorithm # 密码算法实现(可单独作为库使用) 149 | │ ├── block_cipher 150 | │ │ └── aes 151 | │ ├── classical_cipher 152 | │ ├── hash_algorithm 153 | │ ├── public_cipher 154 | │ │ ├── ecc 155 | │ │ └── rsa 156 | │ └── stream_cipher 157 | │ └── ca 158 | ├── assets # 图标与(可选)QSS 样式 159 | │ ├── icons 160 | │ ├── python 161 | │ └── qss 162 | ├── event # GUI 事件绑定与操作流程 163 | ├── ui # GUI 界面定义 164 | ├── test_file # 示例/测试文件 165 | ├── main.py # 程序入口 166 | ├── requirements.txt # 依赖清单 167 | └── pyproject.toml # 项目配置(可选) 168 | ``` 169 | 170 | ## 开发者用法(不依赖 GUI) 171 | 172 | 你可以直接调用 `algorithm` 目录下的实现: 173 | 174 | ```python 175 | # RC4 字符串加/解密 176 | from algorithm.stream_cipher.rc4_cipher import RC4 177 | cipher = RC4() 178 | c = cipher.encrypt('key', 'plaintext') 179 | p = cipher.decrypt('key', c) 180 | 181 | # DES 文件加/解密 182 | from algorithm.block_cipher import des_cipher 183 | desc = des_cipher.DESCipher() 184 | desc.new('12345678') 185 | desc.encrypt_file('input.txt', 'output.encrypted') 186 | desc.decrypt_file('output.encrypted', 'output.decrypted') 187 | 188 | # AES 字符串加/解密 189 | from algorithm.block_cipher.aes import aes_string 190 | c = aes_string.encrypt('hello world', '12345678') 191 | p = aes_string.decrypt(c, '12345678') 192 | 193 | # MD5 194 | from algorithm.hash_algorithm import md5_string, md5_file 195 | md5_s = md5_string.md5('hello') 196 | md5_f = md5_file.md5('path/to/file') 197 | ``` 198 | 199 | ## 常见问题(FAQ) 200 | 201 | - 加密/解密无响应:确认已选择算法分类,并正确填写密钥与输入内容/文件路径。 202 | - 密钥长度错误:分组密码(DES/AES)需 8 位密钥,否则状态栏会提示错误。 203 | - CA 密钥范围:必须是整数且在 0-255 之间。 204 | - 文本导入失败:确保导入的是 UTF-8 文本文件;二进制文件请使用“文件模式”。 205 | 206 | ## 版本与致谢 207 | 208 | - 版本记录:见提交历史与仓库说明。 209 | - 若公开使用此项目,请注明作者:morsuning。 210 | 211 | ## 许可证 212 | 213 | [Mozilla Public License 2.0](https://github.com/morsuning/cryptography-GUItool/blob/master/LICENSE) 214 | 215 | [![Stargazers over time](https://starchart.cc/morsuning/cryptography-GUItool.svg)](https://starchart.cc/morsuning/cryptography-GUItool) -------------------------------------------------------------------------------- /uv.lock: -------------------------------------------------------------------------------- 1 | version = 1 2 | revision = 2 3 | requires-python = ">=3.13" 4 | 5 | [[package]] 6 | name = "cryptography-gui-tool" 7 | version = "0.1.0" 8 | source = { virtual = "." } 9 | dependencies = [ 10 | { name = "pyqt5" }, 11 | ] 12 | 13 | [package.metadata] 14 | requires-dist = [{ name = "pyqt5", specifier = ">=5.15.11" }] 15 | 16 | [[package]] 17 | name = "pyqt5" 18 | version = "5.15.11" 19 | source = { registry = "https://mirrors.ustc.edu.cn/pypi/web/simple" } 20 | dependencies = [ 21 | { name = "pyqt5-qt5" }, 22 | { name = "pyqt5-sip" }, 23 | ] 24 | sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/0e/07/c9ed0bd428df6f87183fca565a79fee19fa7c88c7f00a7f011ab4379e77a/PyQt5-5.15.11.tar.gz", hash = "sha256:fda45743ebb4a27b4b1a51c6d8ef455c4c1b5d610c90d2934c7802b5c1557c52", size = 3216775, upload-time = "2024-07-19T08:39:57.756Z" } 25 | wheels = [ 26 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/11/64/42ec1b0bd72d87f87bde6ceb6869f444d91a2d601f2e67cd05febc0346a1/PyQt5-5.15.11-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c8b03dd9380bb13c804f0bdb0f4956067f281785b5e12303d529f0462f9afdc2", size = 6579776, upload-time = "2024-07-19T08:39:19.775Z" }, 27 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/49/f5/3fb696f4683ea45d68b7e77302eff173493ac81e43d63adb60fa760b9f91/PyQt5-5.15.11-cp38-abi3-macosx_11_0_x86_64.whl", hash = "sha256:6cd75628f6e732b1ffcfe709ab833a0716c0445d7aec8046a48d5843352becb6", size = 7016415, upload-time = "2024-07-19T08:39:32.977Z" }, 28 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/b4/8c/4065950f9d013c4b2e588fe33cf04e564c2322842d84dbcbce5ba1dc28b0/PyQt5-5.15.11-cp38-abi3-manylinux_2_17_x86_64.whl", hash = "sha256:cd672a6738d1ae33ef7d9efa8e6cb0a1525ecf53ec86da80a9e1b6ec38c8d0f1", size = 8188103, upload-time = "2024-07-19T08:39:40.561Z" }, 29 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/f3/f0/ae5a5b4f9b826b29ea4be841b2f2d951bcf5ae1d802f3732b145b57c5355/PyQt5-5.15.11-cp38-abi3-win32.whl", hash = "sha256:76be0322ceda5deecd1708a8d628e698089a1cea80d1a49d242a6d579a40babd", size = 5433308, upload-time = "2024-07-19T08:39:46.932Z" }, 30 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/56/d5/68eb9f3d19ce65df01b6c7b7a577ad3bbc9ab3a5dd3491a4756e71838ec9/PyQt5-5.15.11-cp38-abi3-win_amd64.whl", hash = "sha256:bdde598a3bb95022131a5c9ea62e0a96bd6fb28932cc1619fd7ba211531b7517", size = 6865864, upload-time = "2024-07-19T08:39:53.572Z" }, 31 | ] 32 | 33 | [[package]] 34 | name = "pyqt5-qt5" 35 | version = "5.15.18" 36 | source = { registry = "https://mirrors.ustc.edu.cn/pypi/web/simple" } 37 | wheels = [ 38 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/46/90/bf01ac2132400997a3474051dd680a583381ebf98b2f5d64d4e54138dc42/pyqt5_qt5-5.15.18-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:8bb997eb903afa9da3221a0c9e6eaa00413bbeb4394d5706118ad05375684767", size = 39715743, upload-time = "2025-11-09T12:56:42.936Z" }, 39 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/24/8e/76366484d9f9dbe28e3bdfc688183433a7b82e314216e9b14c89e5fab690/pyqt5_qt5-5.15.18-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c656af9c1e6aaa7f59bf3d8995f2fa09adbf6762b470ed284c31dca80d686a26", size = 36798484, upload-time = "2025-11-09T12:56:59.998Z" }, 40 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/9a/46/ffe177f99f897a59dc237a20059020427bd2d3853d713992b8081933ddfe/pyqt5_qt5-5.15.18-py3-none-manylinux2014_x86_64.whl", hash = "sha256:bf2457e6371969736b4f660a0c153258fa03dbc6a181348218e6f05421682af7", size = 60864590, upload-time = "2025-11-09T12:57:26.724Z" }, 41 | ] 42 | 43 | [[package]] 44 | name = "pyqt5-sip" 45 | version = "12.17.1" 46 | source = { registry = "https://mirrors.ustc.edu.cn/pypi/web/simple" } 47 | sdist = { url = "https://mirrors.ustc.edu.cn/pypi/packages/ea/08/88a20c862f40b5c178c517cdc7e93767967dec5ac1b994e226d517991c9b/pyqt5_sip-12.17.1.tar.gz", hash = "sha256:0eab72bcb628f1926bf5b9ac51259d4fa18e8b2a81d199071135458f7d087ea8", size = 104136, upload-time = "2025-10-08T09:04:19.893Z" } 48 | wheels = [ 49 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/1d/58/9ecb688050e79ffe7bbd9fc917aa13f63856a5081ac46bbce87bb11ab971/pyqt5_sip-12.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9ebbd7769ccdaaa6295e9c872553b6cde17f38e171056f17300d8af9a14d1fc8", size = 124485, upload-time = "2025-10-08T09:04:17.473Z" }, 50 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/b1/9f/ae691360a9f18e3e06fd297e854d7ad175367e35ea184fd2fcf6c79b8c25/pyqt5_sip-12.17.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b023da906a70af2cf5e6fc1932f441ede07530f3e164dd52c6c2bb5ab7c6f424", size = 281923, upload-time = "2025-10-08T09:15:37.004Z" }, 51 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/d7/31/491c45423174a359a4b8a8d84a7b541c453f48497ae928cbe4006bcd3e01/pyqt5_sip-12.17.1-cp313-cp313-win32.whl", hash = "sha256:36dbef482bd638786b909f3bda65b7b3d5cbd6cbf16797496de38bae542da307", size = 49400, upload-time = "2025-10-08T09:11:25.769Z" }, 52 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/64/61/e28681dd5200094f7b2e6671e85c02a4d6693da36d23ad7d39ffbc70b15c/pyqt5_sip-12.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:d04e5551bbc3bcec98acc63b3b0618ddcbf31ff107349225b516fe7e7c0a7c8b", size = 57979, upload-time = "2025-10-08T09:08:37.036Z" }, 53 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/71/f9/06c09dc94474ffe3f518f80e47fc69d34abf8e4a971ae7e7c667d6ff30a7/pyqt5_sip-12.17.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c49918287e1ad77956d1589f1d3d432a0be7630c646ea02cf652413a48e14458", size = 124400, upload-time = "2025-10-08T08:38:23.927Z" }, 54 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/40/ae/be6e338ea427deac5cd81a93f51ae3fb6505d99d6d5e5d5341bcc099327e/pyqt5_sip-12.17.1-cp314-cp314-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:944a4bf1e1ee18ad03a54964c1c6433fb6de582313a1f0b17673e7203e22fc83", size = 282291, upload-time = "2025-10-08T08:38:25.735Z" }, 55 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/fc/a3/8b758518bd0dd5d1581f7a6d522c9b4d9b58d05087b1d0b4dfaad5376434/pyqt5_sip-12.17.1-cp314-cp314-win32.whl", hash = "sha256:99a2935fd662a67748625b1e6ffa0a2d1f2da068b9df6db04fa59a4a5d4ee613", size = 50578, upload-time = "2025-10-08T08:38:28.72Z" }, 56 | { url = "https://mirrors.ustc.edu.cn/pypi/packages/40/8c/e96f9877548810b1e537f46fc21ba74552dd4e8c498658114a8353bdf659/pyqt5_sip-12.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:aaa33232cc80793d14fdb3b149b27eec0855612ed66aad480add5ac49b9cee63", size = 59763, upload-time = "2025-10-08T08:38:27.443Z" }, 57 | ] 58 | -------------------------------------------------------------------------------- /algorithm/public_cipher/rsa/rsa.py: -------------------------------------------------------------------------------- 1 | import binascii # 二进制和ASCII之间转换 2 | from os import urandom # 系统随机的字符 3 | 4 | flag = False 5 | 6 | 7 | # =========================================== 8 | def Mod_1(x, n): 9 | """取模负1的算法:计算x2= x^-1 (mod n)的值, 10 | r = gcd(a, b) = ia + jb, x与n是互素数""" 11 | x0 = x 12 | y0 = n 13 | x1 = 0 14 | y1 = 1 15 | x2 = 1 16 | y2 = 0 17 | while n != 0: 18 | q = x // n 19 | (x, n) = (n, x % n) 20 | (x1, x2) = ((x2 - (q * x1)), x1) 21 | (y1, y2) = ((y2 - (q * y1)), y1) 22 | if x2 < 0: 23 | x2 += y0 24 | if y2 < 0: 25 | y2 += x0 26 | return x2 27 | 28 | 29 | # =========================================== 30 | def Fast_Mod(a, p, m): 31 | """快速取模指数算法:计算 (a ^ p) % m 的值,可用pow()代替""" 32 | a, p, m = int(a), int(p), int(m) 33 | if p == 0: 34 | return 1 35 | r = a % m 36 | k = 1 37 | while p > 1: 38 | if (p & 1) != 0: 39 | k = (k * r) % m 40 | r = (r * r) % m 41 | p >>= 1 42 | return (r * k) % m 43 | 44 | 45 | # =========================================== 46 | def randint(n): 47 | """random是伪随机数,需要更高安全的随机数产生, 48 | 所以使用os.urandom()或者SystmeRandom模块, 49 | 生成n字节的随机数(8位/字节),返回16进制转为10进制整数返回""" 50 | randomdata = urandom(n) 51 | return int(binascii.hexlify(randomdata), 16) 52 | 53 | 54 | # =========================================== 55 | def primality_testing_1(n): 56 | """测试一,小素数测试,用100以内的小素数检测随机数x, 57 | 可以很大概率排除不是素数,#创建有25个素数的元组""" 58 | small_primes_under_100 = ( 59 | 2, 60 | 3, 61 | 5, 62 | 7, 63 | 11, 64 | 13, 65 | 17, 66 | 19, 67 | 23, 68 | 29, 69 | 31, 70 | 37, 71 | 41, 72 | 43, 73 | 47, 74 | 53, 75 | 59, 76 | 61, 77 | 67, 78 | 71, 79 | 73, 80 | 79, 81 | 83, 82 | 89, 83 | 97, 84 | ) 85 | for y in small_primes_under_100: 86 | if n % y == 0: 87 | return False 88 | return True 89 | 90 | 91 | # =========================================== 92 | def primality_testing_2(n, k): 93 | """测试二,用miller_rabin算法对n进行k次检测""" 94 | if n < 2: 95 | return False 96 | d = n - 1 97 | r = 0 98 | while not (d & 1): 99 | r += 1 100 | d >>= 1 101 | for _ in range(k): 102 | a = randint(120) # 随机数 103 | x = pow(a, d, n) 104 | if x == 1 or x == n - 1: 105 | continue 106 | for _ in range(r - 1): 107 | x = pow(x, 2, n) 108 | if x == 1: 109 | return False 110 | if x == n - 1: 111 | break 112 | else: 113 | return False 114 | return True 115 | 116 | 117 | # =========================================== 118 | def getprime(byte): 119 | while True: 120 | n = randint(byte) 121 | if primality_testing_1(n): 122 | if primality_testing_2(n, 10): 123 | pass 124 | else: 125 | continue 126 | else: 127 | continue 128 | return n 129 | 130 | 131 | # =========================================== 132 | def RSA(): 133 | global flag 134 | message = [] 135 | ciphertext = [] 136 | plaintext = [] 137 | while not flag: 138 | message = [] 139 | ciphertext = [] 140 | plaintext = [] 141 | p = getprime(32) # 1024bit的大整数 142 | q = getprime(32) 143 | while p == q: # 避免p/q值相同 144 | q = getprime(1) 145 | n = p * q # n值公开 146 | OrLa = (p - 1) * (q - 1) # 欧拉函数 147 | e = 524289 148 | """e取e=524289时,其二进制为10000000000000000001""" 149 | d = Mod_1(e, OrLa) 150 | # print('公钥为({0},{1});\n私钥为({2},{3})'.format(n, e, n, d)) 151 | message = "theKingOfNight" 152 | # 从标准输入输出流接收数据,数字化再加解密 153 | message = list(map(ord, message)) 154 | # print('ciphertext数字化:', message) 155 | ciphertext = [] 156 | for x in message: 157 | ciphertext.append(pow(x, e, n)) 158 | # print('ciphertext加密:', ciphertext) 159 | message = ciphertext 160 | plaintext = [] 161 | for x in message: 162 | plaintext.append(pow(x, d, n)) 163 | # print('plaintext解密:', plaintext) 164 | if int(plaintext[0]) <= 256: 165 | flag = True 166 | 167 | # print('公钥为({0},{1});\n私钥为({2},{3})'.format(n, e, n, d)) 168 | # print("p:"+str(p)) 169 | # print("q:"+str(q)) 170 | return e, n, d 171 | 172 | 173 | # =================================================== 174 | def encrypt(e, n, message): 175 | temp = "" 176 | # message = input("输入需要加密的密文") 177 | # 从标准输入输出流接收数据,数字化再加解密 178 | message = list(map(ord, message)) 179 | # print('ciphertext数字化:', message) 180 | ciphertext = [] 181 | for x in message: 182 | ciphertext.append(pow(x, e, n)) 183 | for x in ciphertext: 184 | temp = temp + "," + str(x) 185 | 186 | temp = temp[1:] 187 | # print(temp) 188 | return temp 189 | 190 | 191 | def decrypt(d, n, ciphertext): 192 | message = [] 193 | plaintext = [] 194 | temp = "" 195 | 196 | message = ciphertext.split(",") 197 | for x in message: 198 | plaintext.append(pow(int(x), d, n)) 199 | # print('plaintext解密:', plaintext) 200 | plaintext = list(map(chr, plaintext)) 201 | # print('plaintext字符化:', plaintext) 202 | for i in plaintext: 203 | temp = temp + str(i) 204 | return temp 205 | 206 | 207 | def encode_file(e, n, file_name, encrypted_file_name): 208 | encrpt_file = "encrpt" 209 | # file_name = input("输入当前路径的文件") 210 | # 文件后缀名检测 211 | decrpt_file_name = file_name.split(".")[1] 212 | # 213 | message = [] 214 | plaintext = [] 215 | ciphertext = [] 216 | with open(file_name, "rb") as origin_file: 217 | # 待办:此处读取逐字节数据的实现需要进一步核实 218 | for x in origin_file.read(): 219 | # print(int(x)) 220 | message.append(int(x)) 221 | for x in message: 222 | # print(x) 223 | ciphertext.append(pow(int(x), e, n)) 224 | # 写入加密文件 225 | f = open(encrypted_file_name, "w") 226 | for x in ciphertext: 227 | f.write(str(x) + "\r") 228 | f.close() 229 | return encrpt_file + "." + file_name.split(".")[1] 230 | 231 | 232 | def decode_file(d, n, encode_file, decrypt_file_name=""): 233 | plaintext = [] 234 | with open(encode_file) as f: 235 | for x in f.readlines(): 236 | plaintext.append(pow(int(x), d, n)) 237 | f = open(decrypt_file_name, "wb") 238 | f.write(bytes(plaintext)) 239 | f.close() 240 | 241 | 242 | def main(): 243 | e, n, d = RSA() 244 | print(e) 245 | print(n) 246 | print(d) 247 | # public key e,n 248 | # private key d 249 | # encode_file(e,n,file_name) 250 | cipher_text = encrypt(e, n, "1234567") 251 | print(cipher_text) 252 | print(decrypt(d, n, cipher_text)) 253 | # decode_file(d,n,decode_file()) 254 | 255 | 256 | if __name__ == "__main__": 257 | main() 258 | -------------------------------------------------------------------------------- /algorithm/hash_algorithm/md5_file.py: -------------------------------------------------------------------------------- 1 | def md5(filename): 2 | f1 = open(filename, "rb") 3 | p = f1.read() 4 | x = p.__len__() 5 | plaintext = '' 6 | for i in range(x): 7 | plaintext = plaintext + bin(p[i])[2:].zfill(8) 8 | A = 0x67452301 9 | B = 0xefcdab89 10 | C = 0x98badcfe 11 | D = 0x10325476 12 | bintext = plaintext 13 | # print(bintext) 14 | # print(encrypt(plaintext)) 15 | # print(encrypt(plaintext).__len__()) 16 | t = bintext.__len__() % 512 17 | # print(t) 18 | suffix_bits = bin(bintext.__len__())[2:].zfill(64) 19 | # 最终长度后缀(比特长度,64位) 20 | if t < 448: # 补齐 21 | bintext = bintext + '1' 22 | for i in range(447 - t): 23 | bintext = bintext + '0' 24 | else: 25 | bintext = bintext + '1' 26 | for i in range(959 - t): 27 | bintext = bintext + '0' 28 | 29 | sectext = bintext + suffix_bits # 最终的明文(附加长度后缀) 30 | # print(sectext) 31 | # print(sectext.__len__()) 32 | x = sectext.__len__() / 512 33 | M = [[[0] * 1 for _ in range(16)] for _ in range(int(x))] 34 | M[0][0][0] = 1 35 | for i in range(int(x)): 36 | for j in range(16): 37 | ix = 3 38 | for k in range(1): 39 | x = sectext[i * 512 + j * 32:i * 512 + j * 32 + 32] 40 | y = x[24:32] + x[16:24] + x[8:16] + x[0:8] 41 | # print(hex(int(y,2))) 42 | M[i][j][k] = int(y, 2) 43 | # print(M)#��ʼ����� 44 | 45 | def F(x, y, z): 46 | return (x & y) | ((~x) & z) 47 | 48 | def G(x, y, z): 49 | return (x & z) | (y & (~z)) 50 | 51 | def H(x, y, z): 52 | return x ^ y ^ z 53 | 54 | def I(x, y, z): 55 | return y ^ (x | (~z)) 56 | 57 | def rotate_left(x, z): 58 | x = x & 0xffffffff 59 | y = bin(x).replace('0b', '') 60 | # print(y) 61 | tt = y.__len__() 62 | # print(tt) 63 | if tt < 32: 64 | y = y.zfill(32) 65 | # print(y) 66 | t = y[z:] + y[:z] 67 | return int(t, 2) 68 | else: 69 | x = y[tt - 32:] 70 | # print(x) 71 | t = x[z:] + x[:z] 72 | return int(t, 2) 73 | 74 | def FF(a, b, c, d, M, s, t): 75 | a = b + rotate_left((a + F(b, c, d) + M + t), s) 76 | return a & 0xffffffff 77 | 78 | def GG(a, b, c, d, M, s, t): 79 | a = b + rotate_left((a + G(b, c, d) + M + t), s) 80 | return a & 0xffffffff 81 | 82 | def HH(a, b, c, d, M, s, t): 83 | a = b + rotate_left((a + H(b, c, d) + M + t), s) 84 | return a & 0xffffffff 85 | 86 | def II(a, b, c, d, M, s, t): 87 | a = b + rotate_left((a + I(b, c, d) + M + t), s) 88 | return a & 0xffffffff 89 | 90 | for i in range(int(sectext.__len__() / 512)): 91 | a = A 92 | b = B 93 | c = C 94 | d = D 95 | # ��һ��ѭ�� 96 | a = FF(a, b, c, d, M[i][0][0], 7, 0xd76aa478) 97 | d = FF(d, a, b, c, M[i][1][0], 12, 0xe8c7b756) 98 | c = FF(c, d, a, b, M[i][2][0], 17, 0x242070db) 99 | b = FF(b, c, d, a, M[i][3][0], 22, 0xc1bdceee) 100 | a = FF(a, b, c, d, M[i][4][0], 7, 0xf57c0faf) 101 | d = FF(d, a, b, c, M[i][5][0], 12, 0x4787c62a) 102 | c = FF(c, d, a, b, M[i][6][0], 17, 0xa8304613) 103 | b = FF(b, c, d, a, M[i][7][0], 22, 0xfd469501) 104 | a = FF(a, b, c, d, M[i][8][0], 7, 0x698098d8) 105 | d = FF(d, a, b, c, M[i][9][0], 12, 0x8b44f7af) 106 | c = FF(c, d, a, b, M[i][10][0], 17, 0xffff5bb1) 107 | b = FF(b, c, d, a, M[i][11][0], 22, 0x895cd7be) 108 | a = FF(a, b, c, d, M[i][12][0], 7, 0x6b901122) 109 | d = FF(d, a, b, c, M[i][13][0], 12, 0xfd987193) 110 | c = FF(c, d, a, b, M[i][14][0], 17, 0xa679438e) 111 | b = FF(b, c, d, a, M[i][15][0], 22, 0x49b40821) 112 | # �ڶ���ѭ�� 113 | a = GG(a, b, c, d, M[i][1][0], 5, 0xf61e2562) 114 | d = GG(d, a, b, c, M[i][6][0], 9, 0xc040b340) 115 | c = GG(c, d, a, b, M[i][11][0], 14, 0x265e5a51) 116 | b = GG(b, c, d, a, M[i][0][0], 20, 0xe9b6c7aa) 117 | a = GG(a, b, c, d, M[i][5][0], 5, 0xd62f105d) 118 | d = GG(d, a, b, c, M[i][10][0], 9, 0x02441453) 119 | c = GG(c, d, a, b, M[i][15][0], 14, 0xd8a1e681) 120 | b = GG(b, c, d, a, M[i][4][0], 20, 0xe7d3fbc8) 121 | a = GG(a, b, c, d, M[i][9][0], 5, 0x21e1cde6) 122 | d = GG(d, a, b, c, M[i][14][0], 9, 0xc33707d6) 123 | c = GG(c, d, a, b, M[i][3][0], 14, 0xf4d50d87) 124 | b = GG(b, c, d, a, M[i][8][0], 20, 0x455a14ed) 125 | a = GG(a, b, c, d, M[i][13][0], 5, 0xa9e3e905) 126 | d = GG(d, a, b, c, M[i][2][0], 9, 0xfcefa3f8) 127 | c = GG(c, d, a, b, M[i][7][0], 14, 0x676f02d9) 128 | b = GG(b, c, d, a, M[i][12][0], 20, 0x8d2a4c8a) 129 | # ������ѭ�� 130 | a = HH(a, b, c, d, M[i][5][0], 4, 0xfffa3942) 131 | d = HH(d, a, b, c, M[i][8][0], 11, 0x8771f681) 132 | c = HH(c, d, a, b, M[i][11][0], 16, 0x6d9d6122) 133 | b = HH(b, c, d, a, M[i][14][0], 23, 0xfde5380c) 134 | a = HH(a, b, c, d, M[i][1][0], 4, 0xa4beea44) 135 | d = HH(d, a, b, c, M[i][4][0], 11, 0x4bdecfa9) 136 | c = HH(c, d, a, b, M[i][7][0], 16, 0xf6bb4b60) 137 | b = HH(b, c, d, a, M[i][10][0], 23, 0xbebfbc70) 138 | a = HH(a, b, c, d, M[i][13][0], 4, 0x289b7ec6) 139 | d = HH(d, a, b, c, M[i][0][0], 11, 0xeaa127fa) 140 | c = HH(c, d, a, b, M[i][3][0], 16, 0xd4ef3085) 141 | b = HH(b, c, d, a, M[i][6][0], 23, 0x04881d05) 142 | a = HH(a, b, c, d, M[i][9][0], 4, 0xd9d4d039) 143 | d = HH(d, a, b, c, M[i][12][0], 11, 0xe6db99e5) 144 | c = HH(c, d, a, b, M[i][15][0], 16, 0x1fa27cf8) 145 | b = HH(b, c, d, a, M[i][2][0], 23, 0xc4ac5665) 146 | 147 | # ������ѭ�� 148 | a = II(a, b, c, d, M[i][0][0], 6, 0xf4292244) 149 | d = II(d, a, b, c, M[i][7][0], 10, 0x432aff97) 150 | c = II(c, d, a, b, M[i][14][0], 15, 0xab9423a7) 151 | b = II(b, c, d, a, M[i][5][0], 21, 0xfc93a039) 152 | a = II(a, b, c, d, M[i][12][0], 6, 0x655b59c3) 153 | d = II(d, a, b, c, M[i][3][0], 10, 0x8f0ccc92) 154 | c = II(c, d, a, b, M[i][10][0], 15, 0xffeff47d) 155 | b = II(b, c, d, a, M[i][1][0], 21, 0x85845dd1) 156 | a = II(a, b, c, d, M[i][8][0], 6, 0x6fa87e4f) 157 | d = II(d, a, b, c, M[i][15][0], 10, 0xfe2ce6e0) 158 | c = II(c, d, a, b, M[i][6][0], 15, 0xa3014314) 159 | b = II(b, c, d, a, M[i][13][0], 21, 0x4e0811a1) 160 | a = II(a, b, c, d, M[i][4][0], 6, 0xf7537e82) 161 | d = II(d, a, b, c, M[i][11][0], 10, 0xbd3af235) 162 | c = II(c, d, a, b, M[i][2][0], 15, 0x2ad7d2bb) 163 | b = II(b, c, d, a, M[i][9][0], 21, 0xeb86d391) 164 | A = (A + a) & 0xffffffff 165 | B = (B + b) & 0xffffffff 166 | C = (C + c) & 0xffffffff 167 | D = (D + d) & 0xffffffff 168 | 169 | d = (hex(D)[2:])[6:8] + (hex(D)[2:])[4:6] + (hex(D)[2:])[2:4] + (hex(D)[2:])[0:2] 170 | c = (hex(C)[2:])[6:8] + (hex(C)[2:])[4:6] + (hex(C)[2:])[2:4] + (hex(C)[2:])[0:2] 171 | b = (hex(B)[2:])[6:8] + (hex(B)[2:])[4:6] + (hex(B)[2:])[2:4] + (hex(B)[2:])[0:2] 172 | a = (hex(A)[2:])[6:8] + (hex(A)[2:])[4:6] + (hex(A)[2:])[2:4] + (hex(A)[2:])[0:2] 173 | 174 | return a + b + c + d 175 | 176 | 177 | if __name__ == '__main__': 178 | # 测试 179 | x = md5('upload.png') 180 | print(x) 181 | -------------------------------------------------------------------------------- /algorithm/hash_algorithm/md5_string.py: -------------------------------------------------------------------------------- 1 | def md5(string): 2 | def encode(s): 3 | return ''.join([bin(ord(c)).replace('0b', '').zfill(8) for c in s]) 4 | 5 | def decode(s): 6 | return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]]) 7 | 8 | plaintext = string 9 | # 链接变量 10 | A = 0x67452301 11 | B = 0xefcdab89 12 | C = 0x98badcfe 13 | D = 0x10325476 14 | bintext = encode(plaintext) 15 | # print(encrypt(plaintext)) 16 | # print(encrypt(plaintext).__len__()) 17 | t = bintext.__len__() % 512 18 | # print(t) 19 | suffix_bits = bin(bintext.__len__())[2:].zfill(64) 20 | # 最终长度后缀(比特长度,64位) 21 | if t < 448: # 补齐 22 | bintext = bintext + '1' 23 | for i in range(447 - t): 24 | bintext = bintext + '0' 25 | else: 26 | bintext = bintext + '1' 27 | for i in range(959 - t): 28 | bintext = bintext + '0' 29 | 30 | sectext = bintext + suffix_bits # 最终的明文(附加长度后缀) 31 | # print(sectext) 32 | # print(sectext.__len__()) 33 | x = sectext.__len__() / 512 34 | M = [[[0] * 1 for _ in range(16)] for _ in range(int(x))] 35 | M[0][0][0] = 1 36 | for i in range(int(x)): 37 | for j in range(16): 38 | ix = 3 39 | for k in range(1): 40 | x = sectext[i * 512 + j * 32:i * 512 + j * 32 + 32] 41 | y = x[24:32] + x[16:24] + x[8:16] + x[0:8] 42 | # print(hex(int(y,2))) 43 | M[i][j][k] = int(y, 2) 44 | # print(M)#初始化完成 45 | 46 | def F(x, y, z): 47 | return (x & y) | ((~x) & z) 48 | 49 | def G(x, y, z): 50 | return (x & z) | (y & (~z)) 51 | 52 | def H(x, y, z): 53 | return x ^ y ^ z 54 | 55 | def I(x, y, z): 56 | return y ^ (x | (~z)) 57 | 58 | def rotate_left(x, z): 59 | x = x & 0xffffffff 60 | y = bin(x).replace('0b', '') 61 | # print(y) 62 | tt = y.__len__() 63 | # print(tt) 64 | if tt < 32: 65 | y = y.zfill(32) 66 | # print(y) 67 | t = y[z:] + y[:z] 68 | return int(t, 2) 69 | else: 70 | x = y[tt - 32:] 71 | # print(x) 72 | t = x[z:] + x[:z] 73 | return int(t, 2) 74 | 75 | def FF(a, b, c, d, M, s, t): 76 | a = b + rotate_left((a + F(b, c, d) + M + t), s) 77 | return a & 0xffffffff 78 | 79 | def GG(a, b, c, d, M, s, t): 80 | a = b + rotate_left((a + G(b, c, d) + M + t), s) 81 | return a & 0xffffffff 82 | 83 | def HH(a, b, c, d, M, s, t): 84 | a = b + rotate_left((a + H(b, c, d) + M + t), s) 85 | return a & 0xffffffff 86 | 87 | def II(a, b, c, d, M, s, t): 88 | a = b + rotate_left((a + I(b, c, d) + M + t), s) 89 | return a & 0xffffffff 90 | 91 | for i in range(int(sectext.__len__() / 512)): 92 | a = A 93 | b = B 94 | c = C 95 | d = D 96 | # 第一轮循环 97 | a = FF(a, b, c, d, M[i][0][0], 7, 0xd76aa478) 98 | d = FF(d, a, b, c, M[i][1][0], 12, 0xe8c7b756) 99 | c = FF(c, d, a, b, M[i][2][0], 17, 0x242070db) 100 | b = FF(b, c, d, a, M[i][3][0], 22, 0xc1bdceee) 101 | a = FF(a, b, c, d, M[i][4][0], 7, 0xf57c0faf) 102 | d = FF(d, a, b, c, M[i][5][0], 12, 0x4787c62a) 103 | c = FF(c, d, a, b, M[i][6][0], 17, 0xa8304613) 104 | b = FF(b, c, d, a, M[i][7][0], 22, 0xfd469501) 105 | a = FF(a, b, c, d, M[i][8][0], 7, 0x698098d8) 106 | d = FF(d, a, b, c, M[i][9][0], 12, 0x8b44f7af) 107 | c = FF(c, d, a, b, M[i][10][0], 17, 0xffff5bb1) 108 | b = FF(b, c, d, a, M[i][11][0], 22, 0x895cd7be) 109 | a = FF(a, b, c, d, M[i][12][0], 7, 0x6b901122) 110 | d = FF(d, a, b, c, M[i][13][0], 12, 0xfd987193) 111 | c = FF(c, d, a, b, M[i][14][0], 17, 0xa679438e) 112 | b = FF(b, c, d, a, M[i][15][0], 22, 0x49b40821) 113 | # 第二轮循环 114 | a = GG(a, b, c, d, M[i][1][0], 5, 0xf61e2562) 115 | d = GG(d, a, b, c, M[i][6][0], 9, 0xc040b340) 116 | c = GG(c, d, a, b, M[i][11][0], 14, 0x265e5a51) 117 | b = GG(b, c, d, a, M[i][0][0], 20, 0xe9b6c7aa) 118 | a = GG(a, b, c, d, M[i][5][0], 5, 0xd62f105d) 119 | d = GG(d, a, b, c, M[i][10][0], 9, 0x02441453) 120 | c = GG(c, d, a, b, M[i][15][0], 14, 0xd8a1e681) 121 | b = GG(b, c, d, a, M[i][4][0], 20, 0xe7d3fbc8) 122 | a = GG(a, b, c, d, M[i][9][0], 5, 0x21e1cde6) 123 | d = GG(d, a, b, c, M[i][14][0], 9, 0xc33707d6) 124 | c = GG(c, d, a, b, M[i][3][0], 14, 0xf4d50d87) 125 | b = GG(b, c, d, a, M[i][8][0], 20, 0x455a14ed) 126 | a = GG(a, b, c, d, M[i][13][0], 5, 0xa9e3e905) 127 | d = GG(d, a, b, c, M[i][2][0], 9, 0xfcefa3f8) 128 | c = GG(c, d, a, b, M[i][7][0], 14, 0x676f02d9) 129 | b = GG(b, c, d, a, M[i][12][0], 20, 0x8d2a4c8a) 130 | # 第三轮循环 131 | a = HH(a, b, c, d, M[i][5][0], 4, 0xfffa3942) 132 | d = HH(d, a, b, c, M[i][8][0], 11, 0x8771f681) 133 | c = HH(c, d, a, b, M[i][11][0], 16, 0x6d9d6122) 134 | b = HH(b, c, d, a, M[i][14][0], 23, 0xfde5380c) 135 | a = HH(a, b, c, d, M[i][1][0], 4, 0xa4beea44) 136 | d = HH(d, a, b, c, M[i][4][0], 11, 0x4bdecfa9) 137 | c = HH(c, d, a, b, M[i][7][0], 16, 0xf6bb4b60) 138 | b = HH(b, c, d, a, M[i][10][0], 23, 0xbebfbc70) 139 | a = HH(a, b, c, d, M[i][13][0], 4, 0x289b7ec6) 140 | d = HH(d, a, b, c, M[i][0][0], 11, 0xeaa127fa) 141 | c = HH(c, d, a, b, M[i][3][0], 16, 0xd4ef3085) 142 | b = HH(b, c, d, a, M[i][6][0], 23, 0x04881d05) 143 | a = HH(a, b, c, d, M[i][9][0], 4, 0xd9d4d039) 144 | d = HH(d, a, b, c, M[i][12][0], 11, 0xe6db99e5) 145 | c = HH(c, d, a, b, M[i][15][0], 16, 0x1fa27cf8) 146 | b = HH(b, c, d, a, M[i][2][0], 23, 0xc4ac5665) 147 | 148 | # 第四轮循环 149 | a = II(a, b, c, d, M[i][0][0], 6, 0xf4292244) 150 | d = II(d, a, b, c, M[i][7][0], 10, 0x432aff97) 151 | c = II(c, d, a, b, M[i][14][0], 15, 0xab9423a7) 152 | b = II(b, c, d, a, M[i][5][0], 21, 0xfc93a039) 153 | a = II(a, b, c, d, M[i][12][0], 6, 0x655b59c3) 154 | d = II(d, a, b, c, M[i][3][0], 10, 0x8f0ccc92) 155 | c = II(c, d, a, b, M[i][10][0], 15, 0xffeff47d) 156 | b = II(b, c, d, a, M[i][1][0], 21, 0x85845dd1) 157 | a = II(a, b, c, d, M[i][8][0], 6, 0x6fa87e4f) 158 | d = II(d, a, b, c, M[i][15][0], 10, 0xfe2ce6e0) 159 | c = II(c, d, a, b, M[i][6][0], 15, 0xa3014314) 160 | b = II(b, c, d, a, M[i][13][0], 21, 0x4e0811a1) 161 | a = II(a, b, c, d, M[i][4][0], 6, 0xf7537e82) 162 | d = II(d, a, b, c, M[i][11][0], 10, 0xbd3af235) 163 | c = II(c, d, a, b, M[i][2][0], 15, 0x2ad7d2bb) 164 | b = II(b, c, d, a, M[i][9][0], 21, 0xeb86d391) 165 | A = (A + a) & 0xffffffff 166 | B = (B + b) & 0xffffffff 167 | C = (C + c) & 0xffffffff 168 | D = (D + d) & 0xffffffff 169 | 170 | d = (hex(D)[2:])[6:8] + (hex(D)[2:])[4:6] + (hex(D)[2:])[2:4] + (hex(D)[2:])[0:2] 171 | c = (hex(C)[2:])[6:8] + (hex(C)[2:])[4:6] + (hex(C)[2:])[2:4] + (hex(C)[2:])[0:2] 172 | b = (hex(B)[2:])[6:8] + (hex(B)[2:])[4:6] + (hex(B)[2:])[2:4] + (hex(B)[2:])[0:2] 173 | a = (hex(A)[2:])[6:8] + (hex(A)[2:])[4:6] + (hex(A)[2:])[2:4] + (hex(A)[2:])[0:2] 174 | return a + b + c + d 175 | 176 | 177 | if __name__ == '__main__': 178 | digest = md5('128778877') 179 | print(digest) 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cryptography GUI Tool (cryptography-gui-tool) 2 | 3 | Chinese version: [中文文档](README_CN.md) 4 | 5 | ## Overview 6 | 7 | - A PyQt5-based graphical cryptography tool that supports encrypting and decrypting strings and files, plus MD5 digests. 8 | - The algorithm library is decoupled from the GUI. Implementations under `algorithm` can be used as a standalone library. 9 | - No performance optimization at present. Processing large files may freeze the UI. Recommended for demos, teaching, or small data. 10 | 11 | ## Features 12 | 13 | - Covers 11 classical ciphers, 2 stream ciphers, 2 block ciphers, 2 public-key ciphers, and 1 hash algorithm. 14 | - Supports both “String mode” and “File mode” for encryption and decryption. 15 | - Offers key import/export, plaintext import, ciphertext export, key visibility toggle, and default output path convenience. 16 | 17 | ### Supported Algorithms and Key Requirements 18 | 19 | Classical ciphers (string): 20 | 21 | - Caesar: key is an integer shift. 22 | - Keyword: key is a keyword string. 23 | - Affine: key is two integers `a b` (space separated); `a` must be coprime to 26 (not even and not a multiple of 13). 24 | - Multilateral: key is a string. 25 | - Vigenere: key is a string. 26 | - Autokey Ciphertext: key is a string; recommended key length greater than plaintext length. 27 | - Autokey Plaintext: key is a string. 28 | - Playfair: key is a string. 29 | - Permutation: key is a string. 30 | - Column Permutation: key is a string; spaces in plaintext are removed before encryption. 31 | - Double-Transposition: key is two strings separated by a single space. 32 | 33 | Stream ciphers (string and file): 34 | 35 | - RC4: key is a string. 36 | - CA: key is an integer in `0–255`. 37 | 38 | Block ciphers (string and file): 39 | 40 | - DES-64: key must be 8 characters long. 41 | - AES-64: key must be 8 characters long (per current implementation). 42 | 43 | Public-key ciphers (string and file): 44 | 45 | - RSA: supports keypair generation; public key is saved as `rsa_public_key_.txt` (two lines: `e` and `n`); private key (`d`) is shown in the UI and can be exported. 46 | - ECC: supports keypair generation; public key is saved as `ecc_public_key_.txt` (two lines: point `x` and `y`); private key is shown in the UI and can be exported. 47 | 48 | Hash: 49 | 50 | - MD5: supports generating MD5 for either a string or a file; only one can be chosen at a time. 51 | 52 | ## Environment 53 | 54 | - Python 3.x 55 | - Dependencies in `requirements.txt`: `pyqt5`, `pyqt5-qt5`, `pyqt5-sip` 56 | 57 | ## Installation and Run 58 | 59 | Recommended: virtual environment 60 | 61 | ```bash 62 | # 1) Create venv 63 | python -m venv .env 64 | 65 | # 2) Activate 66 | # Windows (cmd) 67 | .\.env\Scripts\activate.bat 68 | # Windows (PowerShell) 69 | .\.env\Scripts\Activate.ps1 70 | # Linux / macOS 71 | source ./.env/bin/activate 72 | 73 | # 3) Install and start 74 | pip install -r requirements.txt 75 | python3 main.py 76 | ``` 77 | 78 | Using `uv` (recommended): 79 | 80 | ```bash 81 | # Install (macOS recommended) 82 | brew install uv 83 | # Or generic script 84 | curl -LsSf https://astral.sh/uv/install.sh | sh 85 | 86 | # Create venv and install deps 87 | uv venv 88 | source .venv/bin/activate 89 | uv pip install -r requirements.txt 90 | 91 | # Run GUI (can run without activating the venv) 92 | uv run python main.py 93 | ``` 94 | 95 | ## GUI Usage Guide 96 | 97 | Layout: 98 | 99 | - Left: algorithm categories (Classical, Stream, Block, Public-key, Hash, About). 100 | - Right: tabs for “with key / string / file”, inputs, buttons, and a status bar. 101 | 102 | Common operations: 103 | 104 | - Toggle key visibility via the checkbox. 105 | - Import plaintext from a UTF-8 text file. 106 | - Export ciphertext to a chosen file (appended). 107 | - Import input file for file mode. 108 | - Choose output path; if not set, the program will save to the input path with a suffix: `.encrypted` for encryption and `.decrypted` for decryption. 109 | - Watch the status bar for success/error messages. 110 | 111 | Example flows: 112 | 113 | - String encrypt/decrypt (RC4) 114 | 1. Select “Stream” → “RC4”. 115 | 2. Enter a string key. 116 | 3. Enter plaintext and click “Encrypt”; ciphertext appears on the right. 117 | 4. Paste ciphertext back, use the same key, click “Decrypt” to restore plaintext. 118 | - File encrypt/decrypt (DES) 119 | 1. Select “Block” → “DES”. 120 | 2. Use an 8-character key. 121 | 3. Import the input file; optionally set output path. 122 | 4. Click “Encrypt” or “Decrypt”; without output path, it uses `.encrypted` / `.decrypted` suffixes. 123 | - Public-key (RSA) 124 | 1. Select “Public-key” → “RSA”. 125 | 2. Click “Generate Keypair”; public key saved as `rsa_public_key_.txt`, private key shown. 126 | 3. String mode: encrypt/decrypt within the text panes. 127 | 4. File mode: similar with input/output paths. 128 | - MD5 129 | 1. Provide either a string or a file. 130 | 2. Click “Generate MD5”. 131 | 132 | Notes: 133 | 134 | - Large files: >1MB may freeze the UI. 135 | - Text encoding: plaintext import requires UTF-8 text; non-text or other encodings will fail. 136 | - Key specs: 137 | - DES/AES: 8-character key. 138 | - CA: integer 0–255. 139 | - Affine: `a b`, `a` coprime to 26. 140 | - Double-Transposition: two keys separated by a space. 141 | 142 | ## Project Structure 143 | 144 | ``` 145 | . 146 | ├── algorithm # Cipher implementations (usable as a library) 147 | │ ├── block_cipher 148 | │ │ └── aes 149 | │ ├── classical_cipher 150 | │ ├── hash_algorithm 151 | │ ├── public_cipher 152 | │ │ ├── ecc 153 | │ │ └── rsa 154 | │ └── stream_cipher 155 | │ └── ca 156 | ├── assets # Icons and optional QSS styles 157 | │ ├── icons 158 | │ ├── python 159 | │ └── qss 160 | ├── event # GUI event bindings and flows 161 | ├── ui # GUI definitions 162 | ├── test_file # Example/Test files 163 | ├── main.py # Entry point 164 | ├── requirements.txt # Dependencies 165 | └── pyproject.toml # Optional project config 166 | ``` 167 | 168 | ## Developer Usage (without GUI) 169 | 170 | ```python 171 | # RC4 string encrypt/decrypt 172 | from algorithm.stream_cipher.rc4_cipher import RC4 173 | cipher = RC4() 174 | c = cipher.encrypt('key', 'plaintext') 175 | p = cipher.decrypt('key', c) 176 | 177 | # DES file encrypt/decrypt 178 | from algorithm.block_cipher import des_cipher 179 | desc = des_cipher.DESCipher() 180 | desc.new('12345678') 181 | desc.encrypt_file('input.txt', 'output.encrypted') 182 | desc.decrypt_file('output.encrypted', 'output.decrypted') 183 | 184 | # AES string encrypt/decrypt 185 | from algorithm.block_cipher.aes import aes_string 186 | c = aes_string.encrypt('hello world', '12345678') 187 | p = aes_string.decrypt(c, '12345678') 188 | 189 | # MD5 190 | from algorithm.hash_algorithm import md5_string, md5_file 191 | md5_s = md5_string.md5('hello') 192 | md5_f = md5_file.md5('path/to/file') 193 | ``` 194 | 195 | ## FAQ 196 | 197 | - No response on encrypt/decrypt: ensure an algorithm is selected and inputs/keys are provided. 198 | - Wrong key length: DES/AES require 8 characters; errors shown in the status bar. 199 | - CA key range: must be an integer within 0–255. 200 | - Text import failure: input must be UTF-8 text; use file mode for binary files. 201 | 202 | ## Version & Credits 203 | 204 | - See repository history for version records. 205 | - Please credit the author: morsuning, for public use. 206 | 207 | ## License 208 | 209 | [Mozilla Public License 2.0](https://github.com/morsuning/cryptography-GUItool/blob/master/LICENSE) 210 | 211 | [![Stargazers over time](https://starchart.cc/morsuning/cryptography-GUItool.svg)](https://starchart.cc/morsuning/cryptography-GUItool) -------------------------------------------------------------------------------- /algorithm/public_cipher/ecc/verifyrandom.py: -------------------------------------------------------------------------------- 1 | import collections 2 | import hashlib 3 | 4 | 5 | class VerificationFailed(Exception): 6 | pass 7 | 8 | 9 | EllipticCurve = collections.namedtuple('EllipticCurve', 'seed p a b') 10 | 11 | # 除了最后一条曲线外,下面所有的曲线都来自于OpenSSL 12 | # 源代码(crypto/ec/ec_curv .c)。最后四个是假曲线 13 | # 没有通过种子验证。 14 | 15 | curves = { 16 | 'prime192v1': EllipticCurve( 17 | seed=0x3045ae6fc8422f64ed579528d38120eae12196d5, 18 | p=0xfffffffffffffffffffffffffffffffeffffffffffffffff, 19 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffc, 20 | b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1, 21 | ), 22 | 'secp224r1': EllipticCurve( 23 | seed=0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5, 24 | p=0xffffffffffffffffffffffffffffffff000000000000000000000001, 25 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffffffffffe, 26 | b=0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4, 27 | ), 28 | 'secp384r1': EllipticCurve( 29 | seed=0xa335926aa319a27a1d00896a6773a4827acdac73, 30 | p=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff, 31 | a=0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc, 32 | b=0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef, 33 | ), 34 | 'secp521r1': EllipticCurve( 35 | seed=0xd09e8800291cb85396cc6717393284aaa0da64ba, 36 | p=0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 37 | a=0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc, 38 | b=0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00, 39 | ), 40 | 'prime192v2': EllipticCurve( 41 | seed=0x31a92ee2029fd10d901b113e990710f0d21ac6b6, 42 | p=0xfffffffffffffffffffffffffffffffeffffffffffffffff, 43 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffc, 44 | b=0xcc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953, 45 | ), 46 | 'prime192v3': EllipticCurve( 47 | seed=0xc469684435deb378c4b65ca9591e2a5763059a2e, 48 | p=0xfffffffffffffffffffffffffffffffeffffffffffffffff, 49 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffc, 50 | b=0x22123dc2395a05caa7423daeccc94760a7d462256bd56916, 51 | ), 52 | 'prime239v1': EllipticCurve( 53 | seed=0xe43bb460f0b80cc0c0b075798e948060f8321b7d, 54 | p=0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff, 55 | a=0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc, 56 | b=0x6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a, 57 | ), 58 | 'prime239v2': EllipticCurve( 59 | seed=0xe8b4011604095303ca3b8099982be09fcb9ae616, 60 | p=0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff, 61 | a=0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc, 62 | b=0x617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c, 63 | ), 64 | 'prime239v3': EllipticCurve( 65 | seed=0x7d7374168ffe3471b60a857686a19475d3bfa2ff, 66 | p=0x7fffffffffffffffffffffff7fffffffffff8000000000007fffffffffff, 67 | a=0x7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc, 68 | b=0x255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e, 69 | ), 70 | 'prime256v1': EllipticCurve( 71 | seed=0xc49d360886e704936a6678e1139d26b7819f7e90, 72 | p=0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff, 73 | a=0xffffffff00000001000000000000000000000000fffffffffffffffffffffffc, 74 | b=0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b, 75 | ), 76 | 'secp112r1': EllipticCurve( 77 | seed=0x00f50b028e4d696e676875615175290472783fb1, 78 | p=0xdb7c2abf62e35e668076bead208b, 79 | a=0xdb7c2abf62e35e668076bead2088, 80 | b=0x659ef8ba043916eede8911702b22, 81 | ), 82 | 'secp112r2': EllipticCurve( 83 | seed=0x002757a1114d696e6768756151755316c05e0bd4, 84 | p=0xdb7c2abf62e35e668076bead208b, 85 | a=0x6127c24c05f38a0aaaf65c0ef02c, 86 | b=0x51def1815db5ed74fcc34c85d709, 87 | ), 88 | 'secp128r1': EllipticCurve( 89 | seed=0x000e0d4d696e6768756151750cc03a4473d03679, 90 | p=0xfffffffdffffffffffffffffffffffff, 91 | a=0xfffffffdfffffffffffffffffffffffc, 92 | b=0xe87579c11079f43dd824993c2cee5ed3, 93 | ), 94 | 'secp128r2': EllipticCurve( 95 | seed=0x004d696e67687561517512d8f03431fce63b88f4, 96 | p=0xfffffffdffffffffffffffffffffffff, 97 | a=0xd6031998d1b3bbfebf59cc9bbff9aee1, 98 | b=0x5eeefca380d02919dc2c6558bb6d8a5d, 99 | ), 100 | 'secp160r1': EllipticCurve( 101 | seed=0x1053cde42c14d696e67687561517533bf3f83345, 102 | p=0x00ffffffffffffffffffffffffffffffff7fffffff, 103 | a=0x00ffffffffffffffffffffffffffffffff7ffffffc, 104 | b=0x001c97befc54bd7a8b65acf89f81d4d4adc565fa45, 105 | ), 106 | 'secp160r2': EllipticCurve( 107 | seed=0xb99b99b099b323e02709a4d696e6768756151751, 108 | p=0x00fffffffffffffffffffffffffffffffeffffac73, 109 | a=0x00fffffffffffffffffffffffffffffffeffffac70, 110 | b=0x00b4e134d3fb59eb8bab57274904664d5af50388ba, 111 | ), 112 | 'sm2p256v1': EllipticCurve( 113 | seed=0xb99b99b099b323e02709a4d696e6768756151751, 114 | p=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF, 115 | a=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC, 116 | b=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93, 117 | ), 118 | # This is prime192v1 with a wrong value for seed. 119 | 'wrong192v1': EllipticCurve( 120 | seed=0x123, 121 | p=0xfffffffffffffffffffffffffffffffeffffffffffffffff, 122 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffc, 123 | b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1, 124 | ), 125 | # This is prime192v1 with a wrong value for p. 126 | 'wrong192v2': EllipticCurve( 127 | seed=0x3045ae6fc8422f64ed579528d38120eae12196d5, 128 | p=0x123, 129 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffc, 130 | b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1, 131 | ), 132 | # This is prime192v1 with a wrong value for a. 133 | 'wrong192v3': EllipticCurve( 134 | seed=0x3045ae6fc8422f64ed579528d38120eae12196d5, 135 | p=0xfffffffffffffffffffffffffffffffeffffffffffffffff, 136 | a=0x123, 137 | b=0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1, 138 | ), 139 | # This is prime192v1 with a wrong value for b. 140 | 'wrong192v4': EllipticCurve( 141 | seed=0x3045ae6fc8422f64ed579528d38120eae12196d5, 142 | p=0xfffffffffffffffffffffffffffffffeffffffffffffffff, 143 | a=0xfffffffffffffffffffffffffffffffefffffffffffffffc, 144 | b=0x123, 145 | ), 146 | 147 | } 148 | 149 | 150 | def verify_curve(curve): 151 | """ 152 | Verifies whether the a and b parameters of the given curve were generated 153 | from the seed. 154 | 155 | Raises a VerificationFailed exception in case the verification fails. 156 | """ 157 | # What follows is the implementation of the verification algorithm 158 | # described in "The Elliptic Curve Digital Signature Algorithm (ECDSA)", 159 | # from Certicom. There just a few difference between the original algorithm 160 | # and the implementation: 161 | # 162 | # * a few variable names have been changed for the sake of clarity; 163 | # * the document from Certicom allows arbritrary seeds with bit length 164 | # >= 160; here we only care about seeds that are exactly 160-bit long. 165 | 166 | if curve.seed.bit_length() > 160: 167 | raise VerificationFailed('seed too long') 168 | 169 | seed_bytes = curve.seed.to_bytes(length=160 // 8, byteorder='big') 170 | 171 | # Define t, s and v as specified on the document. 172 | t = curve.p.bit_length() 173 | s = (t - 1) // 160 174 | v = t - 160 * s 175 | 176 | # 1. Compute h = SHA-1(seed_bytes) and let c0 denote the bit string of 177 | # length v bits obtained by taking the v rightmost bits of h. 178 | h = hashlib.sha1(seed_bytes).digest() 179 | h = int.from_bytes(h, byteorder='big') 180 | 181 | c0 = h & ((1 << v) - 1) 182 | 183 | # 2. Let w[0] denote the bit string of length v bits obtained by setting 184 | # the leftmost bit of c0 to 0. 185 | # 186 | # Note: here we use 160 bit instead of v bits, as required by the document. 187 | # We do so to make the code easier, and because it does not make any 188 | # difference (see the step 6). 189 | w0 = c0 & ((1 << v - 1) - 1) 190 | w = [w0.to_bytes(length=160 // 8, byteorder='big')] 191 | 192 | # 3. Let z be the integer whose binary expansion is given by 160-bit string 193 | # seed_bytes. 194 | z = curve.seed 195 | 196 | # 4. For i from 1 to s do: 197 | for i in range(1, s + 1): 198 | # 4.1 Let s_i be 160-bit string which is the binary expansion of the 199 | # integer (z + i) % (2 ** g). 200 | z_i = ((z + i) % (2 ** 160)) 201 | s_i = z_i.to_bytes(length=160 // 8, byteorder='big') 202 | 203 | # 4.2 Compute w_i = SHA-1(s_i). 204 | w_i = hashlib.sha1(s_i).digest() 205 | w.append(w_i) 206 | 207 | # 5. Let w be the bit string obtained by concatenating w_0,w_1,...,w_s. 208 | w = b''.join(w) 209 | 210 | # 6. Let c be the integer whose integer expansion is given by w. 211 | # 212 | # On step 2, we said that we used a longer bit length for the first element 213 | # of w. This is correct because the resulting c does not change: using 160 214 | # bits instead of v bits is equivalent to add some zeroes to the left of c. 215 | c = int.from_bytes(w, 'big') 216 | 217 | # If b ** 2 * c == a ** 3 (mod p) then accept; otherwise reject. 218 | if (curve.b * curve.b * c - curve.a * curve.a * curve.a) % curve.p != 0: 219 | raise VerificationFailed('curve verification failed') 220 | 221 | 222 | # Check all the curves defined above. 223 | # Should produce the following output: 224 | # 225 | # prime192v1: ok 226 | # prime192v2: ok 227 | # ... 228 | # secp384r1: ok 229 | # secp521r1: ok 230 | # wrong192v1: failed 231 | # wrong192v2: failed 232 | # wrong192v3: failed 233 | # wrong192v4: failed 234 | for name in sorted(curves): 235 | curve = curves[name] 236 | print(name, end=': ') 237 | try: 238 | verify_curve(curve) 239 | except VerificationFailed: 240 | print('failed') 241 | else: 242 | print('ok') 243 | -------------------------------------------------------------------------------- /algorithm/block_cipher/des_cipher.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 常量部分: 3 | IP置换表 逆IP置换表 4 | S盒中的8个盒(substitution box) 5 | P盒(permutation box) 6 | 压缩置换表1-PC1 压缩置换表2-PC2 7 | 拓展置换表E(expansion box) 8 | ''' 9 | # IP置换表 10 | IP = [ 11 | 58, 50, 42, 34, 26, 18, 10, 2, 12 | 60, 52, 44, 36, 28, 20, 12, 4, 13 | 62, 54, 46, 38, 30, 22, 14, 6, 14 | 64, 56, 48, 40, 32, 24, 16, 8, 15 | 57, 49, 41, 33, 25, 17, 9, 1, 16 | 59, 51, 43, 35, 27, 19, 11, 3, 17 | 61, 53, 45, 37, 29, 21, 13, 5, 18 | 63, 55, 47, 39, 31, 23, 15, 7 19 | ] 20 | 21 | # 逆IP置换表 22 | rIP = [ 23 | 40, 8, 48, 16, 56, 24, 64, 32, 24 | 39, 7, 47, 15, 55, 23, 63, 31, 25 | 38, 6, 46, 14, 54, 22, 62, 30, 26 | 37, 5, 45, 13, 53, 21, 61, 29, 27 | 36, 4, 44, 12, 52, 20, 60, 28, 28 | 35, 3, 43, 11, 51, 19, 59, 27, 29 | 34, 2, 42, 10, 50, 18, 58, 26, 30 | 33, 1, 41, 9, 49, 17, 57, 25 31 | ] 32 | 33 | # S盒1-8 34 | S1 = [ 35 | 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 36 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 37 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 38 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 39 | ] 40 | S2 = [ 41 | 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 42 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 43 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 44 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 45 | ] 46 | S3 = [ 47 | 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 48 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 49 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 50 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 51 | ] 52 | S4 = [ 53 | 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 54 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 55 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 56 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 57 | ] 58 | S5 = [ 59 | 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 60 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 61 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 62 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 63 | ] 64 | S6 = [ 65 | 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 66 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 67 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 68 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 69 | ] 70 | S7 = [ 71 | 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 72 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 73 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 74 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 75 | ] 76 | S8 = [ 77 | 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 78 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 79 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 80 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 81 | ] 82 | S = [S1, S2, S3, S4, S5, S6, S7, S8] 83 | 84 | # P盒 85 | P = [ 86 | 16, 7, 20, 21, 87 | 29, 12, 28, 17, 88 | 1, 15, 23, 26, 89 | 5, 18, 31, 10, 90 | 2, 8, 24, 14, 91 | 32, 27, 3, 9, 92 | 19, 13, 30, 6, 93 | 22, 11, 4, 25 94 | ] 95 | 96 | # 压缩置换表PC1 97 | PC1 = [ 98 | 57, 49, 41, 33, 25, 17, 9, 99 | 1, 58, 50, 42, 34, 26, 18, 100 | 10, 2, 59, 51, 43, 35, 27, 101 | 19, 11, 3, 60, 52, 44, 36, 102 | 63, 55, 47, 39, 31, 23, 15, 103 | 7, 62, 54, 46, 38, 30, 22, 104 | 14, 6, 61, 53, 45, 37, 29, 105 | 21, 13, 5, 28, 20, 12, 4 106 | ] 107 | 108 | # 压缩置换表PC2 109 | PC2 = [ 110 | 14, 17, 11, 24, 1, 5, 111 | 3, 28, 15, 6, 21, 10, 112 | 23, 19, 12, 4, 26, 8, 113 | 16, 7, 27, 20, 13, 2, 114 | 41, 52, 31, 37, 47, 55, 115 | 30, 40, 51, 45, 33, 48, 116 | 44, 49, 39, 56, 34, 53, 117 | 46, 42, 50, 36, 29, 32 118 | ] 119 | 120 | # 拓展置换表E 121 | E = [ 122 | 32, 1, 2, 3, 4, 5, 123 | 4, 5, 6, 7, 8, 9, 124 | 8, 9, 10, 11, 12, 13, 125 | 12, 13, 14, 15, 16, 17, 126 | 16, 17, 18, 19, 20, 21, 127 | 20, 21, 22, 23, 24, 25, 128 | 24, 25, 26, 27, 28, 29, 129 | 28, 29, 30, 31, 32, 1 130 | ] 131 | 132 | 133 | def table_mapping(table, iput): 134 | result = "" 135 | for i in table: 136 | result += iput[i - 1] 137 | return result 138 | 139 | 140 | class DESCipher: 141 | 142 | def __init__(self): 143 | self.encrypt_result_hex = 0 144 | self.encrypted_file_name = "" 145 | 146 | # 表映射,输入长度必须与表大小一致--- 147 | 148 | # 均分成n部分,传入一个字符串,返回包含n项的列表--- 149 | @staticmethod 150 | def separate(entire, n): 151 | result = [] 152 | per = len(entire) // n 153 | if len(entire) % n != 0: 154 | print("分离错误") 155 | exit(-1) 156 | while len(entire) != 0: 157 | result.append(entire[:per]) 158 | entire = entire[per:] 159 | return result 160 | 161 | # 合并成一部分,传入包含n个字符串的列表,返回一个字符串--- 162 | @staticmethod 163 | def merge(list): 164 | return "".join(i for i in list) 165 | 166 | ''' 167 | 对密钥操作部分 168 | ''' 169 | 170 | # 左/右移n位--- 171 | @staticmethod 172 | def l_or_r_move(stream, n, l_or_r): 173 | if l_or_r == "L": 174 | if n > len(stream) - 1: 175 | print("左移错误") 176 | exit(-1) 177 | tmp = stream[:n] 178 | stream = stream[n:] 179 | result = stream + tmp 180 | else: 181 | if n > len(stream) - 1: 182 | print("右移错误") 183 | exit(-1) 184 | tmp = stream[-n:] 185 | stream = stream[:-n] 186 | result = tmp + stream 187 | return result 188 | 189 | # PC1压缩置换--- 190 | def PC1change(self, key): 191 | result = table_mapping(PC1, key) 192 | return result 193 | 194 | # PC2置换--- 195 | def PC2change(self, endkey): 196 | result = table_mapping(PC2, endkey) 197 | return result 198 | 199 | # 生成密钥1-16--- 200 | def key_generator(self, key): 201 | Key = [] 202 | initedKey = self.PC1change(key) # 对key进行PC1置换 203 | curCandD = self.separate(initedKey, 2) # 将key拆成2部分 204 | for i in range(16): 205 | if i == 0 or i == 1 or i == 8 or i == 15: 206 | curCandD[0] = self.l_or_r_move(curCandD[0], 1, "L") 207 | curCandD[1] = self.l_or_r_move(curCandD[1], 1, "L") 208 | Key.append(self.PC2change(self.merge(curCandD))) 209 | else: 210 | curCandD[0] = self.l_or_r_move(curCandD[0], 2, "L") 211 | curCandD[1] = self.l_or_r_move(curCandD[1], 2, "L") 212 | Key.append(self.PC2change(self.merge(curCandD))) 213 | return Key 214 | 215 | # 初始置换IP输入64位明文--- 216 | def init_permutation(self, block_plain_text): 217 | result = table_mapping(IP, block_plain_text) 218 | return result 219 | 220 | # F函数--- 221 | def func(self, k_per_turn, r_per_turn): 222 | curR = self.Echange(r_per_turn) 223 | beforeS = self.xor(curR, k_per_turn) 224 | toS = self.separate(beforeS, 8) 225 | for i, item in enumerate(toS): 226 | toS[i] = self.Schange(item, i) 227 | tmpResult = self.merge(toS) 228 | result = self.Pchange(tmpResult) 229 | return result 230 | 231 | # S置换--- 232 | def Schange(self, str, turn): 233 | column = int(str[1:5], 2) # 列 234 | row = int((str[0] + str[5]), 2) # 行 235 | tmpresult = S[turn][row * 16 + column] 236 | result = bin(int(tmpresult)).replace("0b", "").zfill(4) 237 | return result 238 | 239 | # P置换--- 240 | def Pchange(self, str): 241 | result = table_mapping(P, str) 242 | return result 243 | 244 | # 16轮加密--- 245 | def turn_operation(self, str, key, EorD): 246 | COUNTTURN = 16 247 | curLandR = self.separate(str, 2) # 将明文拆成2部分 248 | Key = self.key_generator(key) 249 | j = 15 250 | for i in range(COUNTTURN): 251 | nextL = curLandR[1] # 先保存右侧 252 | if EorD == "E": 253 | curLandR[1] = self.func(Key[i], curLandR[1]) # 将右侧和k输入f函数 254 | elif EorD == "D": 255 | curLandR[1] = self.func(Key[j], curLandR[1]) 256 | j -= 1 257 | perR = self.xor(curLandR[0], curLandR[1]) # 将新右侧与左侧异或 258 | curLandR[0] = nextL # 原右侧为新左侧 259 | curLandR[1] = perR # 运算结果为新右侧 260 | tmpresult = self.changeleftandright(curLandR) # 16轮结束后,交换左右 261 | result = self.merge(tmpresult) # 合并结果 262 | return result 263 | 264 | # 交换左右--- 265 | def changeleftandright(self, pair): 266 | tmp = pair[0] 267 | pair[0] = pair[1] 268 | pair[1] = tmp 269 | return pair 270 | 271 | # E置换--- 272 | def Echange(self, tmp): 273 | result = table_mapping(E, tmp) 274 | return result 275 | 276 | # 末(rIP)置换--- 277 | def reinitpermutation(self, tmp): 278 | result = table_mapping(rIP, tmp) 279 | return result 280 | 281 | # 异或操作--- 282 | def xor(self, left, right): 283 | length = len(left) 284 | if length != len(right): 285 | print("异或异常") 286 | exit(-1) 287 | result = int(left, 2) ^ int(right, 2) 288 | return bin(result).replace("0b", "").zfill(length) 289 | 290 | # 采用PKCS7标准填充明文:字节对8取余得r,为0补8个"8",不为0补8-r个8-r 291 | def PKCS7Padding(self, plaintext): 292 | toPaddinglen = 8 - (len(plaintext) % 8) 293 | if toPaddinglen == 8: 294 | result = plaintext 295 | else: 296 | result = plaintext + str(toPaddinglen) * toPaddinglen 297 | return result 298 | 299 | # 将字符串转化为二进制字符串--- 300 | def str2bin(self, str): 301 | result = "" 302 | for i in str: 303 | result += bin(ord(i)).replace('0b', '').zfill(8) 304 | return result 305 | 306 | # 将二进制字符串转化为字符串--- 307 | def bin2str(self, bin): 308 | if len(bin) % 8 != 0: 309 | print("二进制转字符串错误") 310 | exit(-1) 311 | result = "" 312 | while len(bin) != 0: 313 | result += chr(int(bin[:8], 2)) 314 | bin = bin[8:] 315 | return result 316 | 317 | # 对明文分组,每组64位--- 318 | def gruoping(self, plaintext): 319 | result = [] 320 | while len(plaintext) != 0: 321 | result.append(plaintext[:64]) 322 | plaintext = plaintext[64:] 323 | return result 324 | 325 | def inputhandle(self, key): 326 | dic = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~" 327 | if len(key) != 8: 328 | return False 329 | for i in key: 330 | if i not in dic: 331 | return False 332 | return True 333 | 334 | def cryption(self, plaintext, key, EnorDe): 335 | Plaintext = self.gruoping(plaintext) # 将明文分组 336 | cipherText = "" 337 | KEY = self.str2bin(key) # 将密钥转为二进制字符串 338 | for i in Plaintext: # 对每组加密 339 | initedPlaintext = self.init_permutation(i) # IP变换 340 | tmp = self.turn_operation(initedPlaintext, KEY, EnorDe) # 16轮加密 341 | result = self.reinitpermutation(tmp) # IP逆变换 342 | Result = self.bin2str(result) 343 | cipherText += Result 344 | return cipherText 345 | 346 | def encryption(self, plaintext, key): 347 | return self.cryption(plaintext, key, "E") 348 | 349 | def decryption(self, ciphertext, key): 350 | tmp = self.cryption(ciphertext, key, "D") 351 | delete = tmp[-1] 352 | if delete in ["1", "2", "3", "4", "5", "6", "7"]: 353 | return tmp[:-int(delete)] 354 | else: 355 | return tmp 356 | 357 | def new(self, key): 358 | if self.inputhandle(key): 359 | self.Key = key 360 | else: 361 | raise ValueError("密钥输入不符合规范,必须为8位,且为A-Za-z0-9及键盘符号的组合请重新输入") 362 | return self 363 | 364 | def result_to_hex(self, result_string): 365 | encrypt_result_hex = "" 366 | for i in result_string: 367 | encrypt_result_hex.join(hex(int(bin(ord(i)).replace("0b", ""), 2)).replace("0x", "")) 368 | return encrypt_result_hex 369 | 370 | def encrypt_string(self, plain_text): 371 | Plaintext = self.PKCS7Padding(plain_text) 372 | encrypt_result = self.encryption(self.str2bin(Plaintext), self.Key) 373 | self.encrypt_result_hex = self.result_to_hex(encrypt_result) 374 | return encrypt_result 375 | 376 | def decrypt_string(self, cipher_text): 377 | self.plain = self.decryption(self.str2bin(cipher_text), self.Key) 378 | return self.plain 379 | 380 | def encrypt_file(self, file_name, save): 381 | with open(file_name, 'rb') as r: 382 | Plaintext = self.PKCS7Padding(str(r.read())) 383 | encrypt = self.encryption(self.str2bin(Plaintext), self.Key) 384 | self.encrypted_file_name = file_name + ".encrypted" 385 | with open(save, 'wb') as w: 386 | w.write(encrypt.encode('utf-8')) 387 | return self.encrypted_file_name 388 | 389 | def decrypt_file(self, file_name, save): 390 | with open(file_name, 'rb') as r: 391 | decry = self.decryption(self.str2bin(r.read().decode('utf-8')), self.Key) 392 | self.decrypt_file_name = file_name + ".decrypted" 393 | with open(save, 'w') as w: 394 | w.write(decry.strip("b'")) 395 | return self.decrypt_file_name 396 | 397 | def main(): 398 | """Example""" 399 | des = DESCipher() 400 | des.new("12345678") 401 | encrypt_result = des.encrypt_string("abcdef") 402 | print(encrypt_result) 403 | decrypt_result = des.decrypt_string(encrypt_result) 404 | print(decrypt_result) 405 | 406 | if __name__ == '__main__': 407 | main() 408 | -------------------------------------------------------------------------------- /algorithm/block_cipher/aes/aes_file.py: -------------------------------------------------------------------------------- 1 | class AESE(): 2 | 3 | def __init__(self, blk, key, Nr): 4 | self.blk = blk 5 | self.key = key 6 | self.Nr = Nr 7 | self.sbox = (0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 8 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 9 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 10 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 11 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 12 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 13 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 14 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 15 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 16 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 17 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 18 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 19 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 20 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 21 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 22 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16) 23 | 24 | # xtime process 25 | def xtime(self, x): 26 | if x & 0x80: 27 | return ((x << 1) ^ 0x1b) & 0xff 28 | return x << 1 29 | 30 | # MixColumns: Process the entire block 31 | def MixColumns(self): 32 | tmp = [0 for t in range(4)] 33 | xt = [0 for q in range(4)] 34 | n = 0 35 | for x in range(4): 36 | xt[0] = self.xtime(self.blk[n]) 37 | xt[1] = self.xtime(self.blk[n + 1]) 38 | xt[2] = self.xtime(self.blk[n + 2]) 39 | xt[3] = self.xtime(self.blk[n + 3]) 40 | tmp[0] = xt[0] ^ xt[1] ^ self.blk[n + 1] ^ self.blk[n + 2] ^ self.blk[n + 3] 41 | tmp[1] = self.blk[n] ^ xt[1] ^ xt[2] ^ self.blk[n + 2] ^ self.blk[n + 3] 42 | tmp[2] = self.blk[n] ^ self.blk[n + 1] ^ xt[2] ^ xt[3] ^ self.blk[n + 3] 43 | tmp[3] = xt[0] ^ self.blk[n] ^ self.blk[n + 1] ^ self.blk[n + 2] ^ xt[3] 44 | self.blk[n] = tmp[0] 45 | self.blk[n + 1] = tmp[1] 46 | self.blk[n + 2] = tmp[2] 47 | self.blk[n + 3] = tmp[3] 48 | n = n + 4 49 | 50 | # ShiftRows:Shifts the entire block 51 | def ShiftRows(self): 52 | # 2nd row 53 | t = self.blk[1] 54 | self.blk[1] = self.blk[5] 55 | self.blk[5] = self.blk[9] 56 | self.blk[9] = self.blk[13] 57 | self.blk[13] = t 58 | # 3nd row 59 | t = self.blk[2] 60 | self.blk[2] = self.blk[10] 61 | self.blk[10] = t 62 | t = self.blk[6] 63 | self.blk[6] = self.blk[14] 64 | self.blk[14] = t 65 | # 4nd row 66 | t = self.blk[15] 67 | self.blk[15] = self.blk[11] 68 | self.blk[11] = self.blk[7] 69 | self.blk[7] = self.blk[3] 70 | self.blk[3] = t 71 | 72 | # SubBytes 73 | def SubBytes(self): 74 | for x in range(16): 75 | self.blk[x] = self.sbox[self.blk[x]] 76 | 77 | # AddRoundKey 78 | def AddRoundKey(self, key): 79 | x = 0 80 | k = [0 for m in range(16)] 81 | for c in range(4): 82 | for r in range(4): 83 | k[x] = key[r][c] 84 | x = x + 1 85 | for y in range(16): 86 | self.blk[y] ^= int(k[y]) 87 | 88 | def show(self): 89 | for i in range(16): 90 | print(hex(self.blk[i])) 91 | 92 | # Schedule a secret key for use. 93 | def ScheduleKey(self, w, Nk): 94 | Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] 95 | for r in range(4): 96 | for c in range(4): 97 | w[0][r][c] = self.key[r + c * 4] 98 | for i in range(1, self.Nr + 1, 1): 99 | for j in range(Nk): 100 | t = [0 for x in range(4)] 101 | for r in range(4): 102 | if j: 103 | t[r] = w[i][r][j - 1] 104 | else: 105 | t[r] = w[i - 1][r][3] 106 | if j == 0: 107 | temp = t[0] 108 | for r in range(3): 109 | t[r] = self.sbox[t[(r + 1) % 4]] 110 | t[3] = self.sbox[temp] 111 | t[0] ^= int(Rcon[i - 1]) 112 | for r in range(4): 113 | w[i][r][j] = w[i - 1][r][j] ^ t[r] 114 | 115 | # 加密函数 116 | def AesEncrypt(self): 117 | outkey = [] 118 | outkey = [[[0 for col in range(4)] for row in range(4)] for s in range(11)] 119 | self.ScheduleKey(outkey, 4) 120 | self.AddRoundKey(outkey[0]) 121 | for x in range(1, self.Nr, 1): 122 | self.SubBytes() 123 | self.ShiftRows() 124 | self.MixColumns() 125 | self.AddRoundKey(outkey[x]) 126 | self.SubBytes() 127 | self.ShiftRows() 128 | self.AddRoundKey(outkey[10]) 129 | return self.blk 130 | 131 | class AESD(): 132 | def __init__(self, blk, key, Nr): 133 | self.blk = blk 134 | self.key = key 135 | self.Nr = Nr 136 | self.sbox = (0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 137 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 138 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 139 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 140 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 141 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 142 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 143 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 144 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 145 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 146 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 147 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 148 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 149 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 150 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 151 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16) 152 | 153 | def xtime(self, x): 154 | if x & 0x80: 155 | return ((x << 1) ^ 0x1b) & 0xff 156 | return x << 1 157 | 158 | def ReMixColumns(self): 159 | tmp = [0 for q in range(4)] 160 | xt1 = [0 for w in range(4)] 161 | xt2 = [0 for e in range(4)] 162 | xt3 = [0 for r in range(4)] 163 | n = 0 164 | for x in range(4): 165 | xt1[0] = self.xtime(self.blk[n]) 166 | xt1[1] = self.xtime(self.blk[n + 1]) 167 | xt1[2] = self.xtime(self.blk[n + 2]) 168 | xt1[3] = self.xtime(self.blk[n + 3]) 169 | xt2[0] = self.xtime(self.xtime(self.blk[n])) 170 | xt2[1] = self.xtime(self.xtime(self.blk[n + 1])) 171 | xt2[2] = self.xtime(self.xtime(self.blk[n + 2])) 172 | xt2[3] = self.xtime(self.xtime(self.blk[n + 3])) 173 | xt3[0] = self.xtime(self.xtime(self.xtime(self.blk[n]))) 174 | xt3[1] = self.xtime(self.xtime(self.xtime(self.blk[n + 1]))) 175 | xt3[2] = self.xtime(self.xtime(self.xtime(self.blk[n + 2]))) 176 | xt3[3] = self.xtime(self.xtime(self.xtime(self.blk[n + 3]))) 177 | tmp[0] = xt1[0] ^ xt2[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt1[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt2[2] ^ xt3[2] ^ \ 178 | self.blk[n + 3] ^ xt3[3] 179 | tmp[1] = self.blk[n] ^ xt3[0] ^ xt1[1] ^ xt2[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt1[2] ^ xt3[2] ^ self.blk[ 180 | n + 3] ^ xt2[3] ^ xt3[3] 181 | tmp[2] = self.blk[n] ^ xt2[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt3[1] ^ xt1[2] ^ xt2[2] ^ xt3[2] ^ self.blk[ 182 | n + 3] ^ xt1[3] ^ xt3[3] 183 | tmp[3] = self.blk[n] ^ xt1[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt2[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt3[2] ^ xt1[ 184 | 3] ^ xt2[3] ^ xt3[3] 185 | self.blk[n] = tmp[0] 186 | self.blk[n + 1] = tmp[1] 187 | self.blk[n + 2] = tmp[2] 188 | self.blk[n + 3] = tmp[3] 189 | n = n + 4 190 | 191 | def ReShiftRows(self): 192 | # 2nd row 193 | t = self.blk[13] 194 | self.blk[13] = self.blk[9] 195 | self.blk[9] = self.blk[5] 196 | self.blk[5] = self.blk[1] 197 | self.blk[1] = t 198 | # 3rd row 199 | t = self.blk[2] 200 | self.blk[2] = self.blk[10] 201 | self.blk[10] = t 202 | t = self.blk[6] 203 | self.blk[6] = self.blk[14] 204 | self.blk[14] = t 205 | # 4th row 206 | t = self.blk[3] 207 | self.blk[3] = self.blk[7] 208 | self.blk[7] = self.blk[11] 209 | self.blk[11] = self.blk[15] 210 | self.blk[15] = t 211 | 212 | def ReSubBytes(self): 213 | for i in range(16): 214 | for j in range(256): 215 | if self.sbox[j] == self.blk[i]: 216 | self.blk[i] = j 217 | break 218 | 219 | def AddRoundKey(self, key): 220 | x = 0 221 | k = [0 for m in range(16)] 222 | for c in range(4): 223 | for r in range(4): 224 | k[x] = key[r][c] 225 | x = x + 1 226 | for y in range(16): 227 | self.blk[y] ^= k[y] 228 | 229 | def ScheduleKey(self, w, Nk): 230 | Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] 231 | for r in range(4): 232 | for c in range(4): 233 | w[0][r][c] = self.key[r + c * 4] 234 | for i in range(1, self.Nr + 1, 1): 235 | for j in range(Nk): 236 | t = [0 for x in range(4)] 237 | for r in range(4): 238 | if j: 239 | t[r] = w[i][r][j - 1] 240 | else: 241 | t[r] = w[i - 1][r][3] 242 | if j == 0: 243 | temp = t[0] 244 | for r in range(3): 245 | t[r] = self.sbox[t[(r + 1) % 4]] 246 | t[3] = self.sbox[temp] 247 | t[0] ^= int(Rcon[i - 1]) 248 | for r in range(4): 249 | w[i][r][j] = w[i - 1][r][j] ^ t[r] 250 | 251 | def AesDecrpyt(self): 252 | outkey = [] 253 | outkey = [[[0 for col in range(4)] for row in range(4)] for s in range(11)] 254 | self.ScheduleKey(outkey, 4) 255 | self.AddRoundKey(outkey[10]) 256 | self.ReShiftRows() 257 | self.ReSubBytes() 258 | for x in range(self.Nr - 1, 0, -1): 259 | self.AddRoundKey(outkey[x]) 260 | self.ReMixColumns() 261 | self.ReShiftRows() 262 | self.ReSubBytes() 263 | self.AddRoundKey(outkey[0]) 264 | return self.blk 265 | 266 | 267 | def StringToListN(string): 268 | s = [0 for x in range(16)] 269 | strLen = len(string) 270 | for x in range(strLen): 271 | s[x] = int(ord(string[x])) 272 | return s 273 | 274 | def HexToInt(string): 275 | s = [0 for x in range(16)] 276 | for i in range(16): 277 | s[i] = int(string[2 * i:2 * i + 2], 16) 278 | return s 279 | 280 | def encrypt(filename, skey, newfilename): 281 | f1 = open(filename, "rb") 282 | data = f1.read() 283 | f1.close() 284 | key = StringToListN(skey) 285 | f2 = open(newfilename, "wb") 286 | number = int(len(data) / 16) 287 | if len(data) % 16 != 0: 288 | number = number + 1 289 | for i in range(0, number): 290 | blk = [0 for x in range(16)] 291 | tmp = data[i * 16:i * 16 + 16] 292 | for j in range(len(tmp)): 293 | blk[j] = int(tmp[j]) 294 | a = AESE(blk, key, 10) 295 | f2.write(bytes(a.AesEncrypt())) 296 | f2.close() 297 | 298 | def decrypt(filename, skey, newfilename): 299 | f1 = open(filename, "rb") 300 | data = f1.read() 301 | key = StringToListN(skey) 302 | f2 = open(newfilename, "wb") 303 | number = int(len(data) / 16) 304 | if len(data) % 16 != 0: 305 | number = number + 1 306 | for i in range(0, number): 307 | blk = [0 for x in range(16)] 308 | tmp = data[i * 16:i * 16 + 16] 309 | for j in range(len(tmp)): 310 | blk[j] = int(tmp[j]) 311 | a = AESD(blk, key, 10) 312 | f2.write(bytes(a.AesDecrpyt())) 313 | f2.close() 314 | -------------------------------------------------------------------------------- /algorithm/block_cipher/aes/aes_string.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | class AESE(): 4 | def __init__(self, blk, key, Nr): 5 | self.blk = blk 6 | self.key = key 7 | self.Nr = Nr 8 | self.sbox = (0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 9 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 10 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 11 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 12 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 13 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 14 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 15 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 16 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 17 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 18 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 19 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 20 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 21 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 22 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 23 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16) 24 | 25 | # xtime process 26 | def xtime(self, x): 27 | if (x & 0x80): 28 | return (((x << 1) ^ 0x1b) & 0xff) 29 | return x << 1 30 | 31 | # MixColumns: Process the entire block 32 | def MixColumns(self): 33 | tmp = [0 for t in range(4)] 34 | xt = [0 for q in range(4)] 35 | n = 0 36 | for x in range(4): 37 | xt[0] = self.xtime(self.blk[n]) 38 | xt[1] = self.xtime(self.blk[n + 1]) 39 | xt[2] = self.xtime(self.blk[n + 2]) 40 | xt[3] = self.xtime(self.blk[n + 3]) 41 | tmp[0] = xt[0] ^ xt[1] ^ self.blk[n + 1] ^ self.blk[n + 2] ^ self.blk[n + 3] 42 | tmp[1] = self.blk[n] ^ xt[1] ^ xt[2] ^ self.blk[n + 2] ^ self.blk[n + 3] 43 | tmp[2] = self.blk[n] ^ self.blk[n + 1] ^ xt[2] ^ xt[3] ^ self.blk[n + 3] 44 | tmp[3] = xt[0] ^ self.blk[n] ^ self.blk[n + 1] ^ self.blk[n + 2] ^ xt[3] 45 | self.blk[n] = tmp[0] 46 | self.blk[n + 1] = tmp[1] 47 | self.blk[n + 2] = tmp[2] 48 | self.blk[n + 3] = tmp[3] 49 | n = n + 4 50 | 51 | # ShiftRows:Shifts the entire block 52 | def ShiftRows(self): 53 | # 2nd row 54 | t = self.blk[1] 55 | self.blk[1] = self.blk[5] 56 | self.blk[5] = self.blk[9] 57 | self.blk[9] = self.blk[13] 58 | self.blk[13] = t 59 | # 3nd row 60 | t = self.blk[2] 61 | self.blk[2] = self.blk[10] 62 | self.blk[10] = t 63 | t = self.blk[6] 64 | self.blk[6] = self.blk[14] 65 | self.blk[14] = t 66 | # 4nd row 67 | t = self.blk[15] 68 | self.blk[15] = self.blk[11] 69 | self.blk[11] = self.blk[7] 70 | self.blk[7] = self.blk[3] 71 | self.blk[3] = t 72 | 73 | # SubBytes 74 | def SubBytes(self): 75 | for x in range(16): 76 | self.blk[x] = self.sbox[self.blk[x]] 77 | 78 | # AddRoundKey 79 | def AddRoundKey(self, key): 80 | x = 0 81 | k = [0 for m in range(16)] 82 | for c in range(4): 83 | for r in range(4): 84 | k[x] = key[r][c] 85 | x = x + 1 86 | for y in range(16): 87 | self.blk[y] ^= int(k[y]) 88 | 89 | def show(self): 90 | for i in range(16): 91 | print(hex(self.blk[i])) 92 | 93 | # Schedule a secret key for use. 94 | def ScheduleKey(self, w, Nk): 95 | Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] 96 | for r in range(4): 97 | for c in range(4): 98 | w[0][r][c] = self.key[r + c * 4] 99 | for i in range(1, self.Nr + 1, 1): 100 | for j in range(Nk): 101 | t = [0 for x in range(4)] 102 | for r in range(4): 103 | if j: 104 | t[r] = w[i][r][j - 1] 105 | else: 106 | t[r] = w[i - 1][r][3] 107 | if j == 0: 108 | temp = t[0] 109 | for r in range(3): 110 | t[r] = self.sbox[t[(r + 1) % 4]] 111 | t[3] = self.sbox[temp] 112 | t[0] ^= int(Rcon[i - 1]) 113 | for r in range(4): 114 | w[i][r][j] = w[i - 1][r][j] ^ t[r] 115 | 116 | # 加密函数 117 | def AesEncrypt(self): 118 | outkey = [] 119 | outkey = [[[0 for col in range(4)] for row in range(4)] for s in range(11)] 120 | self.ScheduleKey(outkey, 4) 121 | self.AddRoundKey(outkey[0]) 122 | for x in range(1, self.Nr, 1): 123 | self.SubBytes() 124 | self.ShiftRows() 125 | self.MixColumns() 126 | self.AddRoundKey(outkey[x]) 127 | self.SubBytes() 128 | self.ShiftRows() 129 | self.AddRoundKey(outkey[10]) 130 | cText = "" 131 | for i in range(16): 132 | xxl = hex(self.blk[i]) 133 | if (len(xxl) == 3): 134 | cText += "0" + xxl[2:] 135 | else: 136 | cText += xxl[2:] 137 | return cText 138 | 139 | class AESD(): 140 | def __init__(self, blk, key, Nr): 141 | self.blk = blk 142 | self.key = key 143 | self.Nr = Nr 144 | self.sbox = (0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 145 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 146 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 147 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 148 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 149 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 150 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 151 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 152 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 153 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 154 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 155 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 156 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 157 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 158 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 159 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16) 160 | 161 | def xtime(self, x): 162 | if (x & 0x80): 163 | return (((x << 1) ^ 0x1b) & 0xff) 164 | return x << 1 165 | 166 | def ReMixColumns(self): 167 | tmp = [0 for q in range(4)] 168 | xt1 = [0 for w in range(4)] 169 | xt2 = [0 for e in range(4)] 170 | xt3 = [0 for r in range(4)] 171 | n = 0 172 | for x in range(4): 173 | xt1[0] = self.xtime(self.blk[n]) 174 | xt1[1] = self.xtime(self.blk[n + 1]) 175 | xt1[2] = self.xtime(self.blk[n + 2]) 176 | xt1[3] = self.xtime(self.blk[n + 3]) 177 | xt2[0] = self.xtime(self.xtime(self.blk[n])) 178 | xt2[1] = self.xtime(self.xtime(self.blk[n + 1])) 179 | xt2[2] = self.xtime(self.xtime(self.blk[n + 2])) 180 | xt2[3] = self.xtime(self.xtime(self.blk[n + 3])) 181 | xt3[0] = self.xtime(self.xtime(self.xtime(self.blk[n]))) 182 | xt3[1] = self.xtime(self.xtime(self.xtime(self.blk[n + 1]))) 183 | xt3[2] = self.xtime(self.xtime(self.xtime(self.blk[n + 2]))) 184 | xt3[3] = self.xtime(self.xtime(self.xtime(self.blk[n + 3]))) 185 | tmp[0] = xt1[0] ^ xt2[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt1[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt2[2] ^ xt3[2] ^ \ 186 | self.blk[n + 3] ^ xt3[3] 187 | tmp[1] = self.blk[n] ^ xt3[0] ^ xt1[1] ^ xt2[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt1[2] ^ xt3[2] ^ self.blk[ 188 | n + 3] ^ xt2[3] ^ xt3[3] 189 | tmp[2] = self.blk[n] ^ xt2[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt3[1] ^ xt1[2] ^ xt2[2] ^ xt3[2] ^ self.blk[ 190 | n + 3] ^ xt1[3] ^ xt3[3] 191 | tmp[3] = self.blk[n] ^ xt1[0] ^ xt3[0] ^ self.blk[n + 1] ^ xt2[1] ^ xt3[1] ^ self.blk[n + 2] ^ xt3[2] ^ xt1[ 192 | 3] ^ xt2[3] ^ xt3[3] 193 | self.blk[n] = tmp[0] 194 | self.blk[n + 1] = tmp[1] 195 | self.blk[n + 2] = tmp[2] 196 | self.blk[n + 3] = tmp[3] 197 | n = n + 4 198 | 199 | def ReShiftRows(self): 200 | # 2nd row 201 | t = self.blk[13] 202 | self.blk[13] = self.blk[9] 203 | self.blk[9] = self.blk[5] 204 | self.blk[5] = self.blk[1] 205 | self.blk[1] = t 206 | # 3rd row 207 | t = self.blk[2] 208 | self.blk[2] = self.blk[10] 209 | self.blk[10] = t 210 | t = self.blk[6] 211 | self.blk[6] = self.blk[14] 212 | self.blk[14] = t 213 | # 4th row 214 | t = self.blk[3] 215 | self.blk[3] = self.blk[7] 216 | self.blk[7] = self.blk[11] 217 | self.blk[11] = self.blk[15] 218 | self.blk[15] = t 219 | 220 | def ReSubBytes(self): 221 | for i in range(16): 222 | for j in range(256): 223 | if (self.sbox[j] == self.blk[i]): 224 | self.blk[i] = j 225 | break 226 | 227 | def AddRoundKey(self, key): 228 | x = 0 229 | k = [0 for m in range(16)] 230 | for c in range(4): 231 | for r in range(4): 232 | k[x] = key[r][c] 233 | x = x + 1 234 | for y in range(16): 235 | self.blk[y] ^= k[y] 236 | 237 | def ScheduleKey(self, w, Nk): 238 | Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36] 239 | for r in range(4): 240 | for c in range(4): 241 | w[0][r][c] = self.key[r + c * 4] 242 | for i in range(1, self.Nr + 1, 1): 243 | for j in range(Nk): 244 | t = [0 for x in range(4)] 245 | for r in range(4): 246 | if j: 247 | t[r] = w[i][r][j - 1] 248 | else: 249 | t[r] = w[i - 1][r][3] 250 | if j == 0: 251 | temp = t[0] 252 | for r in range(3): 253 | t[r] = self.sbox[t[(r + 1) % 4]] 254 | t[3] = self.sbox[temp] 255 | t[0] ^= int(Rcon[i - 1]) 256 | for r in range(4): 257 | w[i][r][j] = w[i - 1][r][j] ^ t[r] 258 | 259 | def AesDecrpyt(self): 260 | outkey = [] 261 | outkey = [[[0 for col in range(4)] for row in range(4)] for s in range(11)] 262 | self.ScheduleKey(outkey, 4) 263 | self.AddRoundKey(outkey[10]) 264 | self.ReShiftRows() 265 | self.ReSubBytes() 266 | for x in range(self.Nr - 1, 0, -1): 267 | self.AddRoundKey(outkey[x]) 268 | self.ReMixColumns() 269 | self.ReShiftRows() 270 | self.ReSubBytes() 271 | self.AddRoundKey(outkey[0]) 272 | mText = "" 273 | for x in range(16): 274 | mText += chr(self.blk[x]) 275 | return mText.rstrip(chr(0)) 276 | 277 | 278 | def StringToListN(string): 279 | s = [0 for x in range(16)] 280 | strLen = len(string) 281 | for x in range(strLen): 282 | s[x] = int(ord(string[x])) 283 | return s 284 | 285 | def HexToInt(string): 286 | s = [0 for x in range(16)] 287 | for i in range(16): 288 | s[i] = int(string[2 * i:2 * i + 2], 16) 289 | return s 290 | 291 | def encrypt(plainText, skey): 292 | cText = "" 293 | key = StringToListN(skey) 294 | number = int(len(plainText) / 16) 295 | if (len(plainText) % 16 != 0): 296 | number = number + 1 297 | for i in range(0, number): 298 | blk = StringToListN(plainText[i * 16:i * 16 + 16]) 299 | a = AESE(blk, key, 10) 300 | cText = cText + a.AesEncrypt() 301 | return cText 302 | 303 | def decrypt(cText, skey): 304 | mText = "" 305 | if (len(cText) % 32 != 0): 306 | print("密文位数错误!") 307 | exit(0) 308 | for i in cText: 309 | if (i not in string.digits + string.ascii_letters): 310 | print("密文格式错误!") 311 | exit(0) 312 | key = StringToListN(skey) 313 | number = int(len(cText) / 32) 314 | for i in range(0, number): 315 | rblk = HexToInt(cText[i * 32:i * 32 + 32]) 316 | b = AESD(rblk, key, 10) 317 | mText = mText + b.AesDecrpyt() 318 | return mText 319 | -------------------------------------------------------------------------------- /algorithm/hash_algorithm/md5.py: -------------------------------------------------------------------------------- 1 | class MD5: 2 | 3 | def __init__(self): 4 | super().__init__() 5 | 6 | def md5_file(filename): 7 | 8 | f1 = open(filename, "rb") 9 | p = f1.read() 10 | x = p.__len__() 11 | plaintext = '' 12 | for i in range(x): 13 | plaintext = plaintext + bin(p[i])[2:].zfill(8) 14 | A = 0x67452301 15 | B = 0xefcdab89 16 | C = 0x98badcfe 17 | D = 0x10325476 18 | bintext = plaintext 19 | t = bintext.__len__() % 512 20 | suffix_bits = bin(bintext.__len__())[2:].zfill(64) 21 | if t < 448: 22 | bintext = bintext + '1' 23 | for i in range(447 - t): 24 | bintext = bintext + '0' 25 | else: 26 | bintext = bintext + '1' 27 | for i in range(959 - t): 28 | bintext = bintext + '0' 29 | 30 | sectext = bintext + suffix_bits 31 | x = sectext.__len__() / 512 32 | M = [[[0] * 1 for _ in range(16)] for _ in range(int(x))] 33 | M[0][0][0] = 1 34 | for i in range(int(x)): 35 | for j in range(16): 36 | ix = 3 37 | for k in range(1): 38 | x = sectext[i * 512 + j * 32:i * 512 + j * 32 + 32] 39 | y = x[24:32] + x[16:24] + x[8:16] + x[0:8] 40 | M[i][j][k] = int(y, 2) 41 | 42 | def F(x, y, z): 43 | return (x & y) | ((~x) & z) 44 | 45 | def G(x, y, z): 46 | return (x & z) | (y & (~z)) 47 | 48 | def H(x, y, z): 49 | return x ^ y ^ z 50 | 51 | def I(x, y, z): 52 | return y ^ (x | (~z)) 53 | 54 | def rotate_left(x, z): 55 | x = x & 0xffffffff 56 | y = bin(x).replace('0b', '') 57 | tt = y.__len__() 58 | if tt < 32: 59 | y = y.zfill(32) 60 | t = y[z:] + y[:z] 61 | return int(t, 2) 62 | else: 63 | x = y[tt - 32:] 64 | t = x[z:] + x[:z] 65 | return int(t, 2) 66 | 67 | def FF(a, b, c, d, M, s, t): 68 | a = b + rotate_left((a + F(b, c, d) + M + t), s) 69 | return a & 0xffffffff 70 | 71 | def GG(a, b, c, d, M, s, t): 72 | a = b + rotate_left((a + G(b, c, d) + M + t), s) 73 | return a & 0xffffffff 74 | 75 | def HH(a, b, c, d, M, s, t): 76 | a = b + rotate_left((a + H(b, c, d) + M + t), s) 77 | return a & 0xffffffff 78 | 79 | def II(a, b, c, d, M, s, t): 80 | a = b + rotate_left((a + I(b, c, d) + M + t), s) 81 | return a & 0xffffffff 82 | 83 | for i in range(int(sectext.__len__() / 512)): 84 | a = A 85 | b = B 86 | c = C 87 | d = D 88 | a = FF(a, b, c, d, M[i][0][0], 7, 0xd76aa478) 89 | d = FF(d, a, b, c, M[i][1][0], 12, 0xe8c7b756) 90 | c = FF(c, d, a, b, M[i][2][0], 17, 0x242070db) 91 | b = FF(b, c, d, a, M[i][3][0], 22, 0xc1bdceee) 92 | a = FF(a, b, c, d, M[i][4][0], 7, 0xf57c0faf) 93 | d = FF(d, a, b, c, M[i][5][0], 12, 0x4787c62a) 94 | c = FF(c, d, a, b, M[i][6][0], 17, 0xa8304613) 95 | b = FF(b, c, d, a, M[i][7][0], 22, 0xfd469501) 96 | a = FF(a, b, c, d, M[i][8][0], 7, 0x698098d8) 97 | d = FF(d, a, b, c, M[i][9][0], 12, 0x8b44f7af) 98 | c = FF(c, d, a, b, M[i][10][0], 17, 0xffff5bb1) 99 | b = FF(b, c, d, a, M[i][11][0], 22, 0x895cd7be) 100 | a = FF(a, b, c, d, M[i][12][0], 7, 0x6b901122) 101 | d = FF(d, a, b, c, M[i][13][0], 12, 0xfd987193) 102 | c = FF(c, d, a, b, M[i][14][0], 17, 0xa679438e) 103 | b = FF(b, c, d, a, M[i][15][0], 22, 0x49b40821) 104 | a = GG(a, b, c, d, M[i][1][0], 5, 0xf61e2562) 105 | d = GG(d, a, b, c, M[i][6][0], 9, 0xc040b340) 106 | c = GG(c, d, a, b, M[i][11][0], 14, 0x265e5a51) 107 | b = GG(b, c, d, a, M[i][0][0], 20, 0xe9b6c7aa) 108 | a = GG(a, b, c, d, M[i][5][0], 5, 0xd62f105d) 109 | d = GG(d, a, b, c, M[i][10][0], 9, 0x02441453) 110 | c = GG(c, d, a, b, M[i][15][0], 14, 0xd8a1e681) 111 | b = GG(b, c, d, a, M[i][4][0], 20, 0xe7d3fbc8) 112 | a = GG(a, b, c, d, M[i][9][0], 5, 0x21e1cde6) 113 | d = GG(d, a, b, c, M[i][14][0], 9, 0xc33707d6) 114 | c = GG(c, d, a, b, M[i][3][0], 14, 0xf4d50d87) 115 | b = GG(b, c, d, a, M[i][8][0], 20, 0x455a14ed) 116 | a = GG(a, b, c, d, M[i][13][0], 5, 0xa9e3e905) 117 | d = GG(d, a, b, c, M[i][2][0], 9, 0xfcefa3f8) 118 | c = GG(c, d, a, b, M[i][7][0], 14, 0x676f02d9) 119 | b = GG(b, c, d, a, M[i][12][0], 20, 0x8d2a4c8a) 120 | a = HH(a, b, c, d, M[i][5][0], 4, 0xfffa3942) 121 | d = HH(d, a, b, c, M[i][8][0], 11, 0x8771f681) 122 | c = HH(c, d, a, b, M[i][11][0], 16, 0x6d9d6122) 123 | b = HH(b, c, d, a, M[i][14][0], 23, 0xfde5380c) 124 | a = HH(a, b, c, d, M[i][1][0], 4, 0xa4beea44) 125 | d = HH(d, a, b, c, M[i][4][0], 11, 0x4bdecfa9) 126 | c = HH(c, d, a, b, M[i][7][0], 16, 0xf6bb4b60) 127 | b = HH(b, c, d, a, M[i][10][0], 23, 0xbebfbc70) 128 | a = HH(a, b, c, d, M[i][13][0], 4, 0x289b7ec6) 129 | d = HH(d, a, b, c, M[i][0][0], 11, 0xeaa127fa) 130 | c = HH(c, d, a, b, M[i][3][0], 16, 0xd4ef3085) 131 | b = HH(b, c, d, a, M[i][6][0], 23, 0x04881d05) 132 | a = HH(a, b, c, d, M[i][9][0], 4, 0xd9d4d039) 133 | d = HH(d, a, b, c, M[i][12][0], 11, 0xe6db99e5) 134 | c = HH(c, d, a, b, M[i][15][0], 16, 0x1fa27cf8) 135 | b = HH(b, c, d, a, M[i][2][0], 23, 0xc4ac5665) 136 | 137 | a = II(a, b, c, d, M[i][0][0], 6, 0xf4292244) 138 | d = II(d, a, b, c, M[i][7][0], 10, 0x432aff97) 139 | c = II(c, d, a, b, M[i][14][0], 15, 0xab9423a7) 140 | b = II(b, c, d, a, M[i][5][0], 21, 0xfc93a039) 141 | a = II(a, b, c, d, M[i][12][0], 6, 0x655b59c3) 142 | d = II(d, a, b, c, M[i][3][0], 10, 0x8f0ccc92) 143 | c = II(c, d, a, b, M[i][10][0], 15, 0xffeff47d) 144 | b = II(b, c, d, a, M[i][1][0], 21, 0x85845dd1) 145 | a = II(a, b, c, d, M[i][8][0], 6, 0x6fa87e4f) 146 | d = II(d, a, b, c, M[i][15][0], 10, 0xfe2ce6e0) 147 | c = II(c, d, a, b, M[i][6][0], 15, 0xa3014314) 148 | b = II(b, c, d, a, M[i][13][0], 21, 0x4e0811a1) 149 | a = II(a, b, c, d, M[i][4][0], 6, 0xf7537e82) 150 | d = II(d, a, b, c, M[i][11][0], 10, 0xbd3af235) 151 | c = II(c, d, a, b, M[i][2][0], 15, 0x2ad7d2bb) 152 | b = II(b, c, d, a, M[i][9][0], 21, 0xeb86d391) 153 | A = (A + a) & 0xffffffff 154 | B = (B + b) & 0xffffffff 155 | C = (C + c) & 0xffffffff 156 | D = (D + d) & 0xffffffff 157 | 158 | d = (hex(D)[2:])[6:8] + (hex(D)[2:])[4:6] + (hex(D)[2:])[2:4] + (hex(D)[2:])[0:2] 159 | c = (hex(C)[2:])[6:8] + (hex(C)[2:])[4:6] + (hex(C)[2:])[2:4] + (hex(C)[2:])[0:2] 160 | b = (hex(B)[2:])[6:8] + (hex(B)[2:])[4:6] + (hex(B)[2:])[2:4] + (hex(B)[2:])[0:2] 161 | a = (hex(A)[2:])[6:8] + (hex(A)[2:])[4:6] + (hex(A)[2:])[2:4] + (hex(A)[2:])[0:2] 162 | 163 | return a + b + c + d 164 | 165 | def md5_string(string): 166 | def encode(s): 167 | return ''.join([bin(ord(c)).replace('0b', '').zfill(8) for c in s]) 168 | 169 | def decode(s): 170 | return ''.join([chr(i) for i in [int(b, 2) for b in s.split(' ')]]) 171 | 172 | plaintext = string 173 | # 链接变量 174 | A = 0x67452301 175 | B = 0xefcdab89 176 | C = 0x98badcfe 177 | D = 0x10325476 178 | bintext = encode(plaintext) 179 | # print(encrypt(plaintext)) 180 | # print(encrypt(plaintext).__len__()) 181 | t = bintext.__len__() % 512 182 | # print(t) 183 | suffix_bits = bin(bintext.__len__())[2:].zfill(64) 184 | # 最终长度后缀(比特长度,64位) 185 | if t < 448: # 补齐 186 | bintext = bintext + '1' 187 | for i in range(447 - t): 188 | bintext = bintext + '0' 189 | else: 190 | bintext = bintext + '1' 191 | for i in range(959 - t): 192 | bintext = bintext + '0' 193 | 194 | sectext = bintext + suffix_bits # 最终的明文 195 | x = sectext.__len__() / 512 196 | M = [[[0] * 1 for _ in range(16)] for _ in range(int(x))] 197 | M[0][0][0] = 1 198 | for i in range(int(x)): 199 | for j in range(16): 200 | ix = 3 201 | for k in range(1): 202 | x = sectext[i * 512 + j * 32:i * 512 + j * 32 + 32] 203 | y = x[24:32] + x[16:24] + x[8:16] + x[0:8] 204 | M[i][j][k] = int(y, 2) 205 | 206 | def F(x, y, z): 207 | return (x & y) | ((~x) & z) 208 | 209 | def G(x, y, z): 210 | return (x & z) | (y & (~z)) 211 | 212 | def H(x, y, z): 213 | return x ^ y ^ z 214 | 215 | def I(x, y, z): 216 | return y ^ (x | (~z)) 217 | 218 | def rotate_left(x, z): 219 | x = x & 0xffffffff 220 | y = bin(x).replace('0b', '') 221 | tt = y.__len__() 222 | if tt < 32: 223 | y = y.zfill(32) 224 | t = y[z:] + y[:z] 225 | return int(t, 2) 226 | else: 227 | x = y[tt - 32:] 228 | t = x[z:] + x[:z] 229 | return int(t, 2) 230 | 231 | def FF(a, b, c, d, M, s, t): 232 | a = b + rotate_left((a + F(b, c, d) + M + t), s) 233 | return a & 0xffffffff 234 | 235 | def GG(a, b, c, d, M, s, t): 236 | a = b + rotate_left((a + G(b, c, d) + M + t), s) 237 | return a & 0xffffffff 238 | 239 | def HH(a, b, c, d, M, s, t): 240 | a = b + rotate_left((a + H(b, c, d) + M + t), s) 241 | return a & 0xffffffff 242 | 243 | def II(a, b, c, d, M, s, t): 244 | a = b + rotate_left((a + I(b, c, d) + M + t), s) 245 | return a & 0xffffffff 246 | 247 | for i in range(int(sectext.__len__() / 512)): 248 | a = A 249 | b = B 250 | c = C 251 | d = D 252 | # 第一轮循环 253 | a = FF(a, b, c, d, M[i][0][0], 7, 0xd76aa478) 254 | d = FF(d, a, b, c, M[i][1][0], 12, 0xe8c7b756) 255 | c = FF(c, d, a, b, M[i][2][0], 17, 0x242070db) 256 | b = FF(b, c, d, a, M[i][3][0], 22, 0xc1bdceee) 257 | a = FF(a, b, c, d, M[i][4][0], 7, 0xf57c0faf) 258 | d = FF(d, a, b, c, M[i][5][0], 12, 0x4787c62a) 259 | c = FF(c, d, a, b, M[i][6][0], 17, 0xa8304613) 260 | b = FF(b, c, d, a, M[i][7][0], 22, 0xfd469501) 261 | a = FF(a, b, c, d, M[i][8][0], 7, 0x698098d8) 262 | d = FF(d, a, b, c, M[i][9][0], 12, 0x8b44f7af) 263 | c = FF(c, d, a, b, M[i][10][0], 17, 0xffff5bb1) 264 | b = FF(b, c, d, a, M[i][11][0], 22, 0x895cd7be) 265 | a = FF(a, b, c, d, M[i][12][0], 7, 0x6b901122) 266 | d = FF(d, a, b, c, M[i][13][0], 12, 0xfd987193) 267 | c = FF(c, d, a, b, M[i][14][0], 17, 0xa679438e) 268 | b = FF(b, c, d, a, M[i][15][0], 22, 0x49b40821) 269 | # 第二轮循环 270 | a = GG(a, b, c, d, M[i][1][0], 5, 0xf61e2562) 271 | d = GG(d, a, b, c, M[i][6][0], 9, 0xc040b340) 272 | c = GG(c, d, a, b, M[i][11][0], 14, 0x265e5a51) 273 | b = GG(b, c, d, a, M[i][0][0], 20, 0xe9b6c7aa) 274 | a = GG(a, b, c, d, M[i][5][0], 5, 0xd62f105d) 275 | d = GG(d, a, b, c, M[i][10][0], 9, 0x02441453) 276 | c = GG(c, d, a, b, M[i][15][0], 14, 0xd8a1e681) 277 | b = GG(b, c, d, a, M[i][4][0], 20, 0xe7d3fbc8) 278 | a = GG(a, b, c, d, M[i][9][0], 5, 0x21e1cde6) 279 | d = GG(d, a, b, c, M[i][14][0], 9, 0xc33707d6) 280 | c = GG(c, d, a, b, M[i][3][0], 14, 0xf4d50d87) 281 | b = GG(b, c, d, a, M[i][8][0], 20, 0x455a14ed) 282 | a = GG(a, b, c, d, M[i][13][0], 5, 0xa9e3e905) 283 | d = GG(d, a, b, c, M[i][2][0], 9, 0xfcefa3f8) 284 | c = GG(c, d, a, b, M[i][7][0], 14, 0x676f02d9) 285 | b = GG(b, c, d, a, M[i][12][0], 20, 0x8d2a4c8a) 286 | # 第三轮循环 287 | a = HH(a, b, c, d, M[i][5][0], 4, 0xfffa3942) 288 | d = HH(d, a, b, c, M[i][8][0], 11, 0x8771f681) 289 | c = HH(c, d, a, b, M[i][11][0], 16, 0x6d9d6122) 290 | b = HH(b, c, d, a, M[i][14][0], 23, 0xfde5380c) 291 | a = HH(a, b, c, d, M[i][1][0], 4, 0xa4beea44) 292 | d = HH(d, a, b, c, M[i][4][0], 11, 0x4bdecfa9) 293 | c = HH(c, d, a, b, M[i][7][0], 16, 0xf6bb4b60) 294 | b = HH(b, c, d, a, M[i][10][0], 23, 0xbebfbc70) 295 | a = HH(a, b, c, d, M[i][13][0], 4, 0x289b7ec6) 296 | d = HH(d, a, b, c, M[i][0][0], 11, 0xeaa127fa) 297 | c = HH(c, d, a, b, M[i][3][0], 16, 0xd4ef3085) 298 | b = HH(b, c, d, a, M[i][6][0], 23, 0x04881d05) 299 | a = HH(a, b, c, d, M[i][9][0], 4, 0xd9d4d039) 300 | d = HH(d, a, b, c, M[i][12][0], 11, 0xe6db99e5) 301 | c = HH(c, d, a, b, M[i][15][0], 16, 0x1fa27cf8) 302 | b = HH(b, c, d, a, M[i][2][0], 23, 0xc4ac5665) 303 | 304 | # 第四轮循环 305 | a = II(a, b, c, d, M[i][0][0], 6, 0xf4292244) 306 | d = II(d, a, b, c, M[i][7][0], 10, 0x432aff97) 307 | c = II(c, d, a, b, M[i][14][0], 15, 0xab9423a7) 308 | b = II(b, c, d, a, M[i][5][0], 21, 0xfc93a039) 309 | a = II(a, b, c, d, M[i][12][0], 6, 0x655b59c3) 310 | d = II(d, a, b, c, M[i][3][0], 10, 0x8f0ccc92) 311 | c = II(c, d, a, b, M[i][10][0], 15, 0xffeff47d) 312 | b = II(b, c, d, a, M[i][1][0], 21, 0x85845dd1) 313 | a = II(a, b, c, d, M[i][8][0], 6, 0x6fa87e4f) 314 | d = II(d, a, b, c, M[i][15][0], 10, 0xfe2ce6e0) 315 | c = II(c, d, a, b, M[i][6][0], 15, 0xa3014314) 316 | b = II(b, c, d, a, M[i][13][0], 21, 0x4e0811a1) 317 | a = II(a, b, c, d, M[i][4][0], 6, 0xf7537e82) 318 | d = II(d, a, b, c, M[i][11][0], 10, 0xbd3af235) 319 | c = II(c, d, a, b, M[i][2][0], 15, 0x2ad7d2bb) 320 | b = II(b, c, d, a, M[i][9][0], 21, 0xeb86d391) 321 | A = (A + a) & 0xffffffff 322 | B = (B + b) & 0xffffffff 323 | C = (C + c) & 0xffffffff 324 | D = (D + d) & 0xffffffff 325 | 326 | d = (hex(D)[2:])[6:8] + (hex(D)[2:])[4:6] + (hex(D)[2:])[2:4] + (hex(D)[2:])[0:2] 327 | c = (hex(C)[2:])[6:8] + (hex(C)[2:])[4:6] + (hex(C)[2:])[2:4] + (hex(C)[2:])[0:2] 328 | b = (hex(B)[2:])[6:8] + (hex(B)[2:])[4:6] + (hex(B)[2:])[2:4] + (hex(B)[2:])[0:2] 329 | a = (hex(A)[2:])[6:8] + (hex(A)[2:])[4:6] + (hex(A)[2:])[2:4] + (hex(A)[2:])[0:2] 330 | return a + b + c + d 331 | -------------------------------------------------------------------------------- /algorithm/public_cipher/ecc/ecc.py: -------------------------------------------------------------------------------- 1 | # from Crypto.PublicKey import ECC 2 | import collections 3 | import random 4 | 5 | from algorithm.public_cipher.ecc import func 6 | from algorithm.public_cipher.ecc import sm3 7 | 8 | # 待办:支持多种曲线 9 | # 待办:支持以PEM格式导入和导出密钥 10 | 11 | EllipticCurve = collections.namedtuple('EllipticCurve', 'name p a b g n h') 12 | # T=(p,a,b,g,n,h)。 13 | # (p为模 用来将曲线离散化如y^2=x^3+ax+b(mod p)此时称曲线在模p后的取值Fp为有限域 14 | # Fp中只有p(p为素数)个元素0,1,2 …… p-2,p-1; 15 | # Fp 的加法(a+b)法则是 a+b≡c (mod p);即,(a+c)÷p的余数 和c÷p的余数相同。 16 | # Fp 的乘法(a×b)法则是 a×b≡c (mod p); 17 | # Fp 的除法(a÷b)法则是 a/b≡c (mod p);即 a×b-1≡c (mod p);(b-1也是一个0到p-1之间的整数,但满足b×b-1≡1 (mod p);具体求法可以参考初等数论,或我的另一篇文章)。 18 | # Fp 的单位元是1,零元是 0。 19 | # 、a 、b 用来确定一条椭圆曲线, 20 | # g为基点, 21 | # n为点G的阶, 22 | # h 是椭圆曲线上所有点的个数m与n相除的整数部分) 23 | # 这几个参量取值的选择,直接影响了加密的安全性。参量值一般要求满足以下几个条件: 24 | # 1、p 当然越大越安全,但越大,计算速度会变慢,200位左右可以满足一般安全要求; 25 | # 2、p≠n×h; 26 | # 3、pt≠1 (mod n),1≤t<20; 27 | # 4、4a3+27b2≠0 (mod p); 28 | # 5、n 为素数; 29 | # 6、h≤4。 30 | 31 | # 根据国家密码管理局公告 32 | # (第 21 号) 33 | # 推荐曲线 公式:y^2 = x^3 + ax +b 34 | # 各参数如下 35 | curve = EllipticCurve( 36 | "sm2p256v1", 37 | p=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF, 38 | a=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC, 39 | b=0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93, 40 | g=(0x32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7, 41 | 0xbc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0), 42 | n=0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123, 43 | h=1, 44 | ) 45 | 46 | default_ecc_table = { 47 | 'n': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123', 48 | 'p': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF', 49 | 'g': '32c4ae2c1f1981195f9904466a39c9948fe30bbff2660be1715a4589334c74c7' 50 | 'bc3736a2f4f6779c59bdcee36b692153d0a9877cc62a474002df32e52139f0a0', 51 | 'a': 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC', 52 | 'b': '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93', 53 | } 54 | standard_public_key = 'B9C9A6E04E9C91F7BA880429273747D7EF5DDEB0BB2FF6317EB00BEF331A83081A6994B8993F3F5D6EADDDB818' \ 55 | '72266C87C018FB4162F5AF347B483E24620207' 56 | standard_private_key = '00B9AB0B828FF68872F21A837FC303668428DEA11DCD1B24429D0C99E24EED83D5' 57 | 58 | 59 | class EccCipher: 60 | 61 | def __init__(self, private_key=standard_private_key, public_key=standard_public_key, ecc_table=default_ecc_table): 62 | self.private_key = private_key 63 | self.public_key = public_key 64 | self.para_len = len(ecc_table['n']) 65 | self.ecc_table = ecc_table 66 | self.ecc_a3 = ( 67 | int(ecc_table['a'], base=16) + 3) % int(ecc_table['p'], base=16) 68 | 69 | def inverse_mod(self, k, p): 70 | """ 71 | 求k模p的逆元x(x满足(x * k) % p == 1)k必须非零,p必须是素数 72 | """ 73 | if k == 0: 74 | raise ZeroDivisionError('division by zero') 75 | 76 | if k < 0: 77 | # k ** -1 = p - (-k) ** -1 (mod p) 78 | return p - self.inverse_mod(-k, p) 79 | 80 | s, old_s = 0, 1 81 | t, old_t = 1, 0 82 | r, old_r = p, k 83 | 84 | while r != 0: 85 | quotient = old_r // r 86 | old_r, r = r, old_r - quotient * r 87 | old_s, s = s, old_s - quotient * s 88 | old_t, t = t, old_t - quotient * t 89 | 90 | gcd, x, y = old_r, old_s, old_t 91 | assert gcd == 1 92 | assert (k * x) % p == 1 93 | return x % p 94 | 95 | # 判断点是否在曲线上 96 | @staticmethod 97 | def is_on_curve(point): 98 | if point is None: 99 | return True 100 | x, y = point 101 | return (y * y - x * x * x - curve.a * x - curve.b) % curve.p == 0 102 | 103 | # 返回点关于x轴对称的一点 对称映射 104 | def point_neg(self, point): 105 | assert self.is_on_curve(point) 106 | if point is None: 107 | # -0 = 0 108 | return None 109 | 110 | x, y = point 111 | result = (x, -y % curve.p) 112 | 113 | assert self.is_on_curve(result) 114 | 115 | return result 116 | 117 | # 点1和点2相加 根据群论公式 118 | def point_add(self, point1, point2): 119 | assert self.is_on_curve(point1) 120 | assert self.is_on_curve(point2) 121 | 122 | if point1 is None: 123 | # 0 + point2 = point2 124 | return point2 125 | if point2 is None: 126 | # point1 + 0 = point1 127 | return point1 128 | 129 | x1, y1 = point1 130 | x2, y2 = point2 131 | 132 | if x1 == x2 and y1 != y2: 133 | # 即关于x轴对称 134 | return None 135 | 136 | if x1 == x2: 137 | # 即点1和点2重合时,此时直线为曲线的切线,切线斜率则为 138 | m = (3 * x1 * x1 + curve.a) * self.inverse_mod(2 * y1, curve.p) 139 | else: 140 | # 点1和点2不重合 141 | # m = (y2 - y1) * (x2 - x1) ^ (-1) mod p; ^(-1)意为逆元 142 | m = (y1 - y2) * self.inverse_mod(x1 - x2, curve.p) 143 | 144 | x3 = m * m - x1 - x2 145 | y3 = y1 + m * (x3 - x1) 146 | result = (x3 % curve.p, 147 | -y3 % curve.p) 148 | 149 | assert self.is_on_curve(result) 150 | return result 151 | 152 | # 做k * 点运算,生成的点还是在曲线上 153 | def scalar_multiply(self, k, point): 154 | """ 155 | 生成Pa = kG中的Pa 156 | """ 157 | assert self.is_on_curve(point) 158 | 159 | if k % curve.n == 0 or point is None: 160 | return None 161 | 162 | if k < 0: 163 | # k * point = -k * (-point) 164 | return self.scalar_multiply(-k, self.point_neg(point)) 165 | 166 | result = None 167 | addend = point 168 | 169 | while k: 170 | if k == 1: 171 | result = self.point_add(result, addend) 172 | addend = self.point_add(addend, addend) 173 | k >>= 1 174 | 175 | assert self.is_on_curve(result) 176 | 177 | return result 178 | 179 | # 生成ECC公钥和私钥 180 | def make_key_pair(self): 181 | # 生成随机数K用作私钥 公式 Pa = kG中的k 182 | private_key = random.randrange(1, curve.n) 183 | # 计算公钥中的Pa,与G共同组成公钥 184 | # 传入k和基点G:curve.g 185 | public_key = self.scalar_multiply(private_key, curve.g) 186 | return private_key, public_key 187 | 188 | def generate(self): 189 | return self.make_key_pair() 190 | 191 | def _double_point(self, point): 192 | """倍点""" 193 | l = len(point) 194 | len_2 = 2 * self.para_len 195 | if l < self.para_len * 2: 196 | return None 197 | else: 198 | x1 = int(point[0:self.para_len], 16) 199 | y1 = int(point[self.para_len:len_2], 16) 200 | if l == len_2: 201 | z1 = 1 202 | else: 203 | z1 = int(point[len_2:], 16) 204 | 205 | T6 = (z1 * z1) % int(self.ecc_table['p'], base=16) 206 | T2 = (y1 * y1) % int(self.ecc_table['p'], base=16) 207 | T3 = (x1 + T6) % int(self.ecc_table['p'], base=16) 208 | T4 = (x1 - T6) % int(self.ecc_table['p'], base=16) 209 | T1 = (T3 * T4) % int(self.ecc_table['p'], base=16) 210 | T3 = (y1 * z1) % int(self.ecc_table['p'], base=16) 211 | T4 = (T2 * 8) % int(self.ecc_table['p'], base=16) 212 | T5 = (x1 * T4) % int(self.ecc_table['p'], base=16) 213 | T1 = (T1 * 3) % int(self.ecc_table['p'], base=16) 214 | T6 = (T6 * T6) % int(self.ecc_table['p'], base=16) 215 | T6 = (self.ecc_a3 * T6) % int(self.ecc_table['p'], base=16) 216 | T1 = (T1 + T6) % int(self.ecc_table['p'], base=16) 217 | z3 = (T3 + T3) % int(self.ecc_table['p'], base=16) 218 | T3 = (T1 * T1) % int(self.ecc_table['p'], base=16) 219 | T2 = (T2 * T4) % int(self.ecc_table['p'], base=16) 220 | x3 = (T3 - T5) % int(self.ecc_table['p'], base=16) 221 | 222 | if (T5 % 2) == 1: 223 | T4 = (T5 + ((T5 + int(self.ecc_table['p'], base=16)) >> 1) - T3) % int(self.ecc_table['p'], base=16) 224 | else: 225 | T4 = (T5 + (T5 >> 1) - T3) % int(self.ecc_table['p'], base=16) 226 | 227 | T1 = (T1 * T4) % int(self.ecc_table['p'], base=16) 228 | y3 = (T1 - T2) % int(self.ecc_table['p'], base=16) 229 | 230 | form = '%%0%dx' % self.para_len 231 | form = form * 3 232 | return form % (x3, y3, z3) 233 | 234 | def _add_point(self, P1, P2): 235 | """点加函数,P2点为仿射坐标即z=1,P1为Jacobian加重射影坐标""" 236 | len_2 = 2 * self.para_len 237 | l1 = len(P1) 238 | l2 = len(P2) 239 | if (l1 < len_2) or (l2 < len_2): 240 | return None 241 | else: 242 | X1 = int(P1[0:self.para_len], 16) 243 | Y1 = int(P1[self.para_len:len_2], 16) 244 | if l1 == len_2: 245 | Z1 = 1 246 | else: 247 | Z1 = int(P1[len_2:], 16) 248 | x2 = int(P2[0:self.para_len], 16) 249 | y2 = int(P2[self.para_len:len_2], 16) 250 | 251 | T1 = (Z1 * Z1) % int(self.ecc_table['p'], base=16) 252 | T2 = (y2 * Z1) % int(self.ecc_table['p'], base=16) 253 | T3 = (x2 * T1) % int(self.ecc_table['p'], base=16) 254 | T1 = (T1 * T2) % int(self.ecc_table['p'], base=16) 255 | T2 = (T3 - X1) % int(self.ecc_table['p'], base=16) 256 | T3 = (T3 + X1) % int(self.ecc_table['p'], base=16) 257 | T4 = (T2 * T2) % int(self.ecc_table['p'], base=16) 258 | T1 = (T1 - Y1) % int(self.ecc_table['p'], base=16) 259 | Z3 = (Z1 * T2) % int(self.ecc_table['p'], base=16) 260 | T2 = (T2 * T4) % int(self.ecc_table['p'], base=16) 261 | T3 = (T3 * T4) % int(self.ecc_table['p'], base=16) 262 | T5 = (T1 * T1) % int(self.ecc_table['p'], base=16) 263 | T4 = (X1 * T4) % int(self.ecc_table['p'], base=16) 264 | X3 = (T5 - T3) % int(self.ecc_table['p'], base=16) 265 | T2 = (Y1 * T2) % int(self.ecc_table['p'], base=16) 266 | T3 = (T4 - X3) % int(self.ecc_table['p'], base=16) 267 | T1 = (T1 * T3) % int(self.ecc_table['p'], base=16) 268 | Y3 = (T1 - T2) % int(self.ecc_table['p'], base=16) 269 | form = '%%0%dx' % self.para_len 270 | form = form * 3 271 | return form % (X3, Y3, Z3) 272 | 273 | def _convert_jacb_to_nor(self, point): 274 | """Jacobian加重射影坐标转换成仿射坐标""" 275 | len_2 = 2 * self.para_len 276 | x = int(point[0:self.para_len], 16) 277 | y = int(point[self.para_len:len_2], 16) 278 | z = int(point[len_2:], 16) 279 | z_inv = pow(z, int(self.ecc_table['p'], base=16) - 2, int(self.ecc_table['p'], base=16)) 280 | z_invSquar = (z_inv * z_inv) % int(self.ecc_table['p'], base=16) 281 | z_invQube = (z_invSquar * z_inv) % int(self.ecc_table['p'], base=16) 282 | x_new = (x * z_invSquar) % int(self.ecc_table['p'], base=16) 283 | y_new = (y * z_invQube) % int(self.ecc_table['p'], base=16) 284 | z_new = (z * z_inv) % int(self.ecc_table['p'], base=16) 285 | if z_new == 1: 286 | form = '%%0%dx' % self.para_len 287 | form = form * 2 288 | return form % (x_new, y_new) 289 | else: 290 | return None 291 | 292 | def _kg(self, k, point): # kP运算 293 | # 末尾加字符1,表示映射到z轴 294 | point = '%s%s' % (point, '1') 295 | mask_str = '8' 296 | for i in range(self.para_len - 1): 297 | mask_str += '0' 298 | mask = int(mask_str, 16) 299 | temp = point 300 | flag = False 301 | for n in range(self.para_len * 4): 302 | if flag: 303 | temp = self._double_point(temp) 304 | if (k & mask) != 0: 305 | if flag: 306 | temp = self._add_point(temp, point) 307 | else: 308 | flag = True 309 | temp = point 310 | k = k << 1 311 | return self._convert_jacb_to_nor(temp) 312 | 313 | def encrypt(self, data): 314 | # 加密函数,data消息(bytes) 315 | msg = data.hex() # 消息转化为16进制字符串 316 | k = func.random_hex(self.para_len) 317 | c1 = self._kg(int(k, 16), self.ecc_table['g']) 318 | xy = self._kg(int(k, 16), self.public_key) 319 | x2 = xy[0:self.para_len] 320 | y2 = xy[self.para_len:2 * self.para_len] 321 | ml = len(msg) 322 | t = sm3.sm3_kdf(xy.encode('utf8'), ml / 2) 323 | if int(t, 16) == 0: 324 | return None 325 | else: 326 | form = '%%0%dx' % ml 327 | c2 = form % (int(msg, 16) ^ int(t, 16)) 328 | c3 = sm3.sm3_hash([ 329 | i for i in bytes.fromhex('%s%s%s' % (x2, msg, y2)) 330 | ]) 331 | return bytes.fromhex('%s%s%s' % (c1, c3, c2)) 332 | 333 | def decrypt(self, data): 334 | # 解密函数,data密文(bytes) 335 | data = data.hex() 336 | len_2 = 2 * self.para_len 337 | len_3 = len_2 + 64 338 | c1 = data[0:len_2] 339 | c3 = data[len_2:len_3] 340 | c2 = data[len_3:] 341 | xy = self._kg(int(self.private_key, 16), c1) 342 | x2 = xy[0:self.para_len] 343 | y2 = xy[self.para_len:len_2] 344 | cl = len(c2) 345 | t = sm3.sm3_kdf(xy.encode('utf8'), cl / 2) 346 | if int(t, 16) == 0: 347 | return None 348 | else: 349 | form = '%%0%dx' % cl 350 | M = form % (int(c2, 16) ^ int(t, 16)) 351 | u = sm3.sm3_hash([ 352 | i for i in bytes.fromhex('%s%s%s' % (x2, M, y2)) 353 | ]) 354 | return bytes.fromhex(M) 355 | 356 | 357 | def main(): 358 | print('Curve:', curve.name) 359 | c = EccCipher() 360 | private_key, public_key = c.make_key_pair() 361 | 362 | print("生成密钥测试:") 363 | print("私钥d:", private_key) 364 | print("公钥K(x,y):", public_key) 365 | 366 | print("加密字符串测试:") 367 | plain_text = input("请输入要加密的字符串(utf-8字符均可):\n") 368 | cipher_text = c.encrypt(plain_text.encode('utf-8')) 369 | print("加密后的密文是:", cipher_text) 370 | print("解密后的结果是:\n", c.decrypt(cipher_text).decode("utf-8")) 371 | 372 | print("加密文件测试:") 373 | with open("test.rar", 'rb') as f: 374 | cc = c.encrypt(f.read()) 375 | print("加密后的文件:\n", cc) 376 | print("解密后的文件:(应为rar格式)") 377 | print(c.decrypt(cc)) 378 | 379 | print("ECDHE测试:") 380 | alice_private_key, alice_public_key = c.make_key_pair() 381 | print("Alice's private key:", hex(alice_private_key)) 382 | print("Alice's public key: (0x{:x}, 0x{:x})".format(*alice_public_key)) 383 | 384 | bob_private_key, bob_public_key = c.make_key_pair() 385 | print("Bob's private key:", hex(bob_private_key)) 386 | print("Bob's public key: (0x{:x}, 0x{:x})".format(*bob_public_key)) 387 | 388 | s1 = c.scalar_multiply(alice_private_key, bob_public_key) 389 | s2 = c.scalar_multiply(bob_private_key, alice_public_key) 390 | assert s1 == s2 391 | 392 | print('Shared secret in Alice: (0x{:x}, 0x{:x})'.format(*s1)) 393 | print('Shared secret in Bob: (0x{:x}, 0x{:x})'.format(*s2)) 394 | 395 | 396 | if __name__ == '__main__': 397 | main() 398 | -------------------------------------------------------------------------------- /assets/qss/darkstyle.qss: -------------------------------------------------------------------------------- 1 | QProgressBar:horizontal { 2 | border: 1px solid #3A3939; 3 | text-align: center; 4 | padding: 1px; 5 | background: #201F1F; 6 | } 7 | QProgressBar::chunk:horizontal { 8 | background-color: qlineargradient(spread:reflect, x1:1, y1:0.545, x2:1, y2:0, stop:0 rgba(28, 66, 111, 255), stop:1 rgba(37, 87, 146, 255)); 9 | } 10 | 11 | QToolTip 12 | { 13 | border: 1px solid #3A3939; 14 | background-color: rgb(90, 102, 117); 15 | color: white; 16 | padding: 1px; 17 | opacity: 200; 18 | } 19 | 20 | QWidget 21 | { 22 | color: silver; 23 | background-color: #302F2F; 24 | selection-background-color:#78879b; 25 | selection-color: black; 26 | } 27 | 28 | QWidget:item:selected 29 | { 30 | background-color: QLinearGradient( 31 | x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #78879b, stop: 1 #78879b 32 | ); 33 | } 34 | 35 | QMenuBar 36 | { 37 | background-color: #302F2F; 38 | color: silver; 39 | } 40 | 41 | QMenuBar::item 42 | { 43 | background: transparent; 44 | } 45 | 46 | QMenuBar::item:selected 47 | { 48 | background: transparent; 49 | border: 1px solid #3A3939; 50 | } 51 | 52 | QMenuBar::item:pressed 53 | { 54 | border: 1px solid #3A3939; 55 | background-color: #78879b; 56 | color: black; 57 | margin-bottom:-1px; 58 | padding-bottom:1px; 59 | } 60 | 61 | QMenu 62 | { 63 | border: 1px solid #3A3939; 64 | color: silver; 65 | } 66 | 67 | QMenu::item 68 | { 69 | padding: 2px 20px 2px 20px; 70 | } 71 | 72 | QMenu::item:selected 73 | { 74 | color: black; 75 | } 76 | 77 | QWidget:disabled 78 | { 79 | color: #404040; 80 | background-color: #302F2F; 81 | } 82 | 83 | QAbstractItemView 84 | { 85 | alternate-background-color: #3A3939; 86 | color: silver; 87 | border: 1px solid 3A3939; 88 | border-radius: 3px; 89 | padding: 1px; 90 | } 91 | 92 | QWidget:focus, QMenuBar:focus 93 | { 94 | border: 1px solid rgba(48, 86, 111); 95 | } 96 | 97 | QTabWidget:focus, QCheckBox:focus 98 | { 99 | border: none; 100 | } 101 | 102 | QLineEdit 103 | { 104 | background-color: #201F1F; 105 | padding: 2px; 106 | border-style: solid; 107 | border: 1px solid #3A3939; 108 | border-radius: 3px; 109 | color: silver; 110 | } 111 | 112 | QGroupBox { 113 | border:1px solid #3A3939; 114 | border-radius: 7px; 115 | margin-top: 2ex; 116 | } 117 | 118 | QGroupBox::title { 119 | subcontrol-origin: margin; 120 | subcontrol-position: top left; 121 | padding-left: 10px; 122 | padding-right: 10px; 123 | } 124 | 125 | QAbstractScrollArea 126 | { 127 | border-radius: 3px; 128 | border: 1px solid #3A3939; 129 | } 130 | 131 | QScrollBar:horizontal 132 | { 133 | height: 15px; 134 | margin: 0px 11px 0px 11px; 135 | border: 1px solid #3A3939; 136 | border-radius: 6px; 137 | background-color: QLinearGradient( 138 | x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 #302F2F, stop: 1 #484846 139 | ); 140 | } 141 | 142 | QScrollBar::handle:horizontal 143 | { 144 | background-color: QLinearGradient( 145 | x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 #605F5F, stop: 1 #787876 146 | ); 147 | min-width: 5px; 148 | border-radius: 5px; 149 | } 150 | 151 | QScrollBar::sub-line:horizontal 152 | { 153 | border-image: url(icons/right_arrow_disabled.png); 154 | width: 10px; 155 | height: 10px; 156 | subcontrol-position: right; 157 | subcontrol-origin: margin; 158 | } 159 | 160 | QScrollBar::add-line:horizontal 161 | { 162 | border-image: url(icons/left_arrow_disabled.png); 163 | height: 10px; 164 | width: 10px; 165 | subcontrol-position: left; 166 | subcontrol-origin: margin; 167 | } 168 | 169 | QScrollBar::sub-line:horizontal:hover, 170 | QScrollBar::sub-line:horizontal:on 171 | { 172 | border-image: url(icons/right_arrow.png); 173 | height: 10px; 174 | width: 10px; 175 | subcontrol-position: right; 176 | subcontrol-origin: margin; 177 | } 178 | 179 | 180 | QScrollBar::add-line:horizontal:hover, 181 | QScrollBar::add-line:horizontal:on 182 | { 183 | border-image: url(icons/left_arrow.png); 184 | height: 10px; 185 | width: 10px; 186 | subcontrol-position: left; 187 | subcontrol-origin: margin; 188 | } 189 | 190 | QScrollBar::up-arrow:horizontal, 191 | QScrollBar::down-arrow:horizontal 192 | { 193 | background: none; 194 | } 195 | 196 | 197 | QScrollBar::add-page:horizontal, 198 | QScrollBar::sub-page:horizontal 199 | { 200 | background: none; 201 | } 202 | 203 | QScrollBar:vertical 204 | { 205 | background-color: QLinearGradient( 206 | x1: 1, y1: 0, x2: 0, y2: 0, stop: 0 #302F2F, stop: 1 #484846 207 | ); 208 | width: 15px; 209 | margin: 11px 0 11px 0; 210 | border: 1px solid #3A3939; 211 | border-radius: 6px; 212 | } 213 | 214 | QScrollBar::handle:vertical 215 | { 216 | background-color: QLinearGradient( 217 | x1: 1, y1: 0, x2: 0, y2: 0, stop: 0 #605F5F, stop: 1 #787876 218 | ); 219 | min-height: 5px; 220 | border-radius: 5px; 221 | } 222 | 223 | QScrollBar::sub-line:vertical 224 | { 225 | border-image: url(icons/up_arrow_disabled.png); 226 | height: 10px; 227 | width: 10px; 228 | subcontrol-position: top; 229 | subcontrol-origin: margin; 230 | } 231 | 232 | QScrollBar::add-line:vertical 233 | { 234 | border-image: url(icons/down_arrow_disabled.png); 235 | height: 10px; 236 | width: 10px; 237 | subcontrol-position: bottom; 238 | subcontrol-origin: margin; 239 | } 240 | 241 | QScrollBar::sub-line:vertical:hover, 242 | QScrollBar::sub-line:vertical:on 243 | { 244 | 245 | border-image: url(icons/up_arrow.png); 246 | height: 10px; 247 | width: 10px; 248 | subcontrol-position: top; 249 | subcontrol-origin: margin; 250 | } 251 | 252 | 253 | QScrollBar::add-line:vertical:hover, 254 | QScrollBar::add-line:vertical:on 255 | { 256 | border-image: url(icons/down_arrow.png); 257 | height: 10px; 258 | width: 10px; 259 | subcontrol-position: bottom; 260 | subcontrol-origin: margin; 261 | } 262 | 263 | QScrollBar::up-arrow:vertical, 264 | QScrollBar::down-arrow:vertical 265 | { 266 | background: none; 267 | } 268 | 269 | 270 | QScrollBar::add-page:vertical, 271 | QScrollBar::sub-page:vertical 272 | { 273 | background: none; 274 | } 275 | 276 | QTextEdit 277 | { 278 | background-color: #302F2F; 279 | color: silver; 280 | border: 1px solid #3A3939; 281 | } 282 | 283 | QPlainTextEdit 284 | { 285 | background-color: #201F1F;; 286 | color: silver; 287 | border-radius: 3px; 288 | border: 1px solid #3A3939; 289 | } 290 | 291 | QHeaderView::section 292 | { 293 | background-color: #3A3939; 294 | color: silver; 295 | padding-left: 4px; 296 | border: 1px solid #6c6c6c; 297 | } 298 | 299 | QCheckBox:disabled 300 | { 301 | color: #404040; 302 | } 303 | 304 | QSizeGrip { 305 | image: url(icons/sizegrip.png); 306 | width: 12px; 307 | height: 12px; 308 | } 309 | 310 | 311 | QMainWindow::separator 312 | { 313 | background-color: #302F2F; 314 | color: white; 315 | padding-left: 4px; 316 | spacing: 2px; 317 | border: 1px dashed #3A3939; 318 | } 319 | 320 | QMainWindow::separator:hover 321 | { 322 | 323 | background-color: QLinearGradient( 324 | x1:0, y1:0, x2:0, y2:1, stop:0 #58677b, stop:0.5 #78879b stop:1 #58677b 325 | ); 326 | color: white; 327 | padding-left: 4px; 328 | border: 1px solid #3A3939; 329 | spacing: 2px; 330 | } 331 | 332 | 333 | QMenu::separator 334 | { 335 | height: 1px; 336 | background-color: #3A3939; 337 | color: white; 338 | padding-left: 4px; 339 | margin-left: 10px; 340 | margin-right: 5px; 341 | } 342 | 343 | QRadioButton::indicator:checked, 344 | QRadioButton::indicator:unchecked 345 | { 346 | color: #b1b1b1; 347 | background-color: #302F2F; 348 | border: 1px solid silver; 349 | border-radius: 5px; 350 | } 351 | 352 | QRadioButton::indicator:checked 353 | { 354 | background-color: qradialgradient( 355 | cx: 0.5, cy: 0.5, 356 | fx: 0.5, fy: 0.5, 357 | radius: 1.0, 358 | stop: 0.25 #78879b, 359 | stop: 0.3 #302F2F 360 | ); 361 | } 362 | 363 | QCheckBox::indicator{ 364 | color: #b1b1b1; 365 | background-color: #302F2F; 366 | border: 1px solid silver; 367 | width: 9px; 368 | height: 9px; 369 | } 370 | 371 | QRadioButton::indicator 372 | { 373 | border-radius: 7px; 374 | width: 9px; 375 | height: 9px; 376 | } 377 | 378 | QRadioButton::indicator:hover, 379 | QCheckBox::indicator:hover 380 | { 381 | border: 1px solid #78879b; 382 | } 383 | 384 | QCheckBox::indicator:checked 385 | { 386 | image:url(icons/checkbox.png); 387 | } 388 | 389 | QCheckBox::indicator:disabled, 390 | QRadioButton::indicator:disabled 391 | { 392 | border: 1px solid #444; 393 | } 394 | 395 | QFrame 396 | { 397 | border-radius: 3px; 398 | } 399 | 400 | QStackedWidget 401 | { 402 | border: none; 403 | } 404 | 405 | QToolBar 406 | { 407 | border: 1px solid #393838; 408 | background: 1px solid #302F2F; 409 | font-weight: bold; 410 | } 411 | 412 | QToolBar::handle:horizontal 413 | { 414 | image: url(icons/Hmovetoolbar.png); 415 | } 416 | 417 | QToolBar::handle:vertical 418 | { 419 | image: url(icons/Vmovetoolbar.png); 420 | } 421 | 422 | QToolBar::separator:horizontal 423 | { 424 | image: url(icons/Hsepartoolbar.png); 425 | } 426 | 427 | QToolBar::separator:vertical 428 | { 429 | image: url(icons/Vsepartoolbars.png); 430 | } 431 | 432 | QPushButton 433 | { 434 | color: silver; 435 | background-color: QLinearGradient( 436 | x1: 0, y1: 1, x2: 0, y2: 0,stop: 0 #302F2F, stop: 1 #484846 437 | ); 438 | border-width: 1px; 439 | border-color: #4A4949; 440 | border-style: solid; 441 | padding-top: 5px; 442 | padding-bottom: 5px; 443 | padding-left: 5px; 444 | padding-right: 5px; 445 | border-radius: 5px; 446 | } 447 | 448 | QPushButton:disabled 449 | { 450 | background-color: QLinearGradient( 451 | x1: 0, y1: 1, x2: 0, y2: 0, stop: 0 #302F2F, stop: 1 #484846 452 | ); 453 | border-width: 1px; 454 | border-color: #3A3939; 455 | border-style: solid; 456 | padding-top: 5px; 457 | padding-bottom: 5px; 458 | padding-left: 10px; 459 | padding-right: 10px; 460 | /*border-radius: 3px;*/ 461 | color: #3A3939; 462 | } 463 | 464 | QComboBox 465 | { 466 | selection-background-color: #78879b; 467 | background-color: #201F1F; 468 | border-style: solid; 469 | border: 1px solid #3A3939; 470 | border-radius: 3px; 471 | padding: 2px; 472 | } 473 | 474 | QComboBox:hover, 475 | QPushButton:hover, 476 | QAbstractSpinBox:hover, 477 | QLineEdit:hover, 478 | QTextEdit:hover, 479 | QWidget:hover, 480 | QPlainTextEdit:hover, 481 | QAbstractView:hover, 482 | QTreeView:hover 483 | { 484 | border: 1px solid #78879b; 485 | color: silver; 486 | } 487 | 488 | QComboBox:on 489 | { 490 | background-color: #626873; 491 | padding-top: 3px; 492 | padding-left: 4px; 493 | selection-background-color: #4a4a4a; 494 | } 495 | 496 | QComboBox QAbstractItemView 497 | { 498 | background-color: #201F1F; 499 | border-radius: 3px; 500 | border: 1px solid #3A3939; 501 | selection-background-color: QLinearGradient( 502 | x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #78879b, stop: 1 #78879b 503 | ); 504 | } 505 | 506 | QComboBox::drop-down 507 | { 508 | subcontrol-origin: padding; 509 | subcontrol-position: top right; 510 | width: 15px; 511 | border-left-width: 0px; 512 | border-left-color: darkgray; 513 | border-left-style: solid; 514 | border-top-right-radius: 3px; 515 | border-bottom-right-radius: 3px; 516 | } 517 | 518 | QComboBox::down-arrow 519 | { 520 | image: url(icons/down_arrow_disabled.png); 521 | } 522 | 523 | QComboBox::down-arrow:on, 524 | QComboBox::down-arrow:hover, 525 | QComboBox::down-arrow:focus 526 | { 527 | image: url(icons/down_arrow.png); 528 | } 529 | 530 | QPushButton:pressed 531 | { 532 | background-color: QLinearGradient( 533 | x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #302F2F, stop: 1 #484846 534 | ); 535 | } 536 | 537 | QAbstractSpinBox { 538 | padding-top: 2px; 539 | padding-bottom: 2px; 540 | border: 1px solid #3A3939; 541 | background-color: #201F1F; 542 | color: silver; 543 | border-radius: 3px; 544 | } 545 | 546 | QAbstractSpinBox:up-button 547 | { 548 | background-color: transparent; 549 | subcontrol-origin: border; 550 | subcontrol-position: center right; 551 | } 552 | 553 | QAbstractSpinBox:down-button 554 | { 555 | background-color: transparent; 556 | subcontrol-origin: border; 557 | subcontrol-position: center left; 558 | } 559 | 560 | QHeaderView::down-arrow, 561 | QAbstractSpinBox::up-arrow, 562 | QAbstractSpinBox::up-arrow:disabled, 563 | QAbstractSpinBox::up-arrow:off 564 | { 565 | image: url(icons/up_arrow_disabled.png); 566 | width: 10px; 567 | height: 10px; 568 | } 569 | 570 | QHeaderView::down-arrow:hover, 571 | QAbstractSpinBox::up-arrow:hover 572 | 573 | { 574 | image: url(icons/up_arrow.png); 575 | } 576 | 577 | QHeaderView::down-arrow, 578 | QAbstractSpinBox::down-arrow, 579 | QAbstractSpinBox::down-arrow:disabled, 580 | QAbstractSpinBox::down-arrow:off 581 | { 582 | image: url(icons/down_arrow_disabled.png); 583 | width: 10px; 584 | height: 10px; 585 | } 586 | 587 | QHeaderView::up-arrow:hover, 588 | QAbstractSpinBox::down-arrow:hover 589 | { 590 | image: url(icons/down_arrow.png); 591 | } 592 | 593 | QLabel, 594 | QDateEdit::drop-down 595 | { 596 | border: 0px solid black; 597 | } 598 | 599 | QTabBar::tab 600 | { 601 | color: #b1b1b1; 602 | border: 1px solid #3A3939; 603 | background-color: #302F2F; 604 | padding-left: 5px; 605 | padding-right: 5px; 606 | padding-top: 3px; 607 | padding-bottom: 2px; 608 | margin-right: -1px; 609 | } 610 | 611 | 612 | QTabWidget::pane { 613 | border: 1px solid #3A3939; 614 | background-color: QLinearGradient( 615 | x1:0, y1:0, x2:0, y2:1, stop:1 #302F2F, stop:0 #3A3939 616 | ); 617 | } 618 | 619 | QTabBar::tab:last 620 | { 621 | margin-right: 0; 622 | border-top-right-radius: 3px; 623 | } 624 | 625 | QTabBar::tab:first:!selected 626 | { 627 | margin-left: 0px; 628 | border-top-left-radius: 3px; 629 | } 630 | 631 | QTabBar::tab:!selected 632 | { 633 | color: #b1b1b1; 634 | border-bottom-style: solid; 635 | margin-top: 3px; 636 | } 637 | 638 | QTabBar::tab:selected 639 | { 640 | border-top-left-radius: 3px; 641 | border-top-right-radius: 3px; 642 | margin-bottom: 0px; 643 | 644 | background-color: QLinearGradient( 645 | x1:0, y1:0, x2:0, y2:1, stop:1 #302F2F, stop:0 #5A5959 646 | ); 647 | } 648 | 649 | QTabBar::tab:!selected:hover 650 | { 651 | color:white; 652 | } 653 | 654 | QTabBar::tab:selected:hover 655 | { 656 | color:white; 657 | border-top-left-radius: 3px; 658 | border-top-right-radius: 3px; 659 | background-color: QLinearGradient( 660 | x1:0, y1:0, x2:0, y2:1, stop:1 #302F2F, stop:0 #5A5959 661 | ); 662 | } 663 | 664 | QDockWidget 665 | { 666 | color: silver; 667 | titlebar-close-icon: url(icons/close.png); 668 | titlebar-normal-icon: url(icons/undock.png); 669 | } 670 | 671 | QDockWidget::title 672 | { 673 | border: 1px solid #3A3939; 674 | border-bottom: #302F2F; 675 | text-align: left; 676 | spacing: 2px; 677 | background-color: QLinearGradient( 678 | x1:0, y1:0, x2:0, y2:1, stop:1 #302F2F, stop:0 #3A3939 679 | ); 680 | background-image: none; 681 | padding-left: 10px; 682 | } 683 | 684 | QDockWidget { 685 | border: 1px solid lightgray; 686 | titlebar-close-icon: url(icons/close.png); 687 | titlebar-normal-icon: url(icons/undock.png); 688 | } 689 | 690 | QDockWidget::close-button, 691 | QDockWidget::float-button { 692 | border: 1px solid transparent; 693 | border-radius: 5px; 694 | background: transparent; 695 | icon-size: 10px; 696 | } 697 | 698 | QDockWidget::close-button:hover, 699 | QDockWidget::float-button:hover { 700 | background: #3A3939; 701 | } 702 | 703 | QDockWidget::close-button:pressed, 704 | QDockWidget::float-button:pressed { 705 | padding: 1px -1px -1px 1px; 706 | } 707 | 708 | QTreeView, 709 | QListView, 710 | QTableView 711 | { 712 | border: 1px solid #3A3939; 713 | background-color: #201F1F; 714 | } 715 | 716 | QTreeView:branch:selected, 717 | QTreeView:branch:hover 718 | { 719 | background: url(icons/transparent.png); 720 | } 721 | 722 | QTreeView::branch:has-siblings:!adjoins-item 723 | { 724 | border-image: url(icons/transparent.png); 725 | } 726 | 727 | QTreeView::branch:has-siblings:adjoins-item 728 | { 729 | border-image: url(icons/transparent.png); 730 | } 731 | 732 | QTreeView::branch:!has-children:!has-siblings:adjoins-item 733 | { 734 | border-image: url(icons/transparent.png); 735 | } 736 | 737 | QTreeView::branch:has-children:!has-siblings:closed, 738 | QTreeView::branch:closed:has-children:has-siblings 739 | { 740 | image: url(icons/branch_closed.png); 741 | } 742 | 743 | QTreeView::branch:open:has-children:!has-siblings, 744 | QTreeView::branch:open:has-children:has-siblings 745 | { 746 | image: url(icons/branch_open.png); 747 | } 748 | 749 | QTreeView::branch:has-children:!has-siblings:closed:hover, 750 | QTreeView::branch:closed:has-children:has-siblings:hover 751 | { 752 | image: url(icons/branch_closed-on.png); 753 | } 754 | 755 | QTreeView::branch:open:has-children:!has-siblings:hover, 756 | QTreeView::branch:open:has-children:has-siblings:hover 757 | { 758 | image: url(icons/branch_open-on.png); 759 | } 760 | 761 | QSlider::groove:horizontal 762 | { 763 | border: 1px solid #3A3939; 764 | height: 8px; 765 | background: #201F1F; 766 | margin: 2px 0; 767 | border-radius: 4px; 768 | } 769 | 770 | QSlider::handle:horizontal 771 | { 772 | background: QLinearGradient( 773 | x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 silver, stop: 0.2 #a8a8a8, stop: 1 #727272 774 | ); 775 | border: 1px solid #3A3939; 776 | width: 14px; 777 | height: 14px; 778 | margin: -4px 0; 779 | border-radius: 7px; 780 | } 781 | 782 | QSlider::groove:vertical 783 | { 784 | border: 1px solid #3A3939; 785 | width: 8px; 786 | background: #201F1F; 787 | margin: 0 0px; 788 | border-radius: 4px; 789 | } 790 | 791 | QSlider::handle:vertical 792 | { 793 | background: QLinearGradient( 794 | x1: 0, y1: 0, x2: 0, y2: 1, stop: 0.0 silver, stop: 0.2 #a8a8a8, stop: 1 #727272 795 | ); 796 | border: 1px solid #3A3939; 797 | width: 14px; 798 | height: 14px; 799 | margin: 0 -4px; 800 | border-radius: 7px; 801 | } 802 | 803 | QToolButton 804 | { 805 | background-color: #302F2F; 806 | } 807 | 808 | QToolButton:pressed 809 | { 810 | background-color: #3A3939; 811 | } 812 | QToolButton:hover 813 | { 814 | background-color: #3A3939; 815 | } 816 | 817 | QTableView#tagView 818 | { 819 | background-color: transparent; 820 | } 821 | 822 | QLabel#inTotalLabel, QLabel#outTotalLabel, QLabel#recordCountLabel 823 | { 824 | font: bold; 825 | } --------------------------------------------------------------------------------