# Generate public/private keys, encrypt, decrypt, sign, verify

My program generates public private keys, encrypts, decrypts, signs and verifies, while using AES for the bulk of the data for speed, and encrypts the random key with RSA. Many operations were chosen for speed. This works out of the box on 3.6+ . Windows idle env disallows it from working there, but Linux and mac is ideal. I do call gzip which I know I can replace with a module. I almost want to do my own Huffman coding for it but I don't know where to draw the line.

The RSA and DSA portions are written from number theory and don't use the modules, that was the point. I don't know how to put this in the title without it being edited it out. The RSA and DSA portions are manual implementations of the mathematics. The prime finding algorithms are implementations of two theorems, applied in an order to achieve maximum sieving speed.I did away with my lucas test as doing a large number of Miller Rabin tests produces a probability of 1 of being prime.

I'm using this as an educational tool to force the unwilling learners to kinetically understand public and private key cryptography when passed on a USB etc. in a classroom setting. To see the clicks in peoples eyes when they understand signing or the like, that's why I'm sharing this code. I know there's much better ways to handle the data concatenation, but am happy that I'm processing the data at a binary level.

I love the prime number theorem and so should you.

#!/usr/bin/env python3
import os
import sys
import math
import re
import hashlib
import random
import base64
import string
import getpass
import multiprocessing as mp
from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Protocol.KDF import PBKDF2

#Primality testing, extended greatest common divisor and least common multiple
def isprime(n):
if not n & 1:  #check if first bit is 1
return False
for i in (3,5,7,11):
if divmod(n, i)[1] == 0:
return False
#Fermat
if (pow(2, n-1, n)) != 1:
return False
#MilRab, x**2 = 1 mod P - ERH
s = 0
d = n-1
while not d & 1:
d>>=1 #shifts binary rep of number right one place, same as dividing by 2^d
s+=1
assert(2**s * d == n-1) #Process to find s and d
def trial_composite(a):
if pow(a, d, n) == 1:
return False
for i in range(s):
if pow(a, 2**i * d, n) == n-1:
return False
return True
for i in range(100):#Number of Rabin Witness
a = random.randrange(2, n-1)
if trial_composite(a):
return False
return True

def get1prime(keysize):
while True:
p = random.randrange(1<<(keysize), 1<<(keysize+2))
if isprime(p):
return p

def modInverse(a, m) : #Euclid's Extended Algorithm
m0 = m
y = 0
x = 1
while (a > 1) :
q = a // m
t = m
m = divmod(a,m)[1]
a = t
t = y
y = x - q * y
x = t
if (x < 0) :
x = x + m0
return x

def lcm(x, y):
lcm = (x*y)//math.gcd(x,y)
return lcm

##AES256CHUNK
salt = b"We will know, we must know"
kdf = PBKDF2(password, salt, 64, 1000)
key = kdf[:32]
return key

cipher = AES.new(private_key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))

enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(private_key, AES.MODE_CBC, iv)

BLOCK_SIZE = 128 #Block is 128 no matter what,this is multiple of 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

#RSA
#Unique and Arbitrary Pub E, a prime.
e = 66047 # because I can
#e = 65537

def encryptit(e, n, thestring):#for sigining pass d as e
rbinlist = ['{0:08b}'.format(x) for x in thestring]
catstring = ''
catstring += rbinlist[0].lstrip('0')
del rbinlist[0]
for i in rbinlist:
catstring += str(i)
puttynumber = int(catstring,2)
cypherstring = str(pow(puttynumber, e, n))
return cypherstring

def decryptit(d, n, cynum):#for signing pass e as d
decryptmsg = ''
n = int(n)
d = int(d)
puttynum = pow(int(cynum), d, n)
puttynum = '{0:08b}'.format(puttynum)
while True:
if len(puttynum)%8 == 0:
break
puttynum = '0{0}'.format(puttynum)
locs = re.findall('[01]{8}', puttynum)
for x in locs:
letter = chr(int(x,2))
decryptmsg += letter
return decryptmsg

#Begin User Flow
choice = input("""

Welcome to Dan's Cryptography Concept Program.
Generate/Encrypt/Decrypt/Sign
RSA++/DSA++/AES/OTP/Double DH key exch w SHA
Choose:
A: Generate New Public/Private Key Pair
B: Encrypt a File
C: Decrypt a File
=> """)

if choice == 'A' or choice == 'a':
try:
keysize = (int(input("Enter a keysize:  "))>>1)
except ValueError as a:
print('Enter a number\n\n')
sys.exit()
pubkeyname = input('Input desired public key name: ')
pkey = input('Input desired private key name: ')
print('Generating Keys...')
primes = []
plist = []
for i in range(mp.cpu_count()):
plist.append(keysize)
workpool = mp.Pool(processes=mp.cpu_count())
reslist = workpool.imap_unordered(get1prime, plist)
workpool.close()
for res in reslist:
if res:
primes.append(res)
workpool.terminate()
break
workpool.join()
#
workpool1 = mp.Pool(processes=mp.cpu_count())
reslist = workpool1.imap_unordered(get1prime, plist)
workpool1.close()
for res in reslist:
if res:
primes.append(res)
workpool1.terminate()
break
workpool1.join()
if primes[0] != primes[1]:
p, q = primes[0], primes[1]
else:
print('Supremely Unlucky Try Again')
exit()
n = p*q
cm = lcm(p-1, q-1)
print('Computing Private key ...')
d = modInverse(e, cm)
print('Private Key Size: {} bits'.format(keysize*2))
print('Functional Length of: {}'.format(len(bin((d)))))
keystring = encryptaes(str(d).encode('ascii', errors='ignore').decode('utf-8'),pwkey)
b64key = bytes.decode(base64.encodestring(bytes(str(hex(n)).encode())))
with open(pkey, 'w') as f1:
f1.write(str(n)+'\n')
f1.write(bytes.decode(keystring))
with open(pubkeyname, 'w') as f2:
f2.write(b64key)
print('Complete - {} and {} generated'.format(pubkeyname,pkey))
print('e exponent: {}'.format(str(e)))
print("""
-----BEGIN PUBLIC KEY-----
{}-----END PUBLIC KEY-----
""".format(b64key))
b64privkey = b64key = bytes.decode(base64.encodestring(bytes(str(hex(d)).encode())))
print("""
-----BEGIN PRIVATE KEY-----
{}-----END PRIVATE KEY-----
""".format(b64privkey))

if choice == 'B' or choice == 'b':
lineoutholder = []
pubkeyname = input('Enter PUBLIC key to encrypt with(recepient): ')
privkey = input('Enter your private KEY you wish to sign with(yours): ')
try:
with open(pubkeyname, 'r') as f1:
except:
exit()
uhaeskey = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(32)])
n = int(bytes.decode(base64.decodestring(bytes(pubkey.encode()))), 16)
workfile = input('Enter the file to ENCRYPT: ')
outfile = input('Enter filename to WRITE out: ')
sha256_hash = hashlib.sha256()
try:
with open(workfile, 'rb') as f2:
with open(workfile, 'rb') as f2:#open again to clear memory
sha256_hash.update(byte_block)
HASH = sha256_hash.hexdigest()
with open(privkey) as f3:
except Exception as x:
print(x)
exit()
d = int(bytes.decode(decryptaes(priv[1], pwkey)))
HASH = [ord(i) for i in HASH]
numhash = ''
for i in HASH:
numhash +=str(i)
signature = pow(int(numhash), d, int(priv[0]))
aeskey = get_private_key(uhaeskey)
plaintext = base64.encodestring(wholefile)
cyphertext = bytes.decode(encryptaes(plaintext.decode('ascii'), aeskey))
shippedpw = encryptit(e, n, uhaeskey.encode())
concat = str(str(signature)+'CUTcutCUTcutCUT'+shippedpw+'CUTcutCUTcutCUT'+cyphertext)
with open(outfile, 'w') as f3:
f3.write(concat)
os.system('gzip -9 {0};mv {0}.gz {0}'.format(outfile))
print('Wrote to {} ...'.format(outfile))

