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
   | from typing import Tuple from Crypto.Util.number import * from gmpy2 import powmod import os
  flag = os.environb.get(b"FLAG", b"TSJ{test_flag}")
  def pow(a: int, b: int, c: int) -> int:          return int(powmod(a, b, c))
  def getPrimeOrderGroup(bits) -> Tuple[int, int, int]:     """     Generate a prime p with large prime factor q and a generator g     """     while True:         q = getPrime(bits)         for i in range(2, 257, 2):             p = q * i + 1             if isPrime(p):                 g = pow(getRandomRange(2, p), i, p)                 if g != 1:                     assert pow(g, q, p) == 1                     return p, q, g
  class RSA:     def __init__(self, bits):         self.p = getPrime(bits // 2)         self.q = getPrime(bits // 2)         self.n = self.p * self.q         self.e = 65537         self.d = pow(self.e, -1, (self.p - 1) * (self.q - 1))
      def encrypt(self, m: int) -> int:         return pow(m, self.e, self.n)
      def decrypt(self, c: int) -> int:         return pow(c, self.d, self.n)
      def __str__(self) -> str:         e = self.e         n = self.n         return f"RSA({n}, {e})"
  class ElGamal:     def __init__(self, bits):         self.p, self.q, self.g = getPrimeOrderGroup(bits)         self.x = getRandomRange(2, self.q)         self.y = pow(self.g, self.x, self.p)
      def encrypt(self, m: int) -> Tuple[int, int]:         r = getRandomRange(2, self.q)         s = pow(self.y, r, self.p)         c1 = pow(self.g, r, self.p)         c2 = (s * m) % self.p         return c1, c2
      def decrypt(self, c1: int, c2: int) -> int:         s = pow(c1, self.x, self.p)         m = (pow(s, -1, self.p) * c2) % self.p         return m
      def __str__(self) -> str:         p = self.p         g = self.g         y = self.y         return f"ElGamal({p}, {g}, {y})"
  elg = ElGamal(1024) rsa = RSA(1024)
  print("Welcome to Cipher Switching Service!") print() print("This is our public keys:") print(rsa) print(elg) print() print("And this is some information about the encrypted flag:") print(f"{len(flag) = }") flag += os.urandom(96 - len(flag))   flagenc = rsa.encrypt(bytes_to_long(flag)) print(f"{flagenc = }") print()
  for _ in range(1337):     print("1. RSA to ElGamal")     print("2. ElGamal to RSA")     print("3. Quit")     choice = int(input("> "))     if choice == 1:         c = int(input("c = "))         print(elg.encrypt(rsa.decrypt(c)))     elif choice == 2:         c1 = int(input("c1 = "))         c2 = int(input("c2 = "))         print(rsa.encrypt(elg.decrypt(c1, c2)))     elif choice == 3:         print("Bye")         break     else:         print(f"Unknown choice: {choice}") else:     print("To prevent abuse, we limit each session to have only 1337 attempts at most.")
   |