-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions.py
156 lines (129 loc) · 4.66 KB
/
functions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# import pastebin #not working in python3
import hashlib
from hashlib import sha256
import zlib
import Crypto
from Crypto.Hash import SHA256
from AESCipher import aes_encrypt, aes_decrypt
charset_homograph = ['Ѕ', 'І', 'Е', 'Ј', 'А', 'В', 'М', 'К', 'Н', 'О', 'Р', 'С', 'Т', 'Х', 'а', 'е', 'о', 'р', 'с',
'у', 'ѕ', 'і',
'ј', '‚'] # Russian Cyrillic Alphabet. Seems equal to the below
charset_occidental = ['S', 'I', 'E', 'J', 'A', 'B', 'M', 'K', 'H', 'O', 'P', 'C', 'T', 'X', 'a', 'e', 'o', 'p',
'c', 'y', 's',
'i', 'j', ','] # Occidental Alphabet
END_CHARACTER = ""
# TODO Cambiar logica
def hide(message, secret, key):
"""
Hide the secret (encrypted) with the key into the message.
:param message: Message where we are hiding the information
:param secret: Secret we are hiding in the message
:param key: Key used to encrypt the secret after compressing the bits
:return: The message with the secret.
"""
# Get the bytes of the secret
secret_bytes = secret.encode('utf-8')
# Compress the secret
compressed_bytes = zlib.compress(secret_bytes, 9)
# Encrypt the bytes
encrypted_bytes = aes_encrypt(compressed_bytes, password_hasher(key))
# Transform the encrypted secret into bits
encrypted_bits = bytes_to_bitstring(encrypted_bytes)
# For checking the max length
len_encrypted_bits = len(encrypted_bits)
max_length = check_max_secret_length(message)
if max_length < len_encrypted_bits:
print(f'The program can only hide {str(max_length)} bits.')
exit(-1)
binary_string_counter = 0
finished = False
result = []
for c in message:
if binary_string_counter < len_encrypted_bits:
# We should encode the message
if c in charset_occidental:
if encrypted_bits[binary_string_counter] == "0": # Use Occidental
result.append(c)
else: # Use cyrillic
result.append(charset_homograph[charset_occidental.index(c)])
binary_string_counter += 1
elif c in charset_homograph:
if encrypted_bits[binary_string_counter] == "1":
result.append(c)
else:
result.append(charset_occidental[charset_homograph.index(c)])
binary_string_counter += 1
else:
result.append(c)
else:
if not finished:
result.append(END_CHARACTER)
finished = True
result.append(c)
final_result = "".join(result)
return final_result
# TODO cambiar logica
def extract(message, key):
"""
Extract the secret of the message
:param message: Message with the hidden secret
:param key: Key used to encrypt the message
:return:
"""
binary_secret = []
for c in message:
if c in charset_occidental:
binary_secret.append("0")
elif c in charset_homograph:
binary_secret.append("1")
elif c == END_CHARACTER:
break
# Bits to bytes
bit_string = "".join(binary_secret)
# Transform the bit sequence to bytes
bytes_secret = bitstring_to_bytes(bit_string)
# Decrypt the binary
decrypted = aes_decrypt(bytes_secret, password_hasher(key))
# Uncompress
uncompress = zlib.decompress(decrypted)
final_result = uncompress.decode('utf-8')
return final_result
def bitstring_to_bytes(s):
"""
Function that converts a string composed by '1's and '0' to bytes
:param s:
:return:
"""
return bytearray([int(s[i:i + 8], 2) for i in range(0, len(s), 8)])
def bytes_to_bitstring(bytes):
"""
Functions that converts a bytearray to an string composed of '1's and '0's.
:param bytes:
:return:
"""
return ''.join('{:08b}'.format(x) for x in bytearray(bytes))
def check_max_secret_length(message):
"""
It calculates the number of bits that we can hide
:param message:
:return:
"""
max_len = 0
for i in message:
if i in charset_occidental or i in charset_homograph:
max_len += 1
return max_len
def check_secret_length(secret):
# Get the bytes of the secret
secret_bytes = secret.encode('utf-8')
# Compress the secret
compressed_bytes = zlib.compress(secret_bytes, 9)
return len(bytes_to_bitstring(compressed_bytes))
def password_hasher(password):
"""
Just hashes the password
:param password:
:return: 32 byte hash
:rtype: bytes
"""
return hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), b'salt', 100000)