Advertisement
Guest User

Untitled

a guest
Apr 25th, 2021
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.55 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # keychanger.py - a script to create PGP keys with fingerprints begining
  5. # with a custom hex string.
  6. # Requires GnuPG 2.2.x or later and Python 3.4 or later
  7. #
  8. #
  9. # Max number of iterations to try before giving up:
  10. limit = 1209600
  11.  
  12. # If the script fails to find a match for your target, try increasing
  13. # this number. Note that this is equivalent to the maximum number of
  14. # seconds to subtract from the timestamp. The default of 1209600 is 2
  15. # weeks and should be sufficient to find any 4 character or less hex
  16. # string. One year is 31557600 seconds. Longer string lengths require a
  17. # greater number of iterations.
  18.  
  19. ########################################################################
  20. #  ! ! !      DON'T CHANGE ANYTHING FROM THIS POINT ON        !  !  !  #
  21. #  ! ! !      UNLESS YOU REALLY KNOW WHAT YOU'RE DOING.       !  !  !  #
  22. ########################################################################
  23.  
  24. # Python version check (3.4+ required for cleanup function)
  25. import sys
  26. pv = sys.version_info >= (3, 4)
  27. def cleanup(pv,public_key,secret_key):
  28.     if pv == False:
  29.         print("\nPlease manually delete these files:\n"+public_key+"\n"+secret_key)
  30.         sys.exit()
  31.     import pathlib
  32.     pathlib.Path(public_key).unlink()
  33.     pathlib.Path(secret_key).unlink()
  34.     sys.exit()
  35.  
  36. import hashlib, time, subprocess, uuid
  37.  
  38. # Algorithm strings recognized by GnuPG
  39. algos = {'rsa', 'rsa1024', 'rsa2048', 'rsa3072', 'rsa4096', 'dsa', 'dsa1024', 'dsa2048', 'ed25519', 'nistp256', 'nistp384', 'nistp521', 'brainpoolP256r1', 'brainpoolP384r1', 'brainpoolP512r1', 'secp256k1'}
  40.  
  41. # Message prompts for user input
  42. P = ["\nEnter the target hex string you want the key fingerprint to start with.\nIf you want to match a string longer than 4 characters, you'll need to increase to iteration 'limit' value in the script.\n\nEnter hex string target> ","\nChoose the algorithm for the signing key. Valid signing key algorithms are:\n  rsa  rsa1024  rsa2048  rsa3072  rsa4096\n  dsa  dsa1024  dsa2048  dsa3072\nGnuPG also allows elliptic curve key algorithms:\n  ed25519\n  nistp256  nistp384  nistp521\n  brainpoolP256r1  brainpoolP384r1  brainpoolP512r1\n  secp256k1\n(note: some elliptic curve algorithms might not be available in your version of GnuPG)\n\nEnter key algorithm> ", "\n         * * * * * NOTICE * * * * *\n    GnuPG *will* prompt you 3 times to confirm key deletion.\n    Enter y at each of these prompts.\n    If a Pinentry window pups up, the passphrase is '' (two single quotes).\n\n Press enter to continue..."]
  43.  
  44. def hexcheck(target):
  45.     digits = '0123456789abcdef'
  46.     target = target.lower()
  47.     return set(list(target)).issubset(list(digits))
  48.  
  49. # Prompt user for target hex string
  50. target = input(P[0])
  51. while hexcheck(target) == False:
  52.     print("String contains non-hex digits. Try again.")
  53.     target = input(P[0])
  54. target = target.lower()
  55.  
  56. # Prompt user for key algorithm
  57. algo = input(P[1])
  58. while algo not in algos:
  59.     print("Algorithm not in list. Try again.\n")
  60.     algo = input(P[1])
  61.  
  62. # Set user ID and generated file names to random strings.
  63. # This is to ensure none of them already exist
  64. user_id = str(uuid.uuid4())
  65. public_key = str(uuid.uuid4())
  66. secret_key = str(uuid.uuid4())
  67.  
  68. # Inform user of GnuPG behavior during script execution
  69. input(P[2])
  70.  
  71. # Commands to generate, export, then delete the generated keys
  72. cmd1 = ["gpg --quiet --batch --pinentry-mode loopback --passphrase '' --quick-gen-key "+user_id+" "+algo, "gpg --quiet -o "+public_key+" --export "+user_id,"gpg --quiet -o "+secret_key+" --export-secret-keys "+user_id, "gpg --quiet --yes --delete-secret-and-public-keys "+user_id]
  73. for c in cmd1:
  74.     subprocess.call(c, shell=True)
  75.  
  76.  
  77. # Functions to read gpg exported key data and list individual packets
  78. def header_info(x):
  79.     if x[0]&64 == 64:
  80.         tag = x[0]&63
  81.         if x[1] < 192: [hlen,plen] = [2,x[1]]
  82.         elif x[1] <= 223: [hlen,plen] = [3,((x[1] - 192) << 8) + x[2] + 192]
  83.         elif x[1] == 255: [hlen,plen] = [5,int.from_bytes(x[2:6],byteorder='big',signed=False)]
  84.     else:
  85.         tag = (x[0]&60)>>2
  86.         if x[0]&3 == 0: [hlen,plen] = [2,x[1]]
  87.         elif x[0]&3 == 1: [hlen,plen] = [3,int.from_bytes(x[1:3],byteorder='big',signed=False)]
  88.         elif x[0]&3 == 2: [hlen,plen] = [5,int.from_bytes(x[1:5],byteorder='big',signed=False)]
  89.     return [tag, hlen, plen]
  90.  
  91. def splitpackets(x):
  92.     packets = []
  93.     i = 0
  94.     while i < (len(x)-1):
  95.         h = header_info(x[i:i+5])
  96.         tag = h[0]
  97.         packet = x[i:i+h[1]+h[2]]
  98.         i += (h[1]+h[2])
  99.         packets.append([tag,packet])
  100.     return packets
  101.  
  102.  
  103. # Rewrite secret_key file without signature packet
  104. with open(secret_key, 'rb') as f:
  105.     key = bytes(f.read())
  106. key = splitpackets(key)
  107. key = b''.join([x[1] for x in key if x[0] in {5,13}])
  108. with open(secret_key, 'wb') as f:
  109.     f.write(key)
  110.  
  111. # Get public_key packet
  112. with open(public_key,'rb') as f:
  113.     key = bytes(f.read())
  114.  
  115. # Get public_key header and packet length.
  116. [hlen,plen] = header_info(key[0:5])[1:3]
  117.  
  118. # Format header for fingerprinting.
  119. h = b'\x99'+plen.to_bytes(2,byteorder='big',signed=False)
  120.  
  121. # Create initial input for SHA1
  122. key = bytearray(h+key[hlen:hlen+plen])
  123.  
  124. # Extract current timestamp
  125. timestamp = int.from_bytes(key[4:8],byteorder='big',signed=True)
  126.  
  127. # Set length of string to match
  128. L = len(target)
  129.  
  130. # Set the initial hash value and iteration counter.
  131. fingerprint = hashlib.sha1()
  132. fingerprint.update(key)
  133. current = fingerprint.hexdigest()[0:L]
  134. i = 0
  135.  
  136. # Timer to measure duration of search.
  137. start = time.time()
  138.  
  139. # Begin search for fingerprint string match
  140. while current != target and i < limit:
  141.     fingerprint = hashlib.sha1()
  142.     timestamp -= 1
  143.     i += 1
  144.     key[4:8] = timestamp.to_bytes(4,byteorder='big',signed=True)
  145.     fingerprint.update(key)
  146.     current = fingerprint.hexdigest()[0:L]
  147.  
  148. # Stop time for timer.
  149. end = time.time()
  150.  
  151. if current == target:
  152.     # Success :)
  153.     with open(secret_key,'r+b') as f:
  154.         # Go to start of timestamp data in exported secret key packet
  155.         f.seek(hlen+1)
  156.         # Overwrite timestamp with the one found in the while loop
  157.         f.write(bytes(key[4:8]))
  158.     print("\nMatch found in "+str(i)+" iterations. Total time: "+str(end-start)+" seconds.")
  159.     input("Press enter to continue")
  160.     print("\nKey fingerprint will be "+fingerprint.hexdigest().upper())
  161.     answer = input("import this key to GnuPG (y/n)?")
  162.     if answer.lower() == 'y':
  163.         pass
  164.     else:
  165.         print("Exiting")
  166.         cleanup(pv,public_key,secret_key)
  167.     # List of commands to import key and display fingerprint
  168.     cmd2 = ["gpg --quiet --allow-non-selfsigned-uid --import "+secret_key, "gpg -K "+user_id]
  169.     for c in cmd2:
  170.         subprocess.call(c, shell=True)
  171.     print("\nYOU NEED TO EDIT THIS KEY.\nEnter 'gpg --edit-key "+user_id+"' then use the following commands after the 'gpg>' prompt in the order shown:\n  gpg> adduid       ...add a new user ID by following the prompts.\n  gpg> 1            ...selects the '"+user_id+"' user id\n  gpg> deluid       ...delete the selected user ID then confirm.\n  gpg> change-usage ...toggle usage options until it shows 'Current allowed actions: Sign Certify' then enter Q.\n  gpg> passwd       ...set a password\n  gpg> addkey       ...follow prompts to add encryption subkey\n  gpg> save         ...save the changes made in editing mode")
  172.     cleanup(pv,public_key,secret_key)
  173. else:
  174.     # Failure :(
  175.     print("Failed to match "+str(target)+" in "+str(i)+" iterations. Total time: "+str(end-start)+" seconds")
  176.     cleanup(pv,public_key,secret_key)
  177.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement