from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import base64
import os
def encrypt_RC4(message, key):
"""Encrypt plaintext message using RC4."""
algorithm = algorithms.ARC4(key)
cipher = Cipher(algorithm, mode=None)
encryptor = cipher.encryptor()
return encryptor.update(message)
def decrypt_RC4(ciphertext, key):
"""Decrypt ciphered text using RC4."""
algorithm = algorithms.ARC4(key)
cipher = Cipher(algorithm, mode=None)
decryptor = cipher.decryptor()
return decryptor.update(ciphertext)
# Call RC4 with an plain text example:
key = base64.urlsafe_b64encode(os.urandom(16))
message = b"This is team Alvin and Juanes, ftw!"
encrypted_message = encrypt_RC4(message, key)
print("Encrypted Message: ", encrypted_message)
decrypted_message = decrypt_RC4(encrypted_message, key)
print("Decrypted Message: ", decrypted_message)
if message == decrypted_message:
print("Original message was properly decrypted!")
else:
print("Original message was not properly decrypted!")
Encrypted Message: b'\x96\xd02\xf8i\x92S\xc9\x18\xa7\x80\x85\x98l\x94@N\xb3\xecA\x18d\xca*\xd5\xa9\x8b\x01\xc4\xb5\xd1\x17\x05a\x9a'
Decrypted Message: b'This is team Alvin and Juanes, ftw!'
Original message was properly decrypted!
key_length = 16
message = bytes(50) # All-zeros byte input string
second_bytes = []
for i in range(2 ** key_length):
key = base64.urlsafe_b64encode(os.urandom(16))
ct = encrypt_RC4(message, key)
second_bytes.append(ct[1])
import seaborn as sns
# Plot RC4 Histogram with kde
sns.reset_defaults()
ax = sns.histplot(second_bytes, bins=2 ** 8, kde=True, stat="density", color="#0504aa")
ax.set_xlim([0, 2 ** 8])
ax.set_xlabel("Byte Value")
ax.set_ylabel("Frequency Density")
ax.set_title("RC4 Frequency analysis of second byte")
ax.grid(axis="y", alpha=0.75)
# Print which byte is the one more frequent
nums = second_bytes
nums.sort()
counts = dict()
max_value, max_count = None, 0
for i in nums:
counts[i] = counts.get(i, 0) + 1
if counts[i] > max_count:
max_value = i
max_count = counts[i]
decoded_max_value = chr(max_value).encode("unicode_escape").decode("utf-8")
print(
f"The most frequent value in the second byte is '{decoded_max_value}' "
f"with a probability of {round(max_count/2**key_length * 100, 4)}%"
)
The most frequent value in the second byte is '\x00' with a probability of 0.705%
# RC4 Distribution of frequencies
norm_counts_rc4 = [count/2**key_length for count in counts.values()]
pd.DataFrame(norm_counts_rc4).describe()
from AESCtr import AESCtr
key_length = 16
message = bytes(50) # All-zeros byte input string
second_bytes = []
for i in range(2 ** key_length):
key = base64.urlsafe_b64encode(os.urandom(16))
aes = AESCtr(key)
ct = aes.encrypt(message)
second_bytes.append(ct[1])
import seaborn as sns
# Plot AES Histogram with kde
sns.reset_defaults()
ax = sns.histplot(second_bytes, bins=2 ** 8, kde=True, stat="density", color="#0504aa")
ax.set_xlim([0, 2 ** 8])
ax.set_xlabel("Byte Value")
ax.set_ylabel("Frequency Density")
ax.set_title("AES Frequency analysis of second byte")
ax.grid(axis="y", alpha=0.75)
# Print which byte is the one more frequent
nums = second_bytes
nums.sort()
counts = dict()
max_value, max_count = None, 0
for i in nums:
counts[i] = counts.get(i, 0) + 1
if counts[i] > max_count:
max_value = i
max_count = counts[i]
decoded_max_value = chr(max_value).encode("unicode_escape").decode("utf-8")
print(
f"The most frequent value in the second byte is '{decoded_max_value}' "
f"with a probability of {round(max_count/2**key_length * 100, 4)}%"
)
The most frequent value in the second byte is '\x96' with a probability of 0.4669%
# AES Distribution of frequencies
norm_counts_aes = [count/2**key_length for count in counts.values()]
pd.DataFrame(norm_counts_aes).describe()
freqs = pd.DataFrame({'RC4': norm_counts_rc4, 'AES': norm_counts_aes})
freqs.describe()
ax = sns.boxplot(data=freqs)
ax.set_xlabel("Cipher")
ax.set_ylabel("Frequency Density")
ax.set_title("Distribution of frequencies in second-byte output")
ax.grid(axis="y", alpha=0.75)