Anstataŭigis AES-CBC per AES-GCM
This commit is contained in:
parent
2d1fc23514
commit
628ee166fc
110
sekreto.py
110
sekreto.py
|
@ -1,10 +1,9 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import binascii, pyperclip, readline, gettext
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Protocol.KDF import PBKDF2
|
||||
from Crypto.Random import get_random_bytes
|
||||
from Crypto.Util.Padding import pad
|
||||
import hashlib, pyperclip, readline, gettext
|
||||
from Cryptodome.Cipher import AES
|
||||
from Cryptodome.Random import get_random_bytes
|
||||
|
||||
|
||||
t = gettext.translation(
|
||||
'sekreto',
|
||||
|
@ -14,49 +13,78 @@ t = gettext.translation(
|
|||
|
||||
_ = t.gettext
|
||||
|
||||
|
||||
IV_LENGTH = 12
|
||||
KEY_LENGTH = 32
|
||||
TAG_LENGTH = 16
|
||||
SALT_LENGTH = 16
|
||||
HASH_NAME = "SHA1"
|
||||
ITERATION_COUNT = 65535
|
||||
|
||||
|
||||
zwc = ["\u2060", "\u200B", "\u200D", "\u200E",
|
||||
"\u200F", "\u200C", "\u2061", "\u180E",
|
||||
"\u202A", "\u202C", "\u202D", "\u2062",
|
||||
"\u2063", "\u2064", "\u2065", "\u2066"]
|
||||
|
||||
def encrypt(plaintext, password):
|
||||
salt = get_random_bytes(16)
|
||||
key = PBKDF2(password, salt, dkLen=16, count=10000)
|
||||
iv = get_random_bytes(16)
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
ciphertext = cipher.encrypt(pad(plaintext.encode('utf-8'), 16))
|
||||
encrypted_data = salt + iv + ciphertext
|
||||
return binascii.hexlify(encrypted_data).decode('utf-8')
|
||||
|
||||
def decrypt(hex_ciphertext, password):
|
||||
ciphertext = bytes.fromhex(hex_ciphertext)
|
||||
salt = ciphertext[:16]
|
||||
iv = ciphertext[16:32]
|
||||
encrypted_data = ciphertext[32:]
|
||||
key = PBKDF2(password, salt, dkLen=16, count=10000)
|
||||
cipher = AES.new(key, AES.MODE_CBC, iv)
|
||||
decrypted_data = cipher.decrypt(encrypted_data)
|
||||
secret = decrypted_data.decode('utf-8').strip()
|
||||
return secret
|
||||
|
||||
def hid2hex(hid_string):
|
||||
mappings = {zwc[i]: hex(i)[2:].upper() for i in range(16)}
|
||||
hex_string = "".join(mappings.get(char, "") for char in hid_string)
|
||||
return hex_string
|
||||
|
||||
|
||||
def hex2hid(hex_string):
|
||||
mappings = {hex(i)[2:].upper(): zwc[i] for i in range(16)}
|
||||
hid_string = "".join(mappings.get(char.upper(), "") for char in hex_string)
|
||||
return hid_string
|
||||
|
||||
|
||||
def wrap(text):
|
||||
wrapped_text = "\uFEFF" + text + "\uFEFF"
|
||||
return wrapped_text
|
||||
|
||||
|
||||
def unwrap(text):
|
||||
unwrapped_text = text.strip('\uFEFF')
|
||||
return unwrapped_text
|
||||
|
||||
|
||||
def get_secret_key(password, salt):
|
||||
return hashlib.pbkdf2_hmac(
|
||||
HASH_NAME, password.encode(), salt, ITERATION_COUNT, KEY_LENGTH
|
||||
)
|
||||
|
||||
|
||||
def encrypt(password, plain_message):
|
||||
salt = get_random_bytes(SALT_LENGTH)
|
||||
iv = get_random_bytes(IV_LENGTH)
|
||||
|
||||
secret = get_secret_key(password, salt)
|
||||
|
||||
cipher = AES.new(secret, AES.MODE_GCM, iv)
|
||||
|
||||
encrypted_message_byte, tag = cipher.encrypt_and_digest(plain_message.encode("utf-8"))
|
||||
cipher_byte = salt + iv + encrypted_message_byte + tag
|
||||
|
||||
encoded_cipher_byte = cipher_byte.hex()
|
||||
return encoded_cipher_byte
|
||||
|
||||
|
||||
def decrypt(password, cipher_message):
|
||||
decoded_cipher_byte = bytes.fromhex(cipher_message)
|
||||
|
||||
salt = decoded_cipher_byte[:SALT_LENGTH]
|
||||
iv = decoded_cipher_byte[SALT_LENGTH : (SALT_LENGTH + IV_LENGTH)]
|
||||
encrypted_message_byte = decoded_cipher_byte[(IV_LENGTH + SALT_LENGTH) : -TAG_LENGTH]
|
||||
tag = decoded_cipher_byte[-TAG_LENGTH:]
|
||||
secret = get_secret_key(password, salt)
|
||||
cipher = AES.new(secret, AES.MODE_GCM, iv)
|
||||
|
||||
decrypted_message_byte = cipher.decrypt_and_verify(encrypted_message_byte, tag)
|
||||
return decrypted_message_byte.decode("utf-8")
|
||||
|
||||
|
||||
while True:
|
||||
|
||||
print()
|
||||
|
@ -66,33 +94,41 @@ while True:
|
|||
print()
|
||||
|
||||
choice = input("Sekreto:~$ ")
|
||||
|
||||
if choice == "1":
|
||||
secret = input(_("Sekreta mesaĝo: "))
|
||||
password = input(_("Pasvorto: "))
|
||||
pub_msg = input(_("Publika teksto: "))
|
||||
|
||||
if len(pub_msg) < 2:
|
||||
secret_msg = input(_("Sekreta mesaĝo: "))
|
||||
secret_key = input(_("Pasvorto: "))
|
||||
public_msg = input(_("Publika teksto: "))
|
||||
|
||||
if len(public_msg) < 2:
|
||||
print(_("La longo de publika teksto devas esti almenaŭ du signoj!"))
|
||||
continue
|
||||
|
||||
encrypt_msg = encrypt(secret, password)
|
||||
|
||||
encrypt_msg = encrypt(secret_key, secret_msg)
|
||||
|
||||
hiding = hex2hid(encrypt_msg)
|
||||
wrapping = wrap(hiding)
|
||||
result = pub_msg[:len(pub_msg) // 2] + wrapping + pub_msg[len(pub_msg) // 2:]
|
||||
pyperclip.copy(result)
|
||||
print(_("Mesaĝo kaŝita kaj kopiita!"))
|
||||
|
||||
result = public_msg[:len(public_msg) // 2] + wrapping + public_msg[len(public_msg) // 2:]
|
||||
|
||||
try:
|
||||
pyperclip.copy(result)
|
||||
print(_("Mesaĝo kaŝita kaj kopiita!"))
|
||||
except pyperclip.PyperclipException:
|
||||
print(_("Eraro okazis dum kopiado!"))
|
||||
|
||||
elif choice == "2":
|
||||
result = input(_("Enigu tekston kun mesaĝo: "))
|
||||
password = input(_("Pasvorto: "))
|
||||
secret_key = input(_("Pasvorto: "))
|
||||
|
||||
extraction = unwrap(result)
|
||||
revealing = hid2hex(extraction)
|
||||
|
||||
try:
|
||||
secret = decrypt(revealing, password)
|
||||
secret = decrypt(secret_key, revealing)
|
||||
print(_("Sekreta mesaĝo: "), secret)
|
||||
except:
|
||||
print(_("Vi enigis malĝustan teksto aŭ pasvorton!"))
|
||||
|
||||
elif choice == "0":
|
||||
quit()
|
||||
|
||||
|
|
Loading…
Reference in New Issue