Advertisement
Guest User

code generator

a guest
Jun 29th, 2019
527
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.17 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. import sys, struct, datetime
  4.  
  5. # using package pycryptodome, please see web for installation instructions and caveats
  6. from Crypto.Cipher import DES3
  7. from Crypto.Random import get_random_bytes
  8.  
  9. # constants
  10. digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
  11. base = len(digits)
  12. limit = pow(base, 10)
  13.  
  14. # variables
  15. key = bytearray(24)
  16. des3 = None
  17. generator = 0
  18.  
  19. def load_key():
  20.     # reads the key file. If not present, creates it
  21.     # this also creates a triple DES cipher with electronic codebook mode that's suitable for
  22.     # encryting and decrypting 64-bit blocks of data independently
  23.     global key, des3
  24.     try:
  25.         with open("key", "rb") as key_file:
  26.             key = key_file.read(24)
  27.     except:
  28.         key = get_random_bytes(24)
  29.         with open("key", "wb") as key_file:
  30.             key_file.write(key)
  31.     des3 = DES3.new(key, DES3.MODE_ECB)
  32.  
  33. def load_generator():
  34.     # reads the generator file, if present. Otherwise generator stays at 0
  35.     global generator
  36.     try:
  37.         with open("generator", "r") as generator_file:
  38.             line = generator_file.readline().rstrip('\r\n')
  39.             generator = int(line)
  40.     except:
  41.         pass
  42.  
  43. def save_generator():
  44.     # this also updates the history file
  45.     global generator
  46.     with open("generator", "w") as generator_file:
  47.         generator_file.write("{}\n".format(generator))
  48.     today = datetime.date.today().isoformat()
  49.     try:
  50.         with open("history", "r+") as history_file:
  51.             pos = line = None
  52.             while True:
  53.                 # complicated way of finiding position of last line
  54.                 (last_pos, last_line) = (pos, line)
  55.                 pos = history_file.tell()
  56.                 line = history_file.readline()
  57.                 if len(line) == 0:
  58.                     break
  59.             if today == last_line[:10]:
  60.                 history_file.seek(last_pos, 0)
  61.             history_file.write("{}:{}\n".format(today, generator))
  62.     except FileNotFoundError:
  63.         with open("history", "w") as history_file:
  64.             history_file.write("{}:{}\n".format(today, generator))
  65.  
  66. def encrypt(num):
  67.     # encrypt a 64-bit number, result is a 64-bit number
  68.     global des3
  69.     plain = struct.pack("Q", num)
  70.     encrypted = des3.encrypt(plain)
  71.     return struct.unpack("Q", encrypted)[0]
  72.  
  73. def decrypt(num):
  74.     # decrypt (inversion operation to encrypt)
  75.     global des3
  76.     encrypted = struct.pack("Q", num)
  77.     plain = des3.decrypt(encrypted)
  78.     return struct.unpack("Q", plain)[0]
  79.  
  80. def encode(num):
  81.     # encode 64-bit number as 10-digit base-64 string
  82.     # num must be positive and less than limit
  83.     # ordering of digits is chosen such that decoding is simple
  84.     global digits, base
  85.     result = ''
  86.     for _ in range(10):
  87.         result = digits[num % base] + result
  88.         num = num // base
  89.     return result
  90.  
  91. def decode(string):
  92.     # reverse operation, not really robust
  93.     global digits, base
  94.     result = 0
  95.     for c in string:
  96.         result = result * base + digits.find(c)
  97.     return result
  98.  
  99. def generate(count):
  100.     # generate the given number of strings
  101.     global generator
  102.     result = []
  103.     while len(result) < count:
  104.         generator += 1
  105.         encrypted = encrypt(generator)
  106.         if encrypted < limit:
  107.             result.append(encode(encrypted))
  108.     return result
  109.  
  110. def usage():
  111.     print("Usage: {} [-g count] [-c code]".format(sys.argv[0]))
  112.     sys.exit(1)
  113.  
  114. if __name__ == "__main__":
  115.     load_key()
  116.     load_generator()
  117.     if len(sys.argv) < 3 or not sys.argv[1] in ['-g', '-c']:
  118.         usage()
  119.     elif sys.argv[1] == '-g':
  120.         for code in generate(int(sys.argv[2])):
  121.             print(code)
  122.         save_generator()
  123.     elif sys.argv[1] == '-c':
  124.         value = decrypt(decode(sys.argv[2]))
  125.         if value <= generator:
  126.             for line in open("history"):
  127.                 (d, g) = line.split(':')
  128.                 if int(g) >= value:
  129.                     break
  130.             print("Valid, code was generated on {} (sequence {})".format(d, value))
  131.         else:
  132.             print("Invalid sequence {}".format(value))
  133.             sys.exit(2)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement