def _3user(): eA = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pA = nacl.crypto_scalarmult_curve25519_base(eA) print "A public: \t%s\nA exp: \t%s" % (b85encode(pA), b85encode(eA)) eB = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pB = nacl.crypto_scalarmult_curve25519_base(eB) print "B public: \t%s\nB exp: \t%s" % (b85encode(pB), b85encode(eB)) eC = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pC = nacl.crypto_scalarmult_curve25519_base(eC) print "C public: \t%s\nC exp: \t%s" % (b85encode(pC), b85encode(eC)) print pAB = nacl.crypto_scalarmult_curve25519(eB, pA) print "public AB", b85encode(pAB) pBA = nacl.crypto_scalarmult_curve25519(eA, pB) print "public BA", b85encode(pBA) pCA = nacl.crypto_scalarmult_curve25519(eA, pC) print "public CA", b85encode(pCA) print key = nacl.crypto_scalarmult_curve25519(eB, pCA) print "key: \t%s" % (b85encode(key)) key = nacl.crypto_scalarmult_curve25519(eC, pBA) print "key: \t%s" % (b85encode(key)) key = nacl.crypto_scalarmult_curve25519(eC, pAB) print "key: \t%s" % (b85encode(key))
def _3user(): eA = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pA = nacl.crypto_scalarmult_curve25519_base(eA) print("A public: \t%s\nA exp: \t%s" % (b85encode(pA), b85encode(eA))) eB = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pB = nacl.crypto_scalarmult_curve25519_base(eB) print("B public: \t%s\nB exp: \t%s" % (b85encode(pB), b85encode(eB))) eC = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) pC = nacl.crypto_scalarmult_curve25519_base(eC) print("C public: \t%s\nC exp: \t%s" % (b85encode(pC), b85encode(eC))) print() pAB = nacl.crypto_scalarmult_curve25519(eB, pA) print("public AB", b85encode(pAB)) pBA = nacl.crypto_scalarmult_curve25519(eA, pB) print("public BA", b85encode(pBA)) pCA = nacl.crypto_scalarmult_curve25519(eA, pC) print("public CA", b85encode(pCA)) print() key = nacl.crypto_scalarmult_curve25519(eB, pCA) print("key: \t%s" % (b85encode(key))) key = nacl.crypto_scalarmult_curve25519(eC, pBA) print("key: \t%s" % (b85encode(key))) key = nacl.crypto_scalarmult_curve25519(eC, pAB) print("key: \t%s" % (b85encode(key)))
def puree_destroy(d, # device v, # show verbose output q # just destroy first and last MiB ): # Calculate how many multiples of 1GiB (and after that, remaining 1MiB) that are on the disk device_bytes = blockdev_size(d) if device_bytes%1048576!=0: raise RuntimeError("Refusing to destroy device: device size isn't a multiple of 1MiB, which is irregular.") device_mibs = device_bytes//1048576 device_gibs_total = device_mibs//1024 device_gibs_remaining_mibs = device_mibs%1024 # Quick destroy if(q): with open(d, 'wb') as f: # Destroy first 1MiB f.seek(0) f.write(pysodium.randombytes(1048576)) # Destroy last 1MiB f.seek(device_bytes-1048576) f.write(pysodium.randombytes(1048576)) # Destroy ENTIRE DISK else: with open(d, 'wb') as f: f.seek(0) for g in range(0,device_gibs_total): for m in range(0,1024): f.write(pysodium.randombytes(1048576)) printProgressBar(g, device_gibs_total, prefix = 'Progress:', suffix = 'Complete', length = 50) for m in range(0,device_gibs_remaining_mibs): f.write(pysodium.randombytes(1048576)) printProgressBar(device_gibs_total, device_gibs_total, prefix = 'Progress:', suffix = 'Complete', length = 50)
def randrange(n): a = (n.bit_length() + 7) // 8 # number of bytes to store n b = 8 * a - n.bit_length() # number of shifts to have good bit number r = int.from_bytes(randombytes(a), byteorder='big') >> b while r >= n: r = int.from_bytes(randombytes(a), byteorder='big') >> b return r
def send(self, plain): # update context if self.peer_pub != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): # calculate a new incoming key, and finish that DH, start a new for # outgoing keys. # only do this directly after receiving a packet, not on later sends # without receiving any acks before, we reset peer_pub to signal, that # an incoming request has been already once processed like this. self.e_in = nacl.randombytes( nacl.crypto_scalarmult_curve25519_BYTES) self.in_prev = self.in_k self.in_k = nacl.crypto_scalarmult_curve25519( self.e_in, self.peer_pub) self.peer_pub = (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) # generate e_out self.e_out = nacl.randombytes( nacl.crypto_scalarmult_curve25519_BYTES) elif self.out_k == (b'\0' * nacl.crypto_secretbox_KEYBYTES): # only for the very first packet necessary # we explicitly need to generate e_out self.e_out = nacl.randombytes( nacl.crypto_scalarmult_curve25519_BYTES) # compose packet dh1 = nacl.crypto_scalarmult_curve25519_base(self.e_out) dh2 = (nacl.crypto_scalarmult_curve25519_base(self.e_in) if self.e_in != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) else (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES)) plain = b''.join((dh1, dh2, plain)) # encrypt the whole packet return self.encrypt(plain)
def constructSTSResponse(self, mType, addr, exchangeData): data = None addrStr = sts_utility.addrToString(addr) if addrStr in STS.STSConnectionStates.keys(): if STS.STSConnectionStates[addrStr][ 'cSuite'] == 1 or STS.STSConnectionStates[addrStr][ 'cSuite'] == 4: nonce = pysodium.randombytes( pysodium.crypto_aead_chacha20poly1305_ietf_NONCEBYTES) m = struct.pack('>B', mType) + struct.pack('>I', len(nonce)) # T = struct.pack('>Q', int(time.time())) encrypData = pysodium.crypto_aead_chacha20poly1305_ietf_encrypt( exchangeData, m, nonce, STS.STSConnectionStates[addrStr]['session_key'][:32]) data = m + nonce + encrypData elif STS.STSConnectionStates[addrStr][ 'cSuite'] == 2 or STS.STSConnectionStates[addrStr][ 'cSuite'] == 5: nonce = pysodium.randombytes( pysodium.crypto_aead_chacha20poly1305_NONCEBYTES) m = struct.pack('>B', mType) + struct.pack('>I', len(nonce)) # T = struct.pack('>Q', int(time.time())) encrypData = pysodium.crypto_aead_chacha20poly1305_encrypt( exchangeData, m, nonce, STS.STSConnectionStates[addrStr]['session_key'][:32]) data = m + nonce + encrypData # print(binascii.hexlify(T)) # print(binascii.hexlify(pysodium.crypto_aead_chacha20poly1305_ietf_decrypt(encrypData, m, nonce, myTX[:32]))) return data
def send(self,plain): # update context if self.peer_pub != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES): # calculate a new incoming key, and finish that DH, start a new for # outgoing keys. # only do this directly after receiving a packet, not on later sends # without receiving any acks before, we reset peer_pub to signal, that # an incoming request has been already once processed like this. self.e_in = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) self.in_prev = self.in_k self.in_k = nacl.crypto_scalarmult_curve25519(self.e_in, self.peer_pub) self.peer_pub = (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) # generate e_out self.e_out = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) elif self.out_k == (b'\0' * nacl.crypto_secretbox_KEYBYTES): # only for the very first packet necessary # we explicitly need to generate e_out self.e_out = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) #else: # axolotlize # print 'axolotl!' # self.out_k = nacl.crypto_generichash(self.out_k, # nacl.crypto_scalarmult_curve25519(self.me_id.cs, self.peer_id.cp), # nacl.crypto_scalarmult_curve25519_BYTES) # compose packet dh1 = nacl.crypto_scalarmult_curve25519_base(self.e_out) dh2 = (nacl.crypto_scalarmult_curve25519_base(self.e_in) if self.e_in != (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES) else (b'\0' * nacl.crypto_scalarmult_curve25519_BYTES)) plain = b''.join((dh1, dh2, plain)) # encrypt the whole packet return self.encrypt(plain)
def test_crypto_secretbox_open_detached(self): m = b"howdy" n = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES) k = pysodium.randombytes(pysodium.crypto_secretbox_KEYBYTES) c, mac = pysodium.crypto_secretbox_detached(m, n, k) mplain = pysodium.crypto_secretbox_open_detached(c, mac, n, k) self.assertEqual(m, mplain) changed = b"\0"*len(c) self.assertRaises(ValueError, pysodium.crypto_secretbox_open_detached, changed, mac, n, k)
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) 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 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) 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 encrypt_keys(self, keyidxs, keys, topic, msgval=None): if (isinstance(topic,(bytes,bytearray))): self._logger.debug("passed a topic in bytes (should be string)") topic = topic.decode('utf-8') # # msgval should be a msgpacked chain. # The public key in the array is the public key to send the key to, using a # common DH-derived key between that public key and our private encryption key. # Then there is at least one more additional item, random bytes: # (3) random bytes # Currently items after this are ignored, and reserved for future use. # try: with self.__allowdenylist_lock: pk,_ = process_chain(msgval,topic,'key-encrypt-request',allowlist=self.__allowlist,denylist=self.__denylist) # Construct shared secret as sha256(topic || random0 || random1 || our_private*their_public) epk = self.__cryptokey.get_epk(topic, 'encrypt_keys') pks = [pk[2]] eks = self.__cryptokey.use_epk(topic, 'encrypt_keys',pks) ek = eks[0] eks[0] = epk random0 = pk[3] random1 = pysodium.randombytes(self.__randombytes) ss = pysodium.crypto_hash_sha256(topic.encode('utf-8') + random0 + random1 + ek)[0:pysodium.crypto_secretbox_KEYBYTES] nonce = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES) # encrypt keys and key indexes (MAC appended, nonce prepended) msg = [] for i in range(0,len(keyidxs)): msg.append(keyidxs[i]) msg.append(keys[i]) msg = msgpack.packb(msg, use_bin_type=True) msg = nonce + pysodium.crypto_secretbox(msg,nonce,ss) # this is then put in a msgpack array with the appropriate max_age, poison, and public key(s) poison = msgpack.packb([['topics',[topic]],['usages',['key-encrypt']]], use_bin_type=True) msg = msgpack.packb([time()+self.__maxage,poison,eks,[random0,random1],msg], use_bin_type=True) # and signed with our signing key msg = self.__cryptokey.sign_spk(msg) # and finally put as last member of a msgpacked array chaining to ROT with self.__spk_chain_lock: tchain = self.__spk_chain.copy() if (len(tchain) == 0): poison = msgpack.packb([['topics',[topic]],['usages',['key-encrypt']],['pathlen',1]], use_bin_type=True) lastcert = msgpack.packb([time()+self.__maxage,poison,self.__cryptokey.get_spk()], use_bin_type=True) _,tempsk = pysodium.crypto_sign_seed_keypair(unhexlify(b'4c194f7de97c67626cc43fbdaf93dffbc4735352b37370072697d44254e1bc6c')) tchain.append(pysodium.crypto_sign(lastcert,tempsk)) provision = msgpack.packb([msgpack.packb([0,b'\x90',self.__cryptokey.get_spk()]),self.__cryptokey.sign_spk(lastcert)], use_bin_type=True) self._logger.warning("Current signing chain is empty. Use %s to provision access and then remove temporary root of trust from allowedlist.", provision.hex()) tchain.append(msg) msg = msgpack.packb(tchain, use_bin_type=True) except Exception as e: self._logger.warning("".join(format_exception_shim(e))) return None return msg
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 make_keypair(): public_key, private_key = pysodium.crypto_sign_keypair() print 'Do you wish to encrypt the private key under a password? (y/n)' answer = raw_input().lower() if answer not in ['y', 'n']: raise SystemExit('Invalid answer') if answer == 'y': salt = pysodium.randombytes(pysodium.crypto_pwhash_SALTBYTES) key = hash_password(prompt_for_new_password(), salt) nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) cyphertext = pysodium.crypto_secretbox(private_key, nonce, key) private_key = b'y' + salt + nonce + cyphertext else: private_key = b'n' + private_key return base64.b64encode(private_key), base64.b64encode(public_key)
def encrypt_aead(key, pt): nonce = pysodium.randombytes(12) ad = "" cipher = pysodium.crypto_aead_chacha20poly1305_encrypt(pt, ad, nonce, key) print "Chacha20 Poly1305: Plaintext Len: " + str( len(pt)) + " Cipher Len: " + str(len(cipher)) return nonce + cipher
def test_crypto_box_open(self): m = b"howdy" pk, sk = pysodium.crypto_box_keypair() n = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) c = pysodium.crypto_box(m, n, pk, sk) plaintext = pysodium.crypto_box_open(c, n, pk, sk) self.assertEqual(m, plaintext)
def _2user(): # 1st user exp1 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public1 = nacl.crypto_scalarmult_curve25519_base(exp1) #print("public1: \t%s\nexp1: \t%s" % (b85encode(public1), b85encode(exp1))) print() # 2nd user exp2 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public2 = nacl.crypto_scalarmult_curve25519_base(exp2) key = nacl.crypto_scalarmult_curve25519(exp2, public1) print("key: \t%s" % (b85encode(key))) #print("public2: \t%s\nkey: \t%s" % (b85encode(public2), b85encode(key))) print() # 1st user completing DH key = nacl.crypto_scalarmult_curve25519(exp1, public2) print("key: \t%s" % (b85encode(key)))
def create(self, data): # needs pubkey, id, challenge, sig(id) # returns output from ./response | fail pk = data[129:161] try: data = pysodium.crypto_sign_open(data, pk) except ValueError: print('invalid signature') return b'fail' id = data[1:33] chal = data[33:65] tdir = datadir + binascii.hexlify(id).decode() if os.path.exists(tdir): print(tdir, 'exists') return b'fail' # key already exists os.mkdir(tdir, 0o700) with open(tdir + '/pub', 'wb') as fd: os.fchmod(fd.fileno(), 0o600) fd.write(pk) key = pysodium.randombytes(32) with open(tdir + '/key', 'wb') as fd: os.fchmod(fd.fileno(), 0o600) fd.write(key) return respond(chal, id)
def __init_cryptokey(self, file): self._logger.warning("Initializing new CryptoKey file %s", file) pk,sk = pysodium.crypto_sign_keypair() self._logger.warning(" Public key: %s", pysodium.crypto_sign_sk_to_pk(sk).hex()) with open(file, "wb") as f: f.write(msgpack.packb([sk,pysodium.randombytes(pysodium.crypto_secretbox_KEYBYTES)], use_bin_type=True)) self._logger.warning(" CryptoKey Initialized. Provisioning required for successful operation.")
def _2user(): # 1st user exp1 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public1 = nacl.crypto_scalarmult_curve25519_base(exp1) # print "public1: \t%s\nexp1: \t%s" % (b85encode(public1), b85encode(exp1)) print # 2nd user exp2 = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public2 = nacl.crypto_scalarmult_curve25519_base(exp2) key = nacl.crypto_scalarmult_curve25519(exp2, public1) print "key: \t%s" % (b85encode(key)) # print "public2: \t%s\nkey: \t%s" % (b85encode(public2), b85encode(key)) print # 1st user completing DH key = nacl.crypto_scalarmult_curve25519(exp1, public2) print "key: \t%s" % (b85encode(key))
def savesecretekey(self, ext, key): fname = get_sk_filename(self.basedir, self.name, ext) k = pbp.getkey(nacl.crypto_secretbox_KEYBYTES, empty=True, text="Master" if ext == "mk" else "Subkey") nonce = nacl.randombytes(nacl.crypto_secretbox_NONCEBYTES) with open(fname, "w") as fd: fd.write(nonce) fd.write(nacl.crypto_secretbox(key, nonce, k))
def encrypt( cls, plaintext: bytes, key: bytes, footer=b'', ) -> bytes: if cls.nonce_for_unit_testing: nonce = cls.nonce_for_unit_testing cls.nonce_for_unit_testing = None else: nonce = pysodium.randombytes( pysodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES) nonce = pysodium.crypto_generichash( plaintext, k=nonce, outlen=pysodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES) ciphertext = pysodium.crypto_aead_xchacha20poly1305_ietf_encrypt( message=plaintext, ad=pre_auth_encode(cls.local_header, nonce, footer), nonce=nonce, key=key) token = cls.local_header + b64encode(nonce + ciphertext) if footer: token += b'.' + b64encode(footer) return token
def change(self, data): # needs id, challenge, sig(id) # returns output from ./response | fail try: pk = self.getpk(data) except: return b'fail' try: data = pysodium.crypto_sign_open(data, pk) except ValueError: print('invalid signature') return b'fail' id = data[1:33] chal = data[33:65] tdir = os.path.expanduser(datadir + binascii.hexlify(id).decode()) k = pysodium.randombytes(32) with open(tdir + '/new', 'wb') as fd: os.fchmod(fd.fileno(), 0o600) fd.write(k) try: rule = readf(tdir + "/rule") except: return b'fail' try: return respond(chal, id, secret=k) except ValueError: if verbose: print("respond fail") return b'fail'
def create(self, cb, pwd, user, host, char_classes, size=0): if set(char_classes) - {'u', 'l', 's', 'd'}: raise ValueError("error: rules can only contain ulsd.") try: size = int(size) except: raise ValueError("error: size has to be integer.") self.namesite = {'name': user, 'site': host} rules = sum(1 << i for i, c in enumerate(('u', 'l', 's', 'd')) if c in char_classes) # pack rule rule = struct.pack('>H', (rules << 7) | (size & 0x7f)) # encrypt rule sk = self.getkey() rk = pysodium.crypto_generichash(sk, self.getsalt()) nonce = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES) rule = nonce + pysodium.crypto_secretbox(rule, nonce, rk) b, c = sphinxlib.challenge(pwd) message = b''.join([ CREATE, self.getid(host, user), c, rule, pysodium.crypto_sign_sk_to_pk(sk) ]) self.doSphinx(message, b, pwd, cb)
def simpleTest(): key = "AAAAAAAAaaaaaaaaAAAAAAAAaaaaaaaa" input_ = "ItsNotATumor" print "Key:", key, "(", len(key), " bytes)" print "Input:", input_, " (", len(input_), " bytes)" nonce = pysodium.randombytes(12) ad = "1234" print "Nonce:", nonce, "(", len(nonce), " bytes)" print "Additional Data: ", ad, " (", len(ad), " bytes)" cipher = pysodium.crypto_aead_chacha20poly1305_encrypt( input_, ad, nonce, key) print "Cipher:", cipher, " (", len(cipher), " bytes)" print "Network Packet:", cipher, ad, nonce, " (", len(cipher) + len( ad) + len(nonce), " bytes)" try: plaintext = pysodium.crypto_aead_chacha20poly1305_decrypt( cipher, ad, nonce, key) except Exception: print "Failed to verify" else: print "Verified and Decrypted." print "Plaintext:", plaintext
def encrypt_blob(blob): # todo implement padding sk = get_sealkey() nonce = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES) ct = pysodium.crypto_secretbox(blob, nonce, sk) clearmem(sk) return nonce + ct
def auth_crypt_message(message: bytes, to_verkey: bytes, from_verkey: bytes, from_sigkey: bytes) -> bytes: """ Apply auth_crypt to a binary message. Args: message: The message to encrypt to_verkey: To recipient's verkey from_verkey: Sender verkey, included in combo box for verification from_sigkey: Sender sigkey, included to authenticated encrypt the message Returns: The encrypted message """ nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) target_pk = pysodium.crypto_sign_pk_to_box_pk(to_verkey) sk = pysodium.crypto_sign_sk_to_box_sk(from_sigkey) enc_body = pysodium.crypto_box(message, nonce, target_pk, sk) combo_box = OrderedDict([ ("msg", bytes_to_b64(enc_body)), ("sender", bytes_to_b58(from_verkey)), ("nonce", bytes_to_b64(nonce)), ]) combo_box_bin = msgpack.packb(combo_box, use_bin_type=True) enc_message = pysodium.crypto_box_seal(combo_box_bin, target_pk) return enc_message
def secret_key(self, passphrase=None, ed25519_seed=True): """ Creates base58 encoded private key representation :param passphrase: encryption phrase for the private key :param ed25519_seed: encode seed rather than full key for ed25519 curve (True by default) :return: the secret key associated with this key, if available """ if not self.secret_exponent: raise ValueError("Secret key not known.") if self.curve == b'ed' and ed25519_seed: key = pysodium.crypto_sign_sk_to_seed(self.secret_exponent) else: key = self.secret_exponent if passphrase: if not ed25519_seed: raise NotImplementedError salt = pysodium.randombytes(8) encryption_key = hashlib.pbkdf2_hmac( hash_name="sha512", password=scrub_input(passphrase), salt=salt, iterations=32768, dklen=32) encrypted_sk = pysodium.crypto_secretbox(msg=key, nonce=b'\000' * 24, k=encryption_key) key = salt + encrypted_sk # we have to combine salt and encrypted key in order to decrypt later prefix = self.curve + b'esk' else: prefix = self.curve + b'sk' return base58_encode(key, prefix).decode()
def auth_crypt_message(message: bytes, to_verkey: bytes, from_secret: bytes) -> bytes: """ Apply auth_crypt to a binary message. Args: message: The message to encrypt to_verkey: To recipient's verkey from_secret: The seed to use Returns: The encrypted message """ nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) target_pk = pysodium.crypto_sign_pk_to_box_pk(to_verkey) sender_pk, sender_sk = create_keypair(from_secret) sk = pysodium.crypto_sign_sk_to_box_sk(sender_sk) enc_body = pysodium.crypto_box(message, nonce, target_pk, sk) combo_box = OrderedDict( [ ("msg", bytes_to_b64(enc_body)), ("sender", bytes_to_b58(sender_pk)), ("nonce", bytes_to_b64(nonce)), ] ) combo_box_bin = msgpack.packb(combo_box, use_bin_type=True) enc_message = pysodium.crypto_box_seal(combo_box_bin, target_pk) return enc_message
def prepare_pack_recipient_keys(to_verkeys: Sequence[bytes], from_secret: bytes = None) -> (str, bytes): """ Assemble the recipients block of a packed message. Args: to_verkeys: Verkeys of recipients from_secret: Secret to use for signing keys Returns: A tuple of (json result, key) """ cek = pysodium.crypto_secretstream_xchacha20poly1305_keygen() recips = [] for target_vk in to_verkeys: target_pk = pysodium.crypto_sign_pk_to_box_pk(target_vk) if from_secret: sender_pk, sender_sk = create_keypair(from_secret) sender_vk = bytes_to_b58(sender_pk).encode("ascii") enc_sender = pysodium.crypto_box_seal(sender_vk, target_pk) sk = pysodium.crypto_sign_sk_to_box_sk(sender_sk) nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) enc_cek = pysodium.crypto_box(cek, nonce, target_pk, sk) else: enc_sender = None nonce = None enc_cek = pysodium.crypto_box_seal(cek, target_pk) recips.append( OrderedDict([ ("encrypted_key", bytes_to_b64(enc_cek, urlsafe=True)), ( "header", OrderedDict([ ("kid", bytes_to_b58(target_vk)), ( "sender", bytes_to_b64(enc_sender, urlsafe=True) if enc_sender else None, ), ( "iv", bytes_to_b64(nonce, urlsafe=True) if nonce else None, ), ]), ), ])) data = OrderedDict([ ("enc", "xchacha20poly1305_ietf"), ("typ", "JWM/1.0"), ("alg", "Authcrypt" if from_secret else "Anoncrypt"), ("recipients", recips), ]) return json.dumps(data), cek
def __generate_esk(self, topic, usage): # ephemeral keys are use once only, so always ok to overwrite # caller must hold self.__eklock prior to calling if not topic in self.__esk or not topic in self.__epk: self.__esk[topic] = {} self.__epk[topic] = {} self.__esk[topic][usage] = pysodium.randombytes(pysodium.crypto_scalarmult_curve25519_BYTES) self.__epk[topic][usage] = pysodium.crypto_scalarmult_curve25519_base(self.__esk[topic][usage])
def test_crypto_box_open_detached(self): pk, sk = pysodium.crypto_box_keypair() n = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) c, mac = pysodium.crypto_box_detached(b"howdy", n, pk, sk) r = pysodium.crypto_box_open_detached(c, mac, n, pk, sk) self.assertEqual(r, b"howdy") changed = b"\0"*len(c) self.assertRaises(ValueError, pysodium.crypto_box_open_detached,changed, mac, n, pk, sk)
def encrypt(plaintext, password): """Encrypts the given plaintext using libsodium secretbox, key is generated using scryptsalsa208sha256 with a random salt and nonce (we can not guarantee the incrementing anyway). Note that any str objects are assumed to be in utf-8.""" salt = pysodium.randombytes(pysodium.crypto_pwhash_scryptsalsa208sha256_SALTBYTES) memlimit = pysodium.crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE opslimit = pysodium.crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE if isinstance(password, str): password = password.encode("utf-8") key = pysodium.crypto_pwhash_scryptsalsa208sha256(pysodium.crypto_secretbox_KEYBYTES, password, salt, memlimit, opslimit) nonce = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES) if isinstance(plaintext, str): plaintext = plaintext.encode("utf-8") cyphertext = pysodium.crypto_secretbox(plaintext, nonce, key) data = (1).to_bytes(1, "little") data += memlimit.to_bytes(4, "little") data += opslimit.to_bytes(4, "little") data += salt data += nonce data += cyphertext return base64.b64encode(data)
def dh2_handler(peer): # provides a high level interface to receive a DH key exchange # request peer contains the public component generated by the peer # when initiating an DH exchange exp = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public = nacl.crypto_scalarmult_curve25519_base(exp) secret = nacl.crypto_scalarmult_curve25519(exp, b85decode(peer)) return (public, secret)
def dh2_handler(peer): # provides a high level interface to receive a DH key exchange # request peer contains the public component generated by the peer # when initiating an DH exchange exp = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public = nacl.crypto_scalarmult_curve25519_base(exp) secret = nacl.crypto_scalarmult_curve25519(exp, peer) return (public, secret)
def test_crypto_box_open_detached(self): pk, sk = pysodium.crypto_box_keypair() n = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) c, mac = pysodium.crypto_box_detached("howdy", n, pk, sk) r = pysodium.crypto_box_open_detached(c, mac, n, pk, sk) self.assertEqual(r, b"howdy") changed = "\0"*len(c) self.assertRaises(ValueError, pysodium.crypto_box_open_detached,changed, mac, n, pk, sk)
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: outfd.close()
def dh1_handler(): exp = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) public = nacl.crypto_scalarmult_curve25519_base(exp) (sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout).write(b"public component " + b85encode(public) + b'\n') (sys.stdout.buffer if hasattr(sys.stdout, 'buffer') else sys.stdout).write(b"secret exponent " + b85encode(exp) + b'\n') clearmem(exp)
def mpecdh1(self, keyring = []): self.key = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring] keyring.append(nacl.crypto_scalarmult_curve25519_base(self.key)) if len(keyring) == int(self.peers): # we are last, remove our own secret self.secret = keyring[0] keyring = keyring[1:] return keyring
def test_AsymCrypto_With_Seeded_Keypair(self): msg = "correct horse battery staple" nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) pk, sk = pysodium.crypto_box_seed_keypair("howdy") c = pysodium.crypto_box_easy(msg, nonce, pk, sk) m = pysodium.crypto_box_open_easy(c, nonce, pk, sk) self.assertEqual(msg, m)
def test_crypto_box_open_afternm(self): m = b"howdy" pk, sk = pysodium.crypto_box_keypair() k = pysodium.crypto_box_beforenm(pk, sk) n = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) c = pysodium.crypto_box_afternm(m, n, k) self.assertEqual(c, c) plaintext = pysodium.crypto_box_open_afternm(c, n, k) self.assertEqual(m, plaintext)
def test_AsymCrypto_With_Seeded_Keypair(self): msg = b"correct horse battery staple" nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) pk, sk = pysodium.crypto_box_seed_keypair("howdy") c = pysodium.crypto_box(msg, nonce, pk, sk) m = pysodium.crypto_box_open(c, nonce, pk, sk) self.assertEqual(msg, m)
def savesecretekey(self, ext, key): fname = get_sk_filename(self.basedir, self.name, ext) k = getkey(nacl.crypto_secretbox_KEYBYTES, empty=True, text='Master' if ext == 'mk' else 'Subkey') nonce = nacl.randombytes(nacl.crypto_secretbox_NONCEBYTES) with open(fname,'wb') as fd: fd.write(nonce) fd.write(nacl.crypto_secretbox(key, nonce, k))
def test_AsymCrypto_With_Seeded_Keypair(self): msg = b"correct horse battery staple" nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) pk, sk = pysodium.crypto_box_seed_keypair(b"\x00" * pysodium.crypto_box_SEEDBYTES) c = pysodium.crypto_box(msg, nonce, pk, sk) m = pysodium.crypto_box_open(c, nonce, pk, sk) self.assertEqual(msg, m)
def encrypt_message(identity, payload): version = 1 nonce = pysodium.randombytes(pysodium.crypto_secretbox_NONCEBYTES) pubkeyhash, encryption_key = expand_handle(identity.handle) if not validate_pubkey(identity.pk, pubkeyhash): raise PubkeyError() decrypted = generate_innerbox(identity.pk, identity.sk, payload, version) encrypted = pysodium.crypto_secretbox(decrypted, nonce, encryption_key) return outer_pack.pack(version, nonce, encrypted)
def do_create_channel(self, line): """ Create a random channel name (hex number) and set the new channel in the configuration. """ channel = base64.b16encode(pysodium.randombytes(16)).lower() self.config[b'channel'] = channel save_data(CONFIG, self.config) print('[+] Channel ID {0} added to configuration.'.format(channel))
def authenticate(): """ This does two things, either validate a pre-existing session token or create a new one from a signed authentication token. """ client_ip = request.environ['REMOTE_ADDR'] repository = request.headers['repository'] if repository not in config['repositories']: return fail(no_such_repo_msg) # == repository_path = config['repositories'][repository]['path'] conn = auth_db_connect(cpjoin(repository_path, 'auth_transient.db')); gc_tokens(conn) gc_tokens(conn) # Allow resume of an existing session if 'session_token' in request.headers: session_token = request.headers['session_token'] conn.execute("delete from session_tokens where expires < ?", (time.time(),)); conn.commit() res = conn.execute("select * from session_tokens where token = ? and ip = ?", (session_token, client_ip)).fetchall() if res != []: return success({'session_token' : session_token}) else: return fail(user_auth_fail_msg) # Create a new session else: user = request.headers['user'] auth_token = request.headers['auth_token'] signiture = request.headers['signature'] try: public_key = config['users'][user]['public_key'] # signature pysodium.crypto_sign_verify_detached(base64.b64decode(signiture), auth_token, base64.b64decode(public_key)) # check token was previously issued by this system and is still valid res = conn.execute("select * from tokens where token = ? and ip = ? ", (auth_token, client_ip)).fetchall() # Validate token matches one we sent if res == [] or len(res) > 1: return fail(user_auth_fail_msg) # Does the user have permission to use this repository? if repository not in config['users'][user]['uses_repositories']: return fail(user_auth_fail_msg) # Everything OK conn.execute("delete from tokens where token = ?", (auth_token,)); conn.commit() # generate a session token and send it to the client session_token = base64.b64encode(pysodium.randombytes(35)) conn.execute("insert into session_tokens (token, expires, ip, username) values (?,?,?, ?)", (session_token, time.time() + extend_session_duration, client_ip, user)) conn.commit() return success({'session_token' : session_token}) except Exception: # pylint: disable=broad-except return fail(user_auth_fail_msg)
def encrypt(msg, pwd=None, k=None): # encrypts a message symmetrically using crypto_secretbox # k specifies an encryption key, which if not supplied, is derived from # pwd which is queried from the user, if also not specified. # returns a (nonce, ciphertext) tuple nonce = nacl.randombytes(nacl.crypto_secretbox_NONCEBYTES) cleark = (k is None) if not k: k = getkey(nacl.crypto_secretbox_KEYBYTES, pwd=pwd) ciphertext = nacl.crypto_secretbox(msg, nonce, k) if cleark: clearmem(k) return (nonce, ciphertext)
def udpServe(key=b'this is my key value!',addr=('localhost',8080)) : s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) nonce = pysodium.randombytes(8) ciphertext = pysodium.crypto_aead_chacha20poly1305_encrypt(b'this is my key value!',None,nonce,key) plaintext = pysodium.crypto_aead_chacha20poly1305_decrypt(ciphertext,None,nonce,key) print(plaintext) print(ciphertext) print(reprlib.repr(ciphertext)) print(nonce) print(ciphertext+nonce) s.sendto(ciphertext+nonce,addr) s.close()
def send(self, msg): """ as per https://github.com/trevp/axolotl/wiki/newversion (Nov 19, 2013 · 41 revisions) Sending messages ----------------- Local variables: MK : message key if DHRs == <none>: DHRs = generateECDH() MK = HASH(CKs || "0") msg = Enc(HKs, Ns || PNs || DHRs) || Enc(MK, plaintext) Ns = Ns + 1 CKs = HASH(CKs || "1") return msg """ if self.DHRs == None: self.DHRs = Key().new() self.PNs = self.Ns # wtf: not in spec, but seems needed self.Ns = 0 # wtf: not in spec, but seems needed mk = nacl.crypto_generichash(self.CKs, 'MK', nacl.crypto_secretbox_KEYBYTES) hnonce = nacl.randombytes(nacl.crypto_secretbox_NONCEBYTES) mnonce = nacl.randombytes(nacl.crypto_secretbox_NONCEBYTES) msg = ''.join((hnonce, mnonce, nacl.crypto_secretbox( ''.join((struct.pack('>I',self.Ns), struct.pack('>I',self.PNs), self.DHRs.pk)), hnonce, self.HKs), nacl.crypto_secretbox(msg, mnonce, mk))) clearmem(mk) mk = None self.Ns += 1 self.CKs = nacl.crypto_generichash(self.CKs, "CK", nacl.crypto_secretbox_KEYBYTES) return msg
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 encrypt(ssk, spk, rpk, msg): """ Encrypt a message using the provided information. """ ssk = base64.b64decode(ssk) rpk = base64.b64decode(rpk) nonce = pysodium.randombytes(pysodium.crypto_box_NONCEBYTES) enc = pysodium.crypto_box_easy(msg, nonce, rpk, ssk) nonce = base64.b64encode(nonce) enc = base64.b64encode(enc) # Return sender's public_key, nonce, and the encrypted message return b':'.join([spk, nonce, enc])
def mpecdh(self, keyring=[]): if self.secret: return self.secret if not self.key: self.key = nacl.randombytes(nacl.crypto_scalarmult_curve25519_BYTES) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring] keyring.append(nacl.crypto_scalarmult_curve25519_base(self.key)) if len(keyring) == self.peers: # we are last, remove our own secret self.secret = keyring[0] keyring = keyring[1:] else: self.secret = nacl.crypto_scalarmult_curve25519(self.key, keyring[0]) keyring = [nacl.crypto_scalarmult_curve25519(self.key, public) for public in keyring[1:]] clearmem(self.key) self.key = None self.next.mpecdh(keyring)
def generate_identity(): pk, sk, handle = None, None, None while True: pk, sk = pysodium.crypto_sign_keypair() if hash_pubkey(pk): break while True: enc = pysodium.randombytes(16) try: handle = hash_pubkey(pk) + hx(enc) expand_handle(handle) except: continue break return Identity(pk=pk, sk=sk, \ enc=enc, handle=handle)
def begin_auth(): """ Request authentication token to sign """ repository = request.headers['repository'] if repository not in config['repositories']: return fail(no_such_repo_msg) # == repository_path = config['repositories'][repository]['path'] conn = auth_db_connect(cpjoin(repository_path, 'auth_transient.db')); gc_tokens(conn) # Issue a new token auth_token = base64.b64encode(pysodium.randombytes(35)).decode('utf-8') conn.execute("insert into tokens (expires, token, ip) values (?,?,?)", (time.time() + 30, auth_token, request.environ['REMOTE_ADDR'])) conn.commit() return success({'auth_token' : auth_token})
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=b''.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,'wb') as fd: fd.write(nonce) fd.write(nacl.crypto_box(ctx, nonce, self.me_id.cp, self.me_id.cs))
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 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 fd != sys.stdin: fd.close() if outfd != sys.stdout: outfd.close()