if choice == 'C' or choice == 'c':
dspubkeyname = input('Enter the PUBLIC key to verify the signature with(sender): ')
try:
with open(dspubkeyname, 'r') as f1:
except:
exit()
nsig = int(bytes.decode(base64.decodestring(bytes(pubkey.encode()))), 16)
privkey = input('YOUR private KEY filename to decrypt the data: ')
workfile = input('Enter the file to DECRYPT: ')
outfile = input('Enter the filename to WRITE out: ')
print('DECRYPTING')
os.system('mv {0} {0}.gz;gzip -d {0}.gz'.format(workfile))
sha256_hash = hashlib.sha256()
try:
with open(workfile) as f1:
signature, codedkey, cyphertext =lineholder[0], lineholder[1], lineholder[2]
except:
exit()
try:
with open(privkey) as f2:
except:
n = priv[0]
d = int(bytes.decode(decryptaes(priv[1], pwkey)))
sigdec = pow(int(signature), e, nsig)#Sig Verification step1
aeskey = decryptit(d, n, codedkey)
aeskey = get_private_key(aeskey)
decstr = bytes.decode(decryptaes(cyphertext, aeskey))
cleartext = base64.decodestring(bytes(decstr, 'ascii'))
with open(outfile, 'wb') as f1:
f1.write(cleartext)
with open(outfile, 'rb') as f2:
sha256_hash.update(byte_block)
HASH = sha256_hash.hexdigest()
HASH = [ord(i) for i in HASH]
numhash = ''
for i in HASH:
numhash +=str(i)
if int(numhash) == int(sigdec):
print('Signature Verified')
else:
print('Wrote out to {} '.format(outfile))

• If you have at least one space before the #, the syntax highlighter does not get confused by ' in the comments. – Graipher Feb 27 at 9:17
• To be clear: as this is a teaching aid rather than a practical tool, you're not interested in resistance to information leakage through observation of timing and power consumption, right? – Toby Speight Feb 27 at 9:19
• Well, I'd be interested. The tools is used so students can pass and sign data with public and private keys, just using the program. The internals are my research. I'm extremely curious to know how observing the timing and power could be used to glean meaningful information from either the key generation or encryption. – TheHoyt Feb 27 at 16:09
• and, definitely not worried about power consumption... :) Id go to C if I wanted to be more efficient. I do all math operations as fast and efficiently as can be done in a python implementation, I think. Half why I posted. – TheHoyt Feb 27 at 16:27
• Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. – Mast Feb 28 at 2:45

Here's a couple small points that aren't a full review, but might be helpful.

% exists instead of divmod for when you only care about the modulo.

In modInverse

   q = a // m
t = m
m = divmod(a,m)[1]
a = t
t = y
y = x - q * y
x = t


could be written more clearly as

   q = a // m
t = m
a, m = m, a%m
x, y = y, x - q*y


For LCM computation, you should probably rewrite it as return x//math.gcd(x,y) * y as that will keep your numbers smaller, which is always nice (especially when x and y might both be big).

Also, you're RSA implementation isn't secure for details of why see textbook rsa flaws. If you care, the solution is to use something like PKCS which is a padding scheme to provide semantic security, and to fix some other problems.

• Thank you Oscar! I chose the divmod for performance. Unfortunately despite the ugliness it runs faster on my machine for a 100k runs etc. Thank you for the return pointer, I shall do that. Also, I shall add a padding to the RSA, that should be straight forward. – TheHoyt Feb 28 at 0:49
• If you actually care about max performance, you should be using gmpy. For big numbers, it will make everything faster. – Oscar Smith Feb 28 at 3:17
• Though stepping away from the builtins, at this point that'd be nice. Do you mean use gmpy's mpz() type for the numbers? (bc also gmpy can just detect primes with every major test) – TheHoyt Feb 28 at 3:30
• yes they have a mutable type, but it's really hard to use rigth – Oscar Smith Feb 28 at 3:33

This is nice work. Very useful educational tool. Keep up the good work.

Now for some nitpicking:

def isprime(n):

• This function has too much things going on in it. Can you break it to smaller functions by refactor extract function?
def isprime(n):
if not n & 1:  #check if first bit is 1

#Fermat

#MilRab, x**2 = 1 mod P - ERH

def trial_composite(a):

for i in range(100):  #Number of Rabin Witness

• Also if possible trial_composite should also go outside. But I can see this might not be possible.
def modInverse(a, m):
m0 = m

• This function is really hard to understand. Please avoid using single letter variables. Rename them to something meaningful.
• You are using a all over the place. I have no idea what it even means. Try to have meaningful parameters and variables.
• Please add spaces before and after # comments.
BLOCK_SIZE = 128 #Block is 128 no matter what,this is multiple of 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

#RSA
#Unique and Arbitrary Pub E, a prime.
e = 66047 # because I can
#e = 65537

• Please define constants at the top so it's easier to read.
• Why are you naming the lambda functions? Use a def if you want a name.
• What is e here? name it properly so you don't need to comment.
modInverse

• Please use snake_case to name functions. Why: Industry standard. PEP-8. You can use autopep8 or black to format your code.
if choice == 'B' or choice == 'b':
lineoutholder = []
pubkeyname = input('Enter PUBLIC key to encrypt with(recepient): ')
privkey = input('Enter your private KEY you wish to sign with(yours): ')
try:
with open(pubkeyname, 'r') as f1:
except:
exit()
uhaeskey = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(32)])
n = int(bytes.decode(base64.decodestring(bytes(pubkey.encode()))), 16)
workfile = input('Enter the file to ENCRYPT: ')
outfile = input('Enter filename to WRITE out: ')
sha256_hash = hashlib.sha256()
try:
with open(workfile, 'rb') as f2:
with open(workfile, 'rb') as f2:#open again to clear memory
sha256_hash.update(byte_block)
HASH = sha256_hash.hexdigest()
with open(privkey) as f3:
except Exception as x:
print(x)
exit()
d = int(bytes.decode(decryptaes(priv[1], pwkey)))
HASH = [ord(i) for i in HASH]
numhash = ''
for i in HASH:
numhash +=str(i)
signature = pow(int(numhash), d, int(priv[0]))
aeskey = get_private_key(uhaeskey)
plaintext = base64.encodestring(wholefile)
cyphertext = bytes.decode(encryptaes(plaintext.decode('ascii'), aeskey))
shippedpw = encryptit(e, n, uhaeskey.encode())
concat = str(str(signature)+'CUTcutCUTcutCUT'+shippedpw+'CUTcutCUTcutCUT'+cyphertext)
with open(outfile, 'w') as f3:
f3.write(concat)
os.system('gzip -9 {0};mv {0}.gz {0}'.format(outfile))
print('Wrote to {} ...'.format(outfile))

if choice == 'C' or choice == 'c':
dspubkeyname = input('Enter the PUBLIC key to verify the signature with(sender): ')
try:
with open(dspubkeyname, 'r') as f1:
except:
exit()
nsig = int(bytes.decode(base64.decodestring(bytes(pubkey.encode()))), 16)
privkey = input('YOUR private KEY filename to decrypt the data: ')
workfile = input('Enter the file to DECRYPT: ')
outfile = input('Enter the filename to WRITE out: ')
print('DECRYPTING')
os.system('mv {0} {0}.gz;gzip -d {0}.gz'.format(workfile))
sha256_hash = hashlib.sha256()
try:
with open(workfile) as f1:
signature, codedkey, cyphertext =lineholder[0], lineholder[1], lineholder[2]
except:
exit()
try:
with open(privkey) as f2:
except:
n = priv[0]
d = int(bytes.decode(decryptaes(priv[1], pwkey)))
sigdec = pow(int(signature), e, nsig)#Sig Verification step1
aeskey = decryptit(d, n, codedkey)
aeskey = get_private_key(aeskey)
decstr = bytes.decode(decryptaes(cyphertext, aeskey))
cleartext = base64.decodestring(bytes(decstr, 'ascii'))
with open(outfile, 'wb') as f1:
f1.write(cleartext)
with open(outfile, 'rb') as f2:
sha256_hash.update(byte_block)
HASH = sha256_hash.hexdigest()
HASH = [ord(i) for i in HASH]
numhash = ''
for i in HASH:
numhash +=str(i)
if int(numhash) == int(sigdec):
print('Signature Verified')
else:
print('Wrote out to {} '.format(outfile))

• Please don't jam your code together. You are not writing code in an A4 sheet.
• This could also use some extract function refactoring.
os.system('mv {0} {0}.gz;gzip -d {0}.gz'.format(workfile))

• Python already have shutil and gzip modules. They can move, copy files, folders and gzip stuff for you. It would be little more code, but your code can be easily made cross platform this way.
• Thank you 422!! This is great! I shall try to implement your suggestions - though the modular inverse will be hard to make clearer, its easier done on paper. I'll likely need to think for a bit on how to refactor certain bits, put I shall post the updated code either here or a new question. – TheHoyt Feb 28 at 14:03
• @dhoyt902 Create a new question titled Generate public/private keys, encrypt, decrypt, sign, verify v2.0 (You may also change v2.0 to something else you wish like for example follow-up). Plus asking a new question will give you more upvotes :) – 422_unprocessable_entity Feb 28 at 14:25
• @dhoyt902 Also added more info on how you can format code. – 422_unprocessable_entity Feb 28 at 14:28

Here is the padded improved code from the suggestions here:

