aboutsummaryrefslogtreecommitdiffstats
path: root/forge_key.py
diff options
context:
space:
mode:
Diffstat (limited to 'forge_key.py')
-rwxr-xr-xforge_key.py88
1 files changed, 0 insertions, 88 deletions
diff --git a/forge_key.py b/forge_key.py
deleted file mode 100755
index 850f2b1..0000000
--- a/forge_key.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python3
-import argparse
-import os
-import shutil
-import base64
-import random
-
-import gmpy2
-from Crypto.PublicKey import RSA
-from stem.control import Controller
-
-
-def main():
- arg_parser = argparse.ArgumentParser()
- args = arg_parser.parse_args()
-
- # Generate RSA key pair
- data_len = 100
- data = random.getrandbits(data_len * 8).to_bytes(data_len, 'little')
- print('Data:', base64.b64encode(data).decode())
- key = forge_rsa_key(data)
-
- # Public hidden service
- with Controller.from_port() as controller:
- controller.authenticate()
- response = controller.create_ephemeral_hidden_service(
- {80: 5000},
- await_publication=True,
- key_type='RSA1024',
- key_content=key,
- )
- print(response.service_id)
-
-def crypto_prime(num):
- i = 2
- for x in range(64): # 2^(-128) false
- if not gmpy2.is_strong_prp(num, i): return False
- i = gmpy2.next_prime(i)
- return True
-
-def next_prime(num):
- while True:
- num = gmpy2.next_prime(num)
- # ensure a sufficient is-prime confidence
- if crypto_prime(num): return int(num)
-
-DATA_LEN = 800
-NONCE_LEN = 200
-KEY_LEN = 1024
-
-def forge_rsa_key(data: bytes):
- # Generate RSA key with p = 11.
- # By Cramer's conjecture (which is likely to be true),
- # the maximum prime gap for a 1024-bit number should be around 500000.
- # We choose a 800-bit data size and a 200-bit nonce, which allows a maximum
- # gap of 2^(1023-1000)/11 ~ 760000 and a collision probability of ~2^(-100).
- assert(len(data) == DATA_LEN // 8)
- # let the highest bit be 1
- while True:
- n_expect = 1 << (KEY_LEN - 1) | \
- int.from_bytes(data, 'little') << (KEY_LEN - 1 - DATA_LEN) | \
- random.getrandbits(NONCE_LEN) << (KEY_LEN - 1 - DATA_LEN - NONCE_LEN)
- while True:
- p = 11
- q = next_prime((n_expect - 1) // p + 1)
- n = p * q
- # final (paranoid) correctness check,
- # should be true given the conjecture is true
- if (n >> (KEY_LEN - 1 - DATA_LEN)) == \
- (n_expect >> (KEY_LEN - 1 - DATA_LEN)): break
- # Compute RSA components
- e = 65537
- d = int(gmpy2.invert(e, (p - 1) * (q - 1)))
- # Library reference
- # https://pycryptodome.readthedocs.io/en/latest/src/public_key/rsa.html
- # if get an invalid key (prob ~1/11), retry with another nonce
- try: key = RSA.construct((n, e, d), consistency_check=True)
- except ValueError: continue
- break
-
- # Tor accepts DER-encoded, then base64 encoded RSA key
- # https://github.com/torproject/tor/blob/a462ca7cce3699f488b5e2f2921738c944cb29c7/src/feature/control/control_cmd.c#L1968
- der = key.export_key('DER', pkcs=1)
- ret = str(base64.b64encode(der), 'ASCII')
- return ret
-
-if __name__ == '__main__':
- main()