Guest User

CrownOTP.py

a guest
Dec 22nd, 2021
261
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.92 KB | None | 0 0
  1. import random
  2. import time
  3. import json
  4.  
  5. from decimal import Decimal, getcontext
  6.  
  7.  
  8. #########################################################
  9. #                        Alice                          #
  10. #########################################################
  11.  
  12. def crown_npsn_rng() -> int:
  13.     """This mocks the Crown RNG that generates non-perfect square numbers."""
  14.     return random.choice([2,3,5,6,7,8,10,11,12,13,14,15,17,18,19,20,21,22,23,24,26])
  15.  
  16.  
  17. def int_to_bytes(x: int) -> bytes:
  18.     return x.to_bytes((x.bit_length() + 7) // 8, 'big')
  19.  
  20.  
  21. def generate_otp(seed: int, length: int, offset: int) -> bytes:
  22.     getcontext().prec = 5 * (length + offset)
  23.     square_root       = Decimal(seed).sqrt()
  24.  
  25.     decimal_expansion = str(square_root).split('.')[1]
  26.     keystream_integer = int(decimal_expansion[offset:])
  27.     one_time_pad      = int_to_bytes(keystream_integer)[:length]
  28.     return one_time_pad
  29.  
  30.  
  31. def xor_bytestrings(var: bytes, key: bytes) -> bytes:
  32.     assert len(var) == len(key)
  33.     return bytes(a ^ b for a, b in zip(var, key))
  34.  
  35.  
  36. #########################################################
  37. #                   Eve (Eavesdropper)                  #
  38. #########################################################
  39.  
  40. def crack_crown_otp(ciphertext: bytes) -> str:
  41.     """Crack the OTP ciphertext.
  42.  
  43.    Crown Sterling's claim is their OTP has perfect secrecy.
  44.    Therefore brute force attack like the one below should
  45.    not be possible.
  46.    """
  47.  
  48.     for seed in range(1, 30):
  49.         for offset in range(1, 30):
  50.  
  51.             try:
  52.                 pad_candidate = generate_otp(seed=seed, length=len(ciphertext), offset=offset)
  53.             except IndexError:
  54.                 continue
  55.  
  56.             try:
  57.                 decryption_candidate = xor_bytestrings(ciphertext, pad_candidate).decode()
  58.                 data_structure       = json.loads(decryption_candidate)
  59.                 return 'Successful decryption: ' + data_structure['message']
  60.             except UnicodeDecodeError:
  61.                 continue
  62.  
  63.     return 'Error: Decryption failed'
  64.  
  65.  
  66. #########################################################
  67. #                         Main                          #
  68. #########################################################
  69.  
  70. def main():
  71.  
  72.     message = 'Attack at dusk'
  73.  
  74.     packet_data_structure = {'message': message, 'send_unix_timestamp': time.time()}
  75.     plaintext_packet      = json.dumps(packet_data_structure, default=(lambda o: {k: packet_data_structure[k] for k in packet_data_structure}), indent=0).encode()
  76.  
  77.     # Alice
  78.     one_time_pad = generate_otp(seed=crown_npsn_rng(),
  79.                                 length=len(plaintext_packet),
  80.                                 offset=random.randint(1, 10))
  81.     ciphertext   = xor_bytestrings(plaintext_packet, one_time_pad)
  82.  
  83.     # Eve
  84.     decryption = crack_crown_otp(ciphertext=ciphertext)
  85.     print(decryption)
  86.  
  87.  
  88. if __name__ == '__main__':
  89.     main()
  90.  
Advertisement
Add Comment
Please, Sign In to add comment