# Public Key Generator
# https://www.nostarch.com/crackingcodes/ (BSD Licensed)

import random, sys, os
from books.CrackingCodesWithPython.Chapter13.cryptomath import gcd, findModInverse
from books.CrackingCodesWithPython.Chapter22.primeNum import generateLargePrime


def main():
    # Create a public/private keypair with 1024-bit keys:
    print('Making key files...')
    makeKeyFiles('al_sweigart', 1024)
    print('Key files made.')


def generateKey(keySize):
    # Creates public/private keys keySize bits in size.
    p = 0
    q = 0
    # Step 1: Create two prime numbers, p and q. Calculate n = p * q:
    print('Generating p prime...')
    while p == q:
        p = generateLargePrime(keySize)
        q = generateLargePrime(keySize)
    n = p * q

    # Step 2: Create a number e that is relatively prime to (p-1)*(q-1):
    print('Generating e that is relatively prime to (p-1)*(q-1)...')
    while True:
        # Keep trying random numbers for e until one is valid:
        e = random.randrange(2 ** (keySize - 1), 2 ** keySize)
        if gcd(e, (p - 1) * (q - 1)) == 1:
            break

    # Step 3: Calculate d, the mod inverse of e:
    print('Calculating d that is mod inverse of e...')
    d = findModInverse(e, (p - 1) * (q - 1))

    publicKey = (n, e)
    privateKey = (n, d)

    print('Public key:', publicKey)
    print('Private key:', privateKey)

    return publicKey, privateKey


def makeKeyFiles(name, keySize):
    # Creates two files 'x_pubkey.txt' and 'x_privkey.txt' (where x
    # is the value in name) with the n,e and d,e integers written in
    # them, delimited by a comma.

    # Our safety check will prevent us from overwriting our old key files:
    if os.path.exists('%s_pubkey.txt' % name) or os.path.exists('%s_privkey.txt' % name):
        sys.exit('WARNING: The file %s_pubkey.txt or %s_privkey.txt already exists!'
                 'Use a different name or delete these files and rerun this program.' % (name, name))

    publicKey, privateKey = generateKey(keySize)

    print()
    print('The public key is a %s and a %s digit number.' % (len(str(publicKey[0])), len(str(publicKey[1]))))
    print('Writing public key to file %s_pubkey.txt...' % name)
    fo = open('%s_pubkey.txt' % name, 'w')
    fo.write('%s,%s,%s' % (keySize, publicKey[0], publicKey[1]))
    fo.close()

    print()
    print('The private key is a %s and a %s digit number.' % (len(str(privateKey[0])), len(str(privateKey[1]))))
    print('Writing private key to file %s_privkey.txt...' % name)
    fo = open('%s_privkey.txt' % name, 'w')
    fo.write('%s,%s,%s' % (keySize, privateKey[0], privateKey[1]))
    fo.close()


# If makePublicPrivateKeys.py is run (instead of imported as a module),
# call the main() function:
if __name__ == '__main__':
    main()

@@ -1,10 +1,11 @@
-# 
+%22%22%22
 Public K
@@ -21,64 +21,397 @@
 tor%0A
-# https://www.nostarch.com/crackingcodes/ (BSD Licensed)
+%0AImplements series of functions capable of creating a %60textbook RSA%60_ public/private keypair and saves them to text%0Afiles.%0A%0ANote:%0A    * https://www.nostarch.com/crackingcodes/ (BSD Licensed)%0A    * 'Textbook/Plain' RSA keys are not secure and should not be used to encrypt sensitive data.%0A%0A.. _textbook RSA:%0A    https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Attacks_against_plain_RSA%0A%22%22%22
 %0A%0Aim
@@ -795,66 +795,293 @@
 Size
-):%0A    # Creates public/private keys keySize bits in size.
+: int) -%3E tuple:%0A    %22%22%22Generate public/private keypair%0A%0A    Creates public/private keys keySize bits in size.%0A%0A    Args:%0A         keySize: Bit size to make public/private keys.%0A%0A    Returns:%0A        Tuples containing the public and private keypair split into their two halves.%0A    %22%22%22
 %0A   
@@ -1990,16 +1990,21 @@
 les(name
+: str
 , keySiz
@@ -2004,24 +2004,58 @@
  keySize
-):%0A    #
+: int) -%3E None:%0A    %22%22%22Make key files%0A%0A   
  Creates
@@ -2112,18 +2112,16 @@
 re x%0A   
- #
  is the 
@@ -2179,18 +2179,16 @@
 n in%0A   
- #
  them, d
@@ -2209,16 +2209,331 @@
 comma.%0A%0A
+    Args:%0A         name: Name to append to public/private key files.%0A         keySize: Bit size to make public/private keys.%0A%0A    Returns:%0A        None. Key files are created in current working directory.%0A%0A    Note:%0A        * Checks if key files with given name already exist and exits with warning if so.%0A%0A    %22%22%22%0A
     # Ou

Update Chapter23/makePublicPrivateKeys.py added docstrings