def __init__(self, me, peer, basedir): self.me = me self.peer = peer self.basedir = basedir self.e_in = ('\0' * nacl.crypto_scalarmult_curve25519_BYTES) self.e_out = ('\0' * nacl.crypto_scalarmult_curve25519_BYTES) self.out_k = ('\0' * nacl.crypto_secretbox_KEYBYTES) self.in_k = ('\0' * nacl.crypto_secretbox_KEYBYTES) self.in_prev = ('\0' * nacl.crypto_secretbox_KEYBYTES) self.peer_pub = ('\0' * nacl.crypto_scalarmult_curve25519_BYTES) self.me_id = publickey.Identity(self.me, basedir=self.basedir) self.peer_id = publickey.Identity(self.peer, basedir=self.basedir)
def encrypt_handler(infile=None, outfile=None, recipient=None, self=None, basedir=None): # provides a high level function to do encryption of files # infile specifies the filename of the input file, # if '-' or not specified it uses stdin # outfile specifies the filename of the output file, if not specified # it uses the same filename with '.pbp' appended # recipient specifies the name of the recipient for using public key crypto # self specifies the sender for signing the message using pk crypto # basedir provides a root for the keystores needed for pk crypto # if both self and recipient is specified pk crypto is used, otherwise symmetric # this function also handles buffering. fd = inputfd(infile) outfd = outputfd(outfile or (infile + '.pbp' if infile not in [None, '-'] else '-')) if recipient and self: # let's do public key encryption key = nacl.randombytes(nacl.crypto_secretbox_KEYBYTES) me = publickey.Identity(self, basedir=basedir) size = struct.pack('>H', len(recipient)) # write out encrypted message key (nonce, c(key+recplen)) for each recipient for r in recipient: r = publickey.Identity(r, basedir=basedir, publicOnly=True) nonce = nacl.randombytes(nacl.crypto_box_NONCEBYTES) outfd.write(nonce) outfd.write(nacl.crypto_box(key + size, nonce, r.cp, me.cs)) me.clear() else: # let's do symmetric crypto key = getkey(nacl.crypto_secretbox_KEYBYTES) buf = fd.read(BLOCK_SIZE) if buf: nonce, cipher = encrypt(buf, k=key) outfd.write(nonce) outfd.write(cipher) buf = fd.read(BLOCK_SIZE) while buf: nonce = inc_nonce(nonce) nonce, cipher = encrypt(buf, k=key, nonce=nonce) outfd.write(cipher) buf = fd.read(BLOCK_SIZE) clearmem(key) key = None if fd != sys.stdin: fd.close() if outfd != sys.stdout and isinstance(outfd, file): outfd.close()
def sign_handler(infile=None, outfile=None, self=None, basedir=None, armor=False): # provides a high level function to sign files # infile specifies the filename of the input file, # if '-' or not specified it uses stdin # outfile specifies the filename of the output file, # if unspecified but armor is, or if '-' or # infile is unspecified, then it uses stdout # otherwise it appends '.sig' to infile # armor instructs the function to output ascii # self specifies the sender for signing the message # basedir provides a root for the keystores # this function also handles buffering. fd = inputfd(infile) if (not outfile and armor) or outfile == '-' or (not infile or infile == '-'): outfd = sys.stdout else: outfd = open(outfile or infile + '.sig', 'w') publickey.Identity(self, basedir=basedir).buffered_sign(fd, outfd, armor) if fd != sys.stdin: fd.close() if outfd != sys.stdout: outfd.close()
def load(self): keyfdir = "%s/sk/.%s" % (self.basedir, self.me) if not os.path.exists(keyfdir): os.mkdir(keyfdir) return self keyfname = '%s/%s' % (keyfdir, self.peer) if not os.path.exists(keyfname): return self if not self.me_id: self.me_id = publickey.Identity(self.me, basedir=self.basedir) with open(keyfname, 'r') as fd: nonce = fd.read(nacl.crypto_box_NONCEBYTES) plain = nacl.crypto_box_open(fd.read(), nonce, self.me_id.cp, self.me_id.cs) c = nacl.crypto_scalarmult_curve25519_BYTES i = 0 self.e_in = plain[:c] i += c self.e_out = plain[i:i + c] i += c self.peer_pub = plain[i:i + c] i += c c = nacl.crypto_secretbox_KEYBYTES self.out_k = plain[i:i + c] i += c self.in_k = plain[i:i + c] i += c self.in_prev = plain[i:i + c]
def encrypt_handler(infile=None, outfile=None, recipient=None, self=None, basedir=None): if not infile or infile == '-': fd = sys.stdin.buffer if hasattr(sys.stdin, 'buffer') else sys.stdin else: fd = open(infile, 'rb') if outfile == '-': outfd = sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout else: outfd = open(outfile or infile + '.pbp', 'wb') if recipient and self: # let's do public key encryption key = nacl.randombytes(nacl.crypto_secretbox_KEYBYTES) me = publickey.Identity(self, basedir=basedir) peerkeys = me.keyencrypt(key, recipients=[ publickey.Identity(x, basedir=basedir) for x in recipient ]) me.clear() outfd.write(struct.pack("B", ASYM_CIPHER)) outfd.write(struct.pack(">L", len(peerkeys))) for rnonce, ct in peerkeys: outfd.write(rnonce) outfd.write(struct.pack("B", len(ct))) outfd.write(ct) else: # let's do symmetric crypto key = getkey(nacl.crypto_secretbox_KEYBYTES) outfd.write(struct.pack("B", BLOCK_CIPHER)) buf = fd.read(BLOCK_SIZE) while buf: nonce, cipher = encrypt(buf, k=key) outfd.write(nonce) outfd.write(cipher) buf = fd.read(BLOCK_SIZE) clearmem(key) if infile != sys.stdin: fd.close() if outfile != sys.stdout: outfd.close()
def decrypt(self, cipher, nonce): if self.in_k == (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): # use pk crypto to decrypt the packet if not self.peer_id: self.peer_id = publickey.Identity(self.peer, basedir=self.basedir) if not self.me_id: self.me_id = publickey.Identity(self.me, basedir=self.basedir) return nacl.crypto_box_open(cipher, nonce, self.peer_id.cp, self.me_id.cs) else: # decrypt using chained keys try: return nacl.crypto_secretbox_open(cipher, nonce, self.in_k) except ValueError: # with previous key in case a prev send failed to be delivered return nacl.crypto_secretbox_open(cipher, nonce, self.in_prev)
def encrypt(self, plain): if self.out_k == (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): # encrypt using public key nonce = nacl.randombytes(nacl.crypto_box_NONCEBYTES) if not self.peer_id: self.peer_id = publickey.Identity(self.peer, basedir=self.basedir) if not self.me_id: self.me_id = publickey.Identity(self.me, basedir=self.basedir) cipher = nacl.crypto_box(plain, nonce, self.peer_id.cp, self.me_id.cs) else: # encrypt using chaining mode nonce = nacl.randombytes(nacl.crypto_secretbox_NONCEBYTES) cipher = nacl.crypto_secretbox(plain, nonce, self.out_k) return cipher, nonce
def export_handler(self, basedir=None): # exports key self from basedir, outputs to stdout, key is ascii armored keys = publickey.Identity(self, basedir=basedir) dates = '{:<32}{:<32}'.format(keys.created.isoformat(), keys.valid.isoformat()) pkt = keys.sign(keys.mp + keys.sp + keys.cp + dates + keys.name, master=True) keys.clear() return b85encode(pkt, True)
def load(self): keyfname="%s/dh/%s/%s" % (self.basedir, self.me, self.id) if not self.me_id: self.me_id = publickey.Identity(self.me, basedir=self.basedir) with open(keyfname,'r') as fd: nonce = fd.read(nacl.crypto_box_NONCEBYTES) raw = fd.read() self.key = nacl.crypto_box_open(raw, nonce, self.me_id.cp, self.me_id.cs) os.remove(keyfname)
def decrypt_handler(infile=None, outfile=None, self=None, basedir=None): if not infile or infile == '-': fd = sys.stdin.buffer if hasattr(sys.stdin, 'buffer') else sys.stdin else: fd = open(infile, 'rb') if not outfile or outfile == '-': outfd = sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout else: outfd = open(outfile, 'wb') key = None type = struct.unpack('B', fd.read(1))[0] # asym if type == ASYM_CIPHER: if not self: sys.stderr.write( "Error: need to specify your own key using the --self param\n") raise ValueError size = struct.unpack('>L', fd.read(4))[0] r = [] for _ in range(size): rnonce = fd.read(nacl.crypto_box_NONCEBYTES) ct = fd.read(struct.unpack('B', fd.read(1))[0]) r.append((rnonce, ct)) me = publickey.Identity(self, basedir=basedir) me.clear() sender, key = me.keydecrypt(r) if sender: sys.stderr.write('good key from %s\n' % sender) else: sys.stderr.write('decryption failed\n') # sym elif type == BLOCK_CIPHER: pwd = getpass.getpass('Passphrase for decrypting: ') key = scrypt.hash(pwd, scrypt_salt)[:nacl.crypto_secretbox_KEYBYTES] clearmem(pwd) else: sys.stderr.write('decryption failed\n') if key: nonce = fd.read(nacl.crypto_secretbox_NONCEBYTES) while len(nonce) == nacl.crypto_secretbox_NONCEBYTES: buf = fd.read(BLOCK_SIZE) if not buf: sys.stderr.write('decryption failed\n') break outfd.write(decrypt((nonce, buf), k=key)) nonce = fd.read(nacl.crypto_secretbox_NONCEBYTES) clearmem(key) if 0 < len(nonce) < nacl.crypto_secretbox_NONCEBYTES: sys.stderr.write('decryption failed\n') if infile != sys.stdin: fd.close() if outfile != sys.stdout: outfd.close()
def keysign_handler(name=None, self=None, basedir=None): fname = publickey.get_pk_filename(basedir, name) with open(fname, 'rb') as fd: data = fd.read() with open(fname + '.sig', 'ab') as fd: me = publickey.Identity(self, basedir=basedir) sig = me.sign(data, master=True) if not sig: sys.stderr.write('signature failed\n') me.clear() fd.write(sig[:nacl.crypto_sign_BYTES])
def save(self): keyfdir = "%s/sk/.%s" % (self.basedir, self.me) if not os.path.exists(keyfdir): os.mkdir(keyfdir) fname = '%s/%s' % (keyfdir, self.peer) nonce = nacl.randombytes(nacl.crypto_box_NONCEBYTES) ctx = ''.join((self.e_in, self.e_out, self.peer_pub, self.out_k, self.in_k, self.in_prev)) if not self.me_id: self.me_id = publickey.Identity(self.me, basedir=self.basedir) with open(fname, 'w') as fd: fd.write(nonce) fd.write(nacl.crypto_box(ctx, nonce, self.me_id.cp, self.me_id.cs))
def save(self): keyfdir="%s/dh/" % (self.basedir) if not os.path.exists(keyfdir): os.mkdir(keyfdir) keyfdir="%s/%s" % (keyfdir, self.me) if not os.path.exists(keyfdir): os.mkdir(keyfdir) fname='%s/%s' % (keyfdir, self.id) nonce = nacl.randombytes(nacl.crypto_box_NONCEBYTES) if not self.me_id: self.me_id = publickey.Identity(self.me, basedir=self.basedir) with open(fname,'w') as fd: fd.write(nonce) fd.write(nacl.crypto_box(self.key, nonce, self.me_id.cp, self.me_id.cs))
def keysign_handler(name=None, self=None, basedir=None): # handles signing of keys using the master key # name is the key to be signed # self the signers name # basedir the root for the keystore fname = publickey.get_pk_filename(basedir, name) with open(fname, 'r') as fd: data = fd.read() with open(fname + '.sig', 'a') as fd: me = publickey.Identity(self, basedir=basedir) sig = me.sign(data, master=True) if sig: me.clear() fd.write(sig[:nacl.crypto_sign_BYTES]) return fname + '.sig'
def import_handler(infile=None, basedir=None): if not infile: b85 = sys.stdin.readline().strip() else: with open(infile, 'rb') as fd: b85 = fd.readline().strip() pkt = b85decode(b85) mp = pkt[nacl.crypto_sign_BYTES:nacl.crypto_sign_BYTES + nacl.crypto_sign_PUBLICKEYBYTES] keys = nacl.crypto_sign_open(pkt, mp) if not keys: die("invalid key") name = keys[nacl.crypto_sign_PUBLICKEYBYTES * 3:] peer = publickey.Identity(name, basedir=basedir) peer.mp = mp peer.cp = keys[nacl. crypto_sign_PUBLICKEYBYTES:nacl.crypto_sign_PUBLICKEYBYTES * 2] peer.sp = keys[nacl.crypto_sign_PUBLICKEYBYTES * 2:nacl.crypto_sign_PUBLICKEYBYTES * 3] # TODO check if key exists, then ask for confirmation of pk overwrite peer.save() print('Success: imported public keys for', name)
def sign_handler(infile=None, outfile=None, self=None, basedir=None, armor=False): if not infile or infile == '-': fd = sys.stdin.buffer if hasattr(sys.stdin, 'buffer') else sys.stdin else: fd = open(infile, 'rb') if (not outfile and armor) or outfile == '-': outfd = sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout else: outfd = open(outfile or infile + '.sig', 'wb') # calculate hash sum of data state = nacl.crypto_generichash_init() while True: block = fd.read(BLOCK_SIZE) if not block.strip(): break state = nacl.crypto_generichash_update(state, block) outfd.write(block) hashsum = nacl.crypto_generichash_final(state) me = publickey.Identity(self, basedir=basedir) # sign hashsum sig = me.sign(hashsum)[:nacl.crypto_sign_BYTES] me.clear() if armor: outfd.write(SIGPREFIX) outfd.write(b85encode(sig)) else: outfd.write(sig) if fd != sys.stdin: fd.close() if outfd != sys.stdout: outfd.close()
def export_handler(self, basedir=None): keys = publickey.Identity(self, basedir=basedir) pkt = keys.sign(keys.mp + keys.cp + keys.sp + keys.name, master=True) keys.clear() print(b85encode(pkt))
def decrypt_handler(infile=None, outfile=None, self=None, peer=None, max_recipients=20, basedir=None): # provides a high level function to do decryption of files # infile specifies the filename of the input file, # if '-' or not specified it uses stdin # outfile specifies the filename of the output file, if not specified # it uses the same filename with '.pbp' appended # self specifies the recipient of the message for using pk crypto # basedir provides a root for the keystores needed for pk crypto # if self is specified pk crypto is used, otherwise symmetric # this function also handles buffering. fd = inputfd(infile) outfd = outputfd(outfile) key = None # asym if self: me = publickey.Identity(self, basedir=basedir) if peer: peer = publickey.Identity(peer, basedir=basedir, publicOnly=True) sender = None size = None i = 0 while i < (max_recipients if not size else size): i += 1 rnonce = fd.read(nacl.crypto_box_NONCEBYTES) ct = fd.read(nacl.crypto_secretbox_KEYBYTES + 2 + nacl.crypto_secretbox_MACBYTES) if sender: continue for keys in ([peer] if peer else publickey.get_public_keys( basedir=basedir)): try: tmp = nacl.crypto_box_open(ct, rnonce, keys.cp, me.cs) except ValueError: continue key = tmp[:nacl.crypto_secretbox_KEYBYTES] size = struct.unpack('>H', tmp[nacl.crypto_secretbox_KEYBYTES:])[0] sender = keys.name break me.clear() if not sender: raise ValueError('decryption failed') # sym else: pwd = getpass.getpass('Passphrase for decrypting: ') key = scrypt.hash(pwd, scrypt_salt)[:nacl.crypto_secretbox_KEYBYTES] sender = None clearmem(pwd) pwd = None if key: nonce = fd.read(nacl.crypto_secretbox_NONCEBYTES) buf = fd.read(BLOCK_SIZE + nacl.crypto_secretbox_MACBYTES) while buf: outfd.write(decrypt((nonce, buf), k=key)) nonce = inc_nonce(nonce) buf = fd.read(BLOCK_SIZE + nacl.crypto_secretbox_MACBYTES) clearmem(key) key = None if fd != sys.stdin: fd.close() if outfd != sys.stdout and type(outfd) == file: outfd.close() return sender
def gen_key(self): self.numkeys += 1 return publickey.Identity(NAME + str(self.numkeys), basedir=self.pbp_path, create=True)
def main(): parser = argparse.ArgumentParser(description='pbp') group = parser.add_mutually_exclusive_group() group.add_argument('--gen-key', '-g', dest='action', action='store_const', const='g', help="generates a new key") group.add_argument('--encrypt', '-c', dest='action', action='store_const', const='c', help="encrypts") group.add_argument('--decrypt', '-d', dest='action', action='store_const', const='d', help="decrypts") group.add_argument('--sign', '-s', dest='action', action='store_const', const='s', help="signs") group.add_argument('--master-sign', '-m', dest='action', action='store_const', const='m', help="signs keys with your masterkey") group.add_argument('--verify', '-v', dest='action', action='store_const', const='v', help="verifies") group.add_argument('--list', '-l', dest='action', action='store_const', const='l', help="lists public keys") group.add_argument('--list-secret', '-L', dest='action', action='store_const', const='L', help="Lists secret keys") group.add_argument('--export-key', '-x', dest='action', action='store_const', const='x', help="export public key") group.add_argument('--import-key', '-X', dest='action', action='store_const', const='X', help="import public key") group.add_argument('--check-sigs', '-C', dest='action', action='store_const', const='C', help="lists all known sigs on a public key") group.add_argument('--fcrypt', '-e', dest='action', action='store_const', const='e', help="encrypts a message using PFS to a peer") group.add_argument('--fdecrypt', '-E', dest='action', action='store_const', const='E', help="decrypts a message using PFS to a peer") group.add_argument('--dh-start', '-D1', dest='action', action='store_const', const='d1', help="initiates an ECDH key exchange") group.add_argument('--dh-respond', '-D2', dest='action', action='store_const', const='d2', help="responds to an ECDH key request") group.add_argument('--dh-end', '-D3', dest='action', action='store_const', const='d3', help="finalizes an ECDH key exchange") group.add_argument('--rand-stream', '-R', dest='action', action='store_const', const='R', help="generate arbitrary random stream") parser.add_argument( '--recipient', '-r', action='append', help="designates a recipient for public key encryption") parser.add_argument('--name', '-n', help="sets the name for a new key") parser.add_argument( '--basedir', '-b', '--base-dir', help="set the base directory for all key storage needs", default=defaultbase) parser.add_argument('--self', '-S', help="sets your own key") parser.add_argument('--dh-param', '-Dp', help="public parameter for ECDH key exchange") parser.add_argument('--dh-exp', '-De', help="public parameter for ECDH key exchange") parser.add_argument('--size', '-Rs', help="size of random stream to generate") parser.add_argument('--infile', '-i', help="file to operate on") parser.add_argument('--armor', '-a', action='store_true', help="ascii armors the output") parser.add_argument('--outfile', '-o', help="file to output to") opts = parser.parse_args() opts.basedir = os.path.expandvars(os.path.expanduser(opts.basedir)) # Generate key if opts.action == 'g': ensure_name_specified(opts) publickey.Identity(opts.name, create=True, basedir=opts.basedir) # list public keys elif opts.action == 'l': for i in publickey.get_public_keys(opts.basedir): print('valid' if i.valid > datetime.datetime.utcnow() > i.created else 'invalid'), i.keyid(), i.name # list secret keys elif opts.action == 'L': for i in publickey.get_secret_keys(opts.basedir): print('valid' if i.valid > datetime.datetime.utcnow() > i.created else 'invalid'), i.keyid(), i.name # encrypt elif opts.action == 'c': if opts.recipient or opts.self: ensure_self_specified(opts) ensure_recipient_specified(opts) encrypt_handler(infile=opts.infile, outfile=opts.outfile, recipient=opts.recipient, self=opts.self, basedir=opts.basedir) # decrypt elif opts.action == 'd': decrypt_handler(infile=opts.infile, outfile=opts.outfile, self=opts.self, basedir=opts.basedir) # sign elif opts.action == 's': ensure_self_specified(opts) sign_handler(infile=opts.infile, outfile=opts.outfile, self=opts.self, armor=opts.armor, basedir=opts.basedir) # verify elif opts.action == 'v': verify_handler(infile=opts.infile, outfile=opts.outfile, basedir=opts.basedir) # key sign elif opts.action == 'm': ensure_name_specified(opts) ensure_self_specified(opts) keysign_handler(name=opts.name, self=opts.self, basedir=opts.basedir) # lists signatures owners on public keys elif opts.action == 'C': ensure_name_specified(opts) keycheck_handler(name=opts.name, basedir=opts.basedir) # export public key elif opts.action == 'x': ensure_self_specified(opts) export_handler(opts.self, basedir=opts.basedir) # import public key elif opts.action == 'X': import_handler(infile=opts.infile, basedir=opts.basedir) # forward encrypt elif opts.action == 'e': ensure_recipient_specified(opts) ensure_only_one_recipient(opts) # TODO could try to find out this automatically if non-ambiguous ensure_self_specified(opts) chaining_encrypt_handler(opts.infile, outfile=opts.outfile, recipient=opts.recipient[0], self=opts.self, armor=opts.armor, basedir=opts.basedir) # forward decrypt elif opts.action == 'E': ensure_recipient_specified(opts) ensure_only_one_recipient(opts) # TODO could try to find out this automatically if non-ambiguous ensure_self_specified(opts) chaining_decrypt_handler(opts.infile, outfile=opts.outfile, recipient=opts.recipient[0], self=opts.self, basedir=opts.basedir) # start ECDH elif opts.action == 'd1': dh1_handler() # receive ECDH elif opts.action == 'd2': ensure_dhparam_specified(opts) dh2_handler(opts.dh_param) # finish ECDH elif opts.action == 'd3': ensure_dhparam_specified(opts) ensure_dhexp_specified(opts) dh3_handler(opts.dh_param, opts.dh_exp) elif opts.action == 'R': ensure_size_good(opts) random_stream_handler(opts.outfile, opts.size)
parser.add_argument('--infile', '-i', help="file to operate on") parser.add_argument('--armor', '-a', action='store_true', help="ascii armors the output") parser.add_argument('--outfile', '-o', help="file to output to") opts=parser.parse_args() opts.basedir=os.path.expandvars( os.path.expanduser(opts.basedir)) if os.path.exists(opts.basedir): mode = os.stat(opts.basedir).st_mode & 0777 if mode not in [0700, 0600]: print >>sys.stderr, '[pbp] ABORT: unsafe permissions %s on basedir %s' % (oct(mode), opts.basedir) # Generate key if opts.action=='g': ensure_name_specified(opts) publickey.Identity(opts.name, create=True, basedir=opts.basedir) # list public keys elif opts.action=='l': if PITCHFORK and opts.PITCHFORK: pitchfork.init() res = pitchfork.listkeys(opts.name) if(res): keys, stats = res pitchfork.print_keys(keys) pitchfork.storage_stats(stats, keys) else: print 'none' else: for i in publickey.get_public_keys(opts.basedir): print ('valid' if i.valid > datetime.datetime.utcnow() > i.created