diff --git a/ExpandApplication/AsymmetricCiphers.py b/ExpandApplication/AsymmetricCiphers.py new file mode 100644 index 0000000..e3c4783 --- /dev/null +++ b/ExpandApplication/AsymmetricCiphers.py @@ -0,0 +1,27 @@ +from fastecdsa import curve, ecdsa, keys +from fastecdsa.encoding.der import DEREncoder + +message = "a message to sign via ECDSA" # 一些訊息 + +print("使用預設曲線P256跟雜湊函數SHA2") +private_key = keys.gen_private_key(curve.P256) +public_key = keys.get_public_key(private_key, curve.P256) +print("私密金鑰: " + str(private_key)) +print("公開金鑰: " + str(public_key)) +print(type(public_key)) + +print("產生數位簽章,為兩個整數r跟s") +r, s = ecdsa.sign(message, private_key) +print(r) +print(s) + +print("編碼數位簽章,使用DEREncoder為r跟s做編碼以利傳輸") +encoded = DEREncoder.encode_signature(r, s) +b = "數位簽章: " +for i in encoded: + b += str(hex(i)) + " " +print(b) +decoded_r, decoded_s = DEREncoder.decode_signature(encoded) +valid = ecdsa.verify((decoded_r, decoded_s), message, public_key) +if r == decoded_r and s == decoded_s and valid: + print("成功") diff --git a/ExpandApplication/SymmetricCiphers.py b/ExpandApplication/SymmetricCiphers.py new file mode 100644 index 0000000..0925b65 --- /dev/null +++ b/ExpandApplication/SymmetricCiphers.py @@ -0,0 +1,150 @@ +import json +from base64 import b64encode +from base64 import b64decode +from Crypto.Cipher import AES +from Crypto.Util.Padding import pad +from Crypto.Util.Padding import unpad +from Crypto.Random import get_random_bytes + + +class stream_ciphers(): + def __init__(self, key=None, encrypt_method="aes-256-cfb", iv=None, + segment_size=8, nonce=None, initial_value=None, + counter=None): + self.__key = key + self.__encrypt_method = encrypt_method + self.__iv = iv + self.__segment_size = segment_size + self.__nonce = nonce + self.__initial_value = initial_value + self.__counter = counter + self.__items = None + + def encrypt(self, message="test"): + """aaa.""" + cipher, iv, segment_size, nonce, initial_value, counter = next( + self.encrypt_method) + message = message.encode('utf8') + if self.__items[2] == "cfb": + ct_bytes = cipher.encrypt(pad(message, AES.block_size)) + else: + ct_bytes = cipher.encrypt(message) + + ct_b64 = b64encode(ct_bytes).decode('utf-8') + + result = { + 'iv': self.__iv, + 'segment_size': self.__segment_size, + 'nonce': self.__nonce, + 'initial_value': self.__initial_value, + 'counter': self.__counter, + 'ciphertext': ct_b64, + } + + result = json.dumps(result) + yield result.encode('utf8') + + def decrypt(self, cipher_message): + # We assume that the key was securely shared beforehand + try: + cipher_message = cipher_message.encode('utf8') + b64 = json.loads(cipher_message) + + iv = b64decode(b64['iv']) + segment_size = b64decode(b64['segment_size']) + nonce = b64decode(b64['nonce']) + initial_value = b64decode(b64['initial_value']) + counter = b64decode(b64['counter']) + ct = b64decode(b64['ciphertext']) + + self.reset_encrypt_method( + key=self.__key, + encrypt_method=self.__encrypt_method, + iv=iv, + segment_size=segment_size, + nonce=nonce, + initial_value=initial_value, + counter=counter + ) + + cipher, iv, segment_size, nonce, initial_value, counter = next( + self.encrypt_method) + + if self.__items[2] == "cfb": + pt = unpad(cipher.decrypt(ct), AES.block_size) + else: + pt = cipher.decrypt(ct) + + yield pt + + except: + print("Incorrect decryption") + + @property + def encrypt_method(self): + if self.__key is None: + self.__key = get_random_bytes(16) + else: + self.__key = self.__key + + if len(self.__key) % 8 != 0: + raise ValueError('金鑰長度必須是符合8的倍數') + + self.__items = items = self.__encrypt_method.split("-") + if items[1] == len(self.__key) * 16: + raise ValueError('不符合金鑰設定的位元長度') + + if items[0] == "aes": + if items[2] == "ecb": + cipher = AES.new(self.__key, AES.MODE_ECB) + + elif items[2] == "cbc": + cipher = AES.new(self.__key, AES.MODE_CBC, iv=self.__iv) + self.__iv = b64encode(cipher.iv).decode('utf-8') + + elif items[2] == "ctr": + cipher = AES.new(self.__key, AES.MODE_CTR, nonce=self.__nonce, + initial_value=self.__initial_value, + counter=self.__counter) + self.__nonce = b64encode(cipher.nonce).decode('utf-8') + + elif items[2] == "cfb": + cipher = AES.new(self.__key, AES.MODE_CFB, iv=self.__iv, + segment_size=self.__segment_size) + self.__iv = b64encode(cipher.iv).decode('utf-8') + + elif items[2] == "ofb": + cipher = AES.new(self.__key, AES.MODE_OFB, iv=self.__iv) + self.__iv = b64encode(cipher.iv).decode('utf-8') + + elif items[2] == "openpgp": + cipher = AES.new(self.__key, AES.MODE_OPENPGP) + + else: + raise ValueError('沒有此加密演算法') + + else: + raise ValueError('沒有此加密演算法') + + iv = self.__iv + segment_size = self.__segment_size + nonce = self.__nonce + initial_value = self.__initial_value + counter = self.__counter + yield cipher, iv, segment_size, nonce, initial_value, counter + + def reset_encrypt_method(self, key=None, encrypt_method="aes-256-cfb", + iv=None, segment_size=None, nonce=None, + initial_value=None, counter=None): + self.__key = key + self.__encrypt_method = encrypt_method + self.__iv = iv + self.__segment_size = segment_size + self.__nonce = nonce + self.__initial_value = initial_value + self.__counter = counter + + +sc = stream_ciphers() +print(next(sc.encrypt())) +print(next(sc.encrypt())) diff --git a/README.md b/README.md index 2e908d5..ccb3593 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,41 @@ -# Talk -利用Python撰寫的點對點或中央談話程式。 +Talk +=== +利用Python撰寫的點對點或中央談話程式,可以選擇使用不同的加密演算法保護傳輸的資料。 Peer-to-peer or central talk program written in Python. + +使用Python3.6,並且使用以下套件: +- fastecdsa +- pycryptodome +- socket + +支援的加密演算法: +- 「對稱性加密演算法」(Symmetric ciphers) + - 「串流加密法」(Stream ciphers) + - ciphers + - ChaCha20 + - XChaCha20 + - Salsa20 + - authentication (MAC) + - Poly1305 + - 「區塊加密法」(Block ciphers) + - Ciphers + - AES + - Classic modes of operation + - ECB mode + - CBC mode + - CTR mode + - CFB mode + - OFB mode + - OpenPGP mode + - Modern modes of operation + - CCM mode + - EAX mode + - GCM mode + - SIV mode + - OCB mode + +- 「非對稱性加密演算法」(Asymmetric ciphers): + - RSA + - ECC + +- Hybrid ciphers:結合兩者