#!/usr/bin/env python3
import os
import sys
import math
import re
import hashlib
import random
import base64
import string
import getpass
import multiprocessing as mp
from Crypto.Cipher import AES
from Crypto import Random
from Crypto.Protocol.KDF import PBKDF2
#Non builtins
from gmpy2 import is_prime as isprime
from gmpy2 import is_strong_bpsw_prp as ispprime
#Primality testing, extended greatest common divisor and least common multiple

def get1prime(keysize):
while True:
p = random.randrange(1<<(keysize), 1<<(keysize+2))
if isprime(p):
if ispprime(p):
return p

def modInverse(a, m) : #Euclid's Extended Algorithm
m0 = m
y = 0
x = 1
while (a > 1) :
q = a // m
t = m
m = divmod(a,m)[1]
a = t
t = y
y = x - q * y
x = t
if (x < 0) :
x = x + m0
return x

def lcm(x, y):
return (x*y)//math.gcd(x,y)

##AES256CHUNK
salt = b"We will know, we must know"
kdf = PBKDF2(password, salt, 64, 1000)
key = kdf[:32]
return key

cipher = AES.new(private_key, AES.MODE_CBC, iv)
return base64.b64encode(iv + cipher.encrypt(raw))

enc = base64.b64decode(enc)
iv = enc[:16]
cipher = AES.new(private_key, AES.MODE_CBC, iv)

BLOCK_SIZE = 64 #Block is 128 no matter what,this is multiple of 16
pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE)
unpad = lambda s: s[:-ord(s[len(s) - 1:])]

#RSA
#Unique and Arbitrary Pub E, a prime.
e = 66047 # because I can
#e = 65537

def encryptit(e, n, thestring):#for sigining pass d as e
rbinlist = ['{0:08b}'.format(x) for x in thestring]
catstring = ''
catstring += rbinlist[0].lstrip('0')
del rbinlist[0]
for i in rbinlist:
catstring += str(i)
puttynumber = int(catstring,2)
cypherstring = str(pow(puttynumber, e, n))
return cypherstring

def decryptit(d, n, cynum):#for signing pass e as d
decryptmsg = ''
n = int(n)
d = int(d)
puttynum = pow(int(cynum), d, n)
puttynum = '{0:08b}'.format(puttynum)
while True:
if len(puttynum)%8 == 0:
break
puttynum = '0{0}'.format(puttynum)
locs = re.findall('[01]{8}', puttynum)
for x in locs:
letter = chr(int(x,2))
decryptmsg += letter

#Begin User Flow
choice = input("""
██████╗ ██████╗ ██╗   ██╗██████╗ ████████╗
██╔════╝ ██╔══██╗╚██╗ ██╔╝██╔══██╗╚══██╔══╝
██║  ███╗██████╔╝ ╚████╔╝ ██████╔╝   ██║
██║   ██║██╔══██╗  ╚██╔╝  ██╔═══╝    ██║
╚██████╔╝██║  ██║   ██║   ██║        ██║
╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚═╝        ╚═
Welcome to Dan's Cryptography Concept Program.
Generate/Encrypt/Decrypt/Sign
RSA++/DSA++/AES/OTP/Double DH key exch w SHA
Choose:
A: Generate New Public/Private Key Pair
B: Encrypt a File
C: Decrypt a File
=> """)

if choice == 'A' or choice == 'a':
try:
keysize = (int(input("Enter a keysize:  "))>>1)
except ValueError as a:
print('Enter a number\n\n')
sys.exit()
pubkeyname = input('Input desired public key name: ')
pkey = input('Input desired private key name: ')
print('Generating Keys...')
primes = []
plist = []
for i in range(mp.cpu_count()):
plist.append(keysize)
workpool = mp.Pool(processes=mp.cpu_count())
reslist = workpool.imap_unordered(get1prime, plist)
workpool.close()
for res in reslist:
if res:
primes.append(res)
workpool.terminate()
break
workpool.join()
#
workpool1 = mp.Pool(processes=mp.cpu_count())
reslist = workpool1.imap_unordered(get1prime, plist)
workpool1.close()
for res in reslist:
if res:
primes.append(res)
workpool1.terminate()
break
workpool1.join()
if primes[0] != primes[1]:
p, q = primes[0], primes[1]
else:
print('Supremely Unlucky Try Again')
exit()
n = p*q
cm = lcm(p-1, q-1)
print('Computing Private key ...')
d = modInverse(e, cm)
print('Private Key Size: {} bits'.format(keysize*2))
print('Functional Length of: {}'.format(len(bin((d)))))
keystring = encryptaes(str(d).encode('ascii', errors='ignore').decode('utf-8'),pwkey)
b64key = bytes.decode(base64.encodestring(bytes(str(hex(n)).encode())))
with open(pkey, 'w') as f1:
f1.write(str(n)+'\n')
f1.write(bytes.decode(keystring))
with open(pubkeyname, 'w') as f2:
f2.write(b64key)
print('Complete - {} and {} generated'.format(pubkeyname,pkey))
print('e exponent: {}'.format(str(e)))
print("""
-----BEGIN PUBLIC KEY-----
{}-----END PUBLIC KEY-----
""".format(b64key))
b64privkey = b64key = bytes.decode(base64.encodestring(bytes(str(hex(d)).encode())))
print("""
-----BEGIN PRIVATE KEY-----
{}-----END PRIVATE KEY-----
""".format(b64privkey))

if choice == 'B' or choice == 'b':
lineoutholder = []
pubkeyname = input('Enter PUBLIC key to encrypt with(recepient): ')
privkey = input('Enter your private KEY you wish to sign with(yours): ')
try:
with open(pubkeyname, 'r') as f1:
except:
exit()
uhaeskey = ''.join([random.choice(string.ascii_letters + string.digits) for n in range(32)])
n = int(bytes.decode(base64.decodestring(bytes(pubkey.encode()))), 16)
workfile = input('Enter the file to ENCRYPT: ')
outfile = input('Enter filename to WRITE out: ')
sha256_hash = hashlib.sha256()
try:
os.system('gzip -9 {0};mv {0}.gz {0}'.format(workfile))
with open(workfile, 'rb') as f2:
with open(workfile, 'rb') as f2:#open again to clear memory
sha256_hash.update(byte_block)
HASH = sha256_hash.hexdigest()
with open(privkey) as f3:
except Exception as x:
print(x)
exit()
d = int(bytes.decode(decryptaes(priv[1], pwkey)))
HASH = [ord(i) for i in HASH]
numhash = ''
for i in HASH:
numhash +=str(i)
signature = pow(int(numhash), d, int(priv[0]))
aeskey = get_private_key(uhaeskey)
plaintext = base64.encodestring(wholefile)
cyphertext = bytes.decode(encryptaes(plaintext.decode('ascii'), aeskey))
shippedpw = encryptit(e, n, uhaeskey.encode())
concat = str(str(signature)+'CUTcutCUTcutCUT'+shippedpw+'CUTcutCUTcutCUT'+cyphertext)
with open(outfile, 'w') as f3:
f3.write(concat)
os.system('gzip -9 {0};mv {0}.gz {0};mv {1} {1}.gz;gzip -d {1}'.format(outfile, workfile))
print('Wrote to {} ...'.format(outfile))

if choice == 'C' or choice == 'c':
dspubkeyname = input('Enter the PUBLIC key to verify the signature with(sender): ')
try:
with open(dspubkeyname, 'r') as f1:
except:
exit()
nsig = int(bytes.decode(base64.decodestring(bytes(pubkey.encode()))), 16)
privkey = input('YOUR private KEY filename to decrypt the data: ')
workfile = input('Enter the file to DECRYPT: ')
outfile = input('Enter the filename to WRITE out: ')
print('DECRYPTING')
os.system('mv {0} {0}.gz;gzip -d {0}.gz'.format(workfile))
sha256_hash = hashlib.sha256()
try:
with open(workfile) as f1:
signature, codedkey, cyphertext =lineholder[0], lineholder[1], lineholder[2]
except:
exit()
try:
with open(privkey) as f2:
except:
n = priv[0]
d = int(bytes.decode(decryptaes(priv[1], pwkey)))
sigdec = pow(int(signature), e, nsig)#Sig Verification step1
aeskey = decryptit(d, n, codedkey)
aeskey = get_private_key(aeskey)
decstr = bytes.decode(decryptaes(cyphertext, aeskey))
cleartext = base64.decodestring(bytes(decstr, 'ascii'))
with open(outfile, 'wb') as f1:
f1.write(cleartext)
with open(outfile, 'rb') as f2:
sha256_hash.update(byte_block)
HASH = sha256_hash.hexdigest()
HASH = [ord(i) for i in HASH]
numhash = ''
for i in HASH:
numhash +=str(i)
if int(numhash) == int(sigdec):
print('Signature Verified')
else: