def test_blake2b(): """ Used generic hash in LibSodium which is Blake2b Also hash std lib """ # create keypair without seed verkey, sigkey = pysodium.crypto_sign_keypair() assert len(verkey) == 32 == pysodium.crypto_sign_PUBLICKEYBYTES assert len(sigkey) == 64 == pysodium.crypto_sign_SECRETKEYBYTES verkey = b'Z\x80s\x81\xd3\xf4\xaa\x94\x80\x86\x9bH\x8ay\xc2\xf9\x89k_\x946\xf1_`\x8c\xa9\xd8\xd2b\xe4\x00\x08' # digest of publickey digest = pysodium.crypto_generichash(verkey) assert len(digest) == 32 == pysodium.crypto_generichash_BYTES assert digest == ( b'\xf9\xa4\xe3\x87\x05\xc9\xf8\x9b\x18pI\xf3\xb5G@\xdf\x03\xbe\xcc\x9b)\xe7u\xeaH\x19\x1d\xe6*4Yp' ) digestbig = pysodium.crypto_generichash(verkey, outlen=64) assert len(digestbig) == 64 # assert digestbig[:32] == digest # not true for blake2b dig = hashlib.blake2b(verkey, digest_size=32).digest() assert dig == ( b'\xf9\xa4\xe3\x87\x05\xc9\xf8\x9b\x18pI\xf3\xb5G@\xdf\x03\xbe\xcc\x9b)\xe7u\xeaH\x19\x1d\xe6*4Yp' ) assert len(dig) == 32 assert dig == digest digbig = hashlib.blake2b(verkey).digest() assert len(digbig) == 64 assert digbig == digestbig """
def tripledh(self): """Triple DH performs cross DH between two peers having two keys each: - an identity key (Ai,Bi), and - an ephemeral key (Ae, Be). the cross DH is then performed on these pairs: (Ai,Be)+(Bi,Ae)+(Ae,Be) The order of the parameters to these operations depends on the order in which the peers are acting. """ if self.isalice: p1 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p2 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1+p2+p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res p1 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p2 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1+p2+p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res
def check_password(self, user_id: str, password: str): public_key_hash = bytes.fromhex(user_id.split(":", 1)[0][1:]) #signature_type = password.split(":")[0] signature = bytes.fromhex(password.split(":")[1]) public_key = bytes.fromhex(password.split(":")[2]) public_key_digest = pysodium.crypto_generichash(public_key) if public_key_hash.hex() == public_key_digest.hex(): try: message_digest = pysodium.crypto_generichash( u"login:{}".format(int(time.time()/(5*60))).encode()) pysodium.crypto_sign_verify_detached( signature, message_digest, public_key) if not (yield self.account_handler.check_user_exists(user_id)): self.log.info( "First user login, registering: user=%r", user_id.lower()) yield self.account_handler.register(localpart=public_key_digest.hex()) defer.returnValue(True) except Exception as exception: self.log.info( "Got exception while verifying signature: "+str(exception)) defer.returnValue(False) else: self.log.info( "pubkey hash did not match pubkey") defer.returnValue(False)
def __init__(self, tree, left = None, right = None): self.tree = tree self.left = left self.right = right if isinstance(left,MerkleHashTreeNode): self.hash = nacl.crypto_generichash(left.hash+(right.hash if right else ('\0' * nacl.crypto_generichash_BYTES))) else: self.hash = nacl.crypto_generichash((left or ('\0' * nacl.crypto_generichash_BYTES))+(right or ('\0' * nacl.crypto_generichash_BYTES)))
def get_signkey(id, rwd): mk = get_masterkey() seed = pysodium.crypto_generichash(SIGN_CTX, mk) clearmem(mk) # rehash with rwd so the user always contributes his pwd and the sphinx server it's seed seed = pysodium.crypto_generichash(seed, id) if rwd_keys: seed = pysodium.crypto_generichash(seed, rwd) pk, sk = pysodium.crypto_sign_seed_keypair(seed) clearmem(seed) return sk, pk
def __init__(self, tree, left=None, right=None): self.tree = tree self.left = left self.right = right if isinstance(left, MerkleHashTreeNode): self.hash = nacl.crypto_generichash(left.hash + ( right.hash if right else ('\0' * nacl.crypto_generichash_BYTES))) else: self.hash = nacl.crypto_generichash( (left or ('\0' * nacl.crypto_generichash_BYTES)) + (right or ('\0' * nacl.crypto_generichash_BYTES)))
def stage_skipped_keys(self, HK, Nr, Np, CK): """ stage_skipped_header_and_message_keys() : Given a current header key, a current message number, a future message number, and a chain key, calculates and stores all skipped-over message keys (if any) in a staging area where they can later be committed, along with their associated header key. Returns the chain key and message key corresponding to the future message number. """ for _ in xrange(Np - Nr): mk = nacl.crypto_generichash(CK, 'MK', nacl.crypto_secretbox_KEYBYTES) self.staged_HK_MK[mk] = HK CK = nacl.crypto_generichash(CK, 'CK', nacl.crypto_secretbox_KEYBYTES) mk = nacl.crypto_generichash(CK, 'MK', nacl.crypto_secretbox_KEYBYTES) CK = nacl.crypto_generichash(CK, 'CK', nacl.crypto_secretbox_KEYBYTES) return CK, mk
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 blind_index_slow(plaintext: bytes, key: bytes, bit_length: int = 256, **options): ops_limit = max( options.get('opslimit', CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE), CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE) mem_limit = max( options.get('memlimit', CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE), CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE) pw_hash_length = bit_length >> 3 if pw_hash_length < 16: pw_hash_length = 16 if pw_hash_length > 4294967295: raise Exception('Output length is far too big') hashed = pysodium.crypto_pwhash( outlen=pw_hash_length, passwd=plaintext, salt=pysodium.crypto_generichash(key, outlen=16), opslimit=ops_limit, memlimit=mem_limit, alg=pysodium.crypto_pwhash_ALG_ARGON2ID13, ) result = and_mask(hashed, bit_length) return result
def data_received(self, data): if verbose: print('Data received: ', data) try: data = pysodium.crypto_sign_open(data, self.handler.getserverkey()) except ValueError: raise ValueError('invalid signature.\nabort') if data!=b'ok' and (data[:-42] == b'fail' or len(data)!=sphinxlib.DECAF_255_SER_BYTES+42): raise ValueError('fail') if not self.b: self.cb() return rwd=sphinxlib.finish(self.pwd, self.b, data[:sphinxlib.DECAF_255_SER_BYTES]) if self.handler.namesite is not None: if self.handler.namesite['name'].encode() not in self.handler.list(self.handler.namesite['site']): self.handler.cacheuser(self.handler.namesite) rule = data[sphinxlib.DECAF_255_SER_BYTES:] if len(rule)!=42: raise ValueError('fail') rk = pysodium.crypto_generichash(self.handler.getkey(),self.handler.getsalt()) rule = pysodium.crypto_secretbox_open(rule[24:], rule[:24],rk) rule = struct.unpack(">H",rule)[0] size = (rule & 0x7f) rule = {c for i,c in enumerate(('u','l','s','d')) if (rule >> 7) & (1 << i)} self.cb(bin2pass.derive(rwd,rule,size).decode())
def delete(self, user, host): message = b''.join([DELETE,self.getid(host, user)]) salt = self.getsalt() hostid = pysodium.crypto_generichash(host, salt, 32) def callback(): self.deluser(hostid,user) self.doSphinx(message, host, None, None, callback)
def sign(self, message, generic=False): """ Sign a raw sequence of bytes :param message: sequence of bytes, raw format or hexadecimal notation :param generic: do not specify elliptic curve if set to True :return: signature in base58 encoding """ message = scrub_input(message) if not self.is_secret: raise ValueError("Cannot sign without a secret key.") # Ed25519 if self.curve == b"ed": digest = pysodium.crypto_generichash(message) signature = pysodium.crypto_sign_detached(digest, self._secret_key) # Secp256k1 elif self.curve == b"sp": pk = secp256k1.PrivateKey(self._secret_key) signature = pk.ecdsa_serialize_compact( pk.ecdsa_sign(message, digest=blake2b_32)) # P256 elif self.curve == b"p2": r, s = sign(msg=message, d=bytes_to_int(self._secret_key), hashfunc=blake2b_32) signature = int_to_bytes(r) + int_to_bytes(s) else: assert False if generic: prefix = b'sig' else: prefix = self.curve + b'sig' return base58_encode(signature, prefix).decode()
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 test_crypto_sign_seed_keypair(self): seed = pysodium.crypto_generichash( b'howdy', outlen=pysodium.crypto_sign_SEEDBYTES) pk, sk = pysodium.crypto_sign_seed_keypair(seed) pk2, sk2 = pysodium.crypto_sign_seed_keypair(seed) self.assertEqual(pk, pk2) self.assertEqual(sk, sk2)
def keyid(self): res = nacl.crypto_generichash(''.join((self.created.isoformat(), self.valid.isoformat(), self.mp, self.sp, self.cp )))[:16] return ' '.join(split_by_n(binascii.b2a_hex(res).decode("ascii"), 4))
def test_crypto_generichash(self): r=pysodium.crypto_generichash(b'howdy') pysodium.crypto_generichash(b'howdy', outlen=4) r6=pysodium.crypto_generichash(b'howdy', outlen=6) pysodium.crypto_generichash(b'howdy', outlen=8) state = pysodium.crypto_generichash_init() pysodium.crypto_generichash_update(state, b'howdy') r1=pysodium.crypto_generichash_final(state) state = pysodium.crypto_generichash_init(outlen=6) pysodium.crypto_generichash_update(state, b'howdy') r61=pysodium.crypto_generichash_final(state, outlen=6) self.assertEqual(r, r1) self.assertEqual(r6, r61) self.assertNotEqual(pysodium.crypto_generichash( 'salt0'), pysodium.crypto_generichash( 'salt1')) self.assertNotEqual(pysodium.crypto_generichash(b'salt0'), pysodium.crypto_generichash(b'salt1'))
def test_crypto_generichash(self): pysodium.crypto_generichash(b'howdy') pysodium.crypto_generichash(b'howdy', outlen=4) pysodium.crypto_generichash(b'howdy', outlen=6) pysodium.crypto_generichash(b'howdy', outlen=8) state = pysodium.crypto_generichash_init() pysodium.crypto_generichash_update(state, b'howdy') pysodium.crypto_generichash_final(state) state = pysodium.crypto_generichash_init(outlen=6) pysodium.crypto_generichash_update(state, b'howdy') pysodium.crypto_generichash_final(state, outlen=6)
def doSphinx(self, message, host, b, pwd, cb): self.hostid=pysodium.crypto_generichash(host, self.getsalt(), 32) signed=pysodium.crypto_sign(message,self.getkey()) loop = asyncio.get_event_loop() coro = loop.create_connection(lambda: SphinxClientProtocol(signed, loop, b, pwd, self, cb), address, port) try: loop.run_until_complete(coro) loop.run_forever() except: raise
def keyid(self): joined_bytestring = b"".join(( self.created.isoformat().encode('utf-8'), self.valid.isoformat().encode('utf-8'), self.mp, self.sp, self.cp )) res = nacl.crypto_generichash(joined_bytestring)[:16] return ' '.join(split_by_n(binascii.b2a_hex(res).decode("ascii"), 4))
def decodeMyCertificate(sock, endpoint_address): f = open("/home/netsec41/node.pub", 'r') myCert = base64.b64decode(f.readline()) self_cert = pysodium.crypto_generichash(myCert, outlen=64) msg = struct.pack('>I', len(self_cert)) + self_cert sock.sendto(msg, endpoint_address) data, addr = sock.recvfrom(1500) myCertStatus = data f.close() return (myCert, myCertStatus)
def is_valid_event(self, h, ev): try: crypto_sign_verify_detached(ev.s, dumps(ev[:-1]), ev.c) except ValueError: return False return ( crypto_generichash(dumps(ev)) == h and (ev.p == () or (len(ev.p) == 2 and ev.p[0] in self.hg and ev.p[1] in self.hg and self.hg[ev.p[0]].c == ev.c and self.hg[ev.p[1]].c != ev.c)))
def tripledh(self): """Triple DH performs cross DH between two peers having two keys each: - an identity key (Ai,Bi), and - an ephemeral key (Ae, Be). the cross DH is then performed on these pairs: (Ai,Be)+(Bi,Ae)+(Ae,Be) The order of the parameters to these operations depends on the order in which the peers are acting. """ if self.isalice: p1 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p2 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1 + p2 + p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res p1 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['identitykey']) p2 = nacl.crypto_scalarmult_curve25519(self.me.identitykey.sk, self.peer['ephemeralkey']) p3 = nacl.crypto_scalarmult_curve25519(self.ephemeralkey.sk, self.peer['ephemeralkey']) sec = p1 + p2 + p3 clearmem(p1) clearmem(p2) clearmem(p3) res = nacl.crypto_generichash(sec, '', nacl.crypto_secretbox_KEYBYTES) clearmem(sec) return res
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 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 new_event(self, d, p): """Create a new event (and also return it's hash).""" assert p == () or len(p) == 2 # 2 parents assert p == () or self.hg[p[0]].c == self.pk # first exists and is self-parent assert p == () or self.hg[p[1]].c != self.pk # second exists and not self-parent # TODO: fail if an ancestor of p[1] from creator self.pk is not an # ancestor of p[0] t = time() s = crypto_sign_detached(dumps((d, p, t, self.pk)), self.sk) ev = Event(d, p, t, self.pk, s) return crypto_generichash(dumps(ev)), ev
def cacheuser(self, namesite): site=namesite['site'] user=namesite['name'] salt = self.getsalt() hostid = pysodium.crypto_generichash(site, salt, 32) userfile = os.path.expanduser(self.datadir+binascii.hexlify(hostid).decode()) try: if not os.path.exists(userfile): with open(userfile, 'wb') as fd: fd.write(user.encode()) else: with open(userfile, 'ab') as fd: fd.write(b"\n"+user.encode()) except: pass
def blind_index_fast(plaintext: bytes, key: bytes, bit_length: int = 256): if not bit_length or bit_length > 512: raise Exception('invalid bit length') if bit_length > 256: hash_length = bit_length >> 3 else: hash_length = 32 if type(plaintext) != bytes: plaintext = plaintext.encode() hashed = pysodium.crypto_generichash( m=plaintext, k=key, outlen=hash_length, ) result = and_mask(hashed, bit_length) return result
def updateCertificateStatus(STS): global myCert, sock, endpoint_address while True: myCertStatus = STS.getCertificateStatus() status_tuple, _ = sts_utility.certificateStatusDict(myCertStatus) # print(status_tuple) currTime = int(time.time()) validity = status_tuple['F'] + status_tuple['U'] self_cert = pysodium.crypto_generichash(myCert, outlen=64) msg = struct.pack('>I', len(self_cert)) + self_cert if validity < currTime: sock.sendto(msg, endpoint_address) time.sleep(5) elif (validity - currTime) >= 0: time.sleep(validity - currTime) sock.sendto(msg, endpoint_address)
def verify(self, signature: Union[str, bytes], message: Union[str, bytes]) -> None: """Verify signature, raise exception if it is not valid. :param message: sequance of bytes, raw format or hexadecimal notation :param signature: a signature in base58 encoding :raises: ValueError if signature is not valid """ encoded_signature = scrub_input(signature) encoded_message = scrub_input(message) if not self.public_point: raise ValueError("Cannot verify without a public key") if encoded_signature[:3] != b'sig': # not generic if self.curve != encoded_signature[:2]: # "sp", "p2" "ed" raise ValueError("Signature and public key curves mismatch.") decoded_signature = base58_decode(encoded_signature) # Ed25519 if self.curve == b"ed": digest = pysodium.crypto_generichash(encoded_message) try: pysodium.crypto_sign_verify_detached(decoded_signature, digest, self.public_point) except ValueError as exc: raise ValueError('Signature is invalid.') from exc # Secp256k1 elif self.curve == b"sp": pk = secp256k1.PublicKey(self.public_point, raw=True) sig = pk.ecdsa_deserialize_compact(decoded_signature) if not pk.ecdsa_verify(encoded_message, sig, digest=blake2b_32): raise ValueError('Signature is invalid.') # P256 elif self.curve == b"p2": pk = fastecdsa.encoding.sec1.SEC1Encoder.decode_public_key( self.public_point, curve=fastecdsa.curve.P256) r, s = bytes_to_int(decoded_signature[:32]), bytes_to_int( decoded_signature[32:]) if not fastecdsa.ecdsa.verify( sig=(r, s), msg=encoded_message, Q=pk, hashfunc=blake2b_32): raise ValueError('Signature is invalid.') else: raise Exception( f'Unknown elliptic curve {self.curve}') # type: ignore
def test_destructure_decrypt_decode_verbose(self): """ Strictly verify the content and behaviour of the serializer, and how the encryption functions are used. """ encrypted = self.obj.dumps(SESSION).encode('utf-8') dec = urlsafe_b64decode(encrypted) key = crypto_generichash(app.secret_key, outlen=crypto_secretbox_KEYBYTES) n = dec[:crypto_secretbox_NONCEBYTES] c = dec[crypto_secretbox_NONCEBYTES:] m = crypto_secretbox_open(c, n, key) session = self.obj.serializer.loads(m) assert session[self.obj.timestamp_key] del session[self.obj.timestamp_key] assert SESSION == session
def test_crypto_generichash(self): r=pysodium.crypto_generichash(b'howdy') pysodium.crypto_generichash(b'howdy', outlen=4) r6=pysodium.crypto_generichash(b'howdy', outlen=6) pysodium.crypto_generichash(b'howdy', outlen=8) state = pysodium.crypto_generichash_init() pysodium.crypto_generichash_update(state, b'howdy') r1=pysodium.crypto_generichash_final(state) state = pysodium.crypto_generichash_init(outlen=6) pysodium.crypto_generichash_update(state, b'howdy') r61=pysodium.crypto_generichash_final(state, outlen=6) self.assertEqual(r, r1) self.assertEqual(r6, r61)
def doSphinx(s, op, pwd, user, host): id = getid(host, user) r, alpha = sphinxlib.challenge(pwd) msg = b''.join([op, id, alpha]) s.send(msg) if op != GET: # == CHANGE, UNDO, COMMIT # auth: do sphinx with current seed, use it to sign the nonce auth(s, id, pwd, r) resp = s.recv(32 + RULE_SIZE) # beta + sealed rules if resp == b'\x00\x04fail' or len(resp) != 32 + RULE_SIZE: raise ValueError("error: sphinx protocol failure.") beta = resp[:32] rules = resp[32:] rwd = sphinxlib.finish(pwd, r, beta, id) try: classes, size = unpack_rule(rules) except ValueError: return if op != GET: # == CHANGE, UNDO, COMMIT # in case of undo/commit we also need to rewrite the rules and pub auth signing key blob if op in {UNDO, COMMIT}: sk, pk = get_signkey(id, rwd) clearmem(sk) rule = encrypt_blob(pack_rule(classes, size)) # send over new signed(pubkey, rule) msg = b''.join([pk, rule]) msg = sign_blob(msg, id, rwd) s.send(msg) if s.recv(2) != b'ok': print( "ohoh, something is corrupt, and this is a bad, very bad error message in so many ways" ) return ret = bin2pass.derive(pysodium.crypto_generichash(PASS_CTX, rwd), classes, size).decode() clearmem(rwd) return ret
def encrypt(plaintext: bytes, key: bytes, footer=b'', nonce_testing=None) -> bytes: if nonce_testing is not None: nonce = nonce_testing else: nonce = randombytes(crypto_aead_xchacha20poly1305_ietf_NPUBBYTES) nonce = crypto_generichash( plaintext, k=nonce, outlen=crypto_aead_xchacha20poly1305_ietf_NPUBBYTES) ciphertext = crypto_aead_xchacha20poly1305_ietf_encrypt( message=plaintext, ad=pre_auth_encode(consts.local_header, nonce, footer), nonce=nonce, key=key) token = consts.local_header + b64encode(nonce + ciphertext) if footer: token += b'.' + b64encode(footer) return token
def verify(self, signature, message): """ Verify signature, raise exception if it is not valid :param message: sequance of bytes, raw format or hexadecimal notation :param signature: a signature in base58 encoding """ signature = scrub_input(signature) message = scrub_input(message) if not self.public_point: raise ValueError("Cannot verify without a public key") if signature[:3] != b'sig': # not generic if self.curve != signature[:2]: # "sp", "p2" "ed" raise ValueError("Signature and public key curves mismatch.") signature = base58_decode(signature) # Ed25519 if self.curve == b"ed": digest = pysodium.crypto_generichash(message) try: pysodium.crypto_sign_verify_detached(signature, digest, self.public_point) except ValueError: raise ValueError('Signature is invalid.') # Secp256k1 elif self.curve == b"sp": pk = secp256k1.PublicKey(self.public_point, raw=True) sig = pk.ecdsa_deserialize_compact(signature) if not pk.ecdsa_verify(message, sig, digest=blake2b_32): raise ValueError('Signature is invalid.') # P256 elif self.curve == b"p2": pk = SEC1Encoder.decode_public_key(self.public_point, curve=P256) r, s = bytes_to_int(signature[:32]), bytes_to_int(signature[32:]) if not verify(sig=(r, s), msg=message, Q=pk, hashfunc=blake2b_32): raise ValueError('Signature is invalid.') else: assert False
def get_key_value_generators(self, topic, node=None): if (isinstance(topic,(str))): topic = bytes(topic, 'utf-8') elif isinstance(topic, (bytes,bytearray)): self._logger.debug('topic provided as bytes (should be string)') # but we need it as bytes for pysodium if not (node is None) and isinstance(node,(str)): node = bytes(node, 'utf-8') # node can be provided as bytes or string in proper usage # pysodium silently computes the hash of an empty string if input is not bytes, so check for # and catch that. if (not isinstance(topic, (bytes,bytearray))): raise KafkaCryptoRatchetError("Topic is not bytes!") hash = pysodium.crypto_hash_sha256(topic) # generate per topic key key,_ = self.generate(salt=hash[0:self.SALTSIZE],ctx=hash[self.SALTSIZE:],keysize=self.SECRETSIZE,noncesize=0) ki = self.__keyidx if node is not None: ki = ki.to_bytes(16, byteorder='big') ki = pysodium.crypto_generichash(node + ki) kg, vg = KeyGenerator.get_key_value_generators(key) return (ki, key, kg, vg)
def init(self, peer): """ as per https://github.com/trevp/axolotl/wiki/newversion (Nov 19, 2013 · 41 revisions) Key Agreement -------------- - Parties exchange identity keys (A,B) and handshake keys (Ah,Ai) and (Bh,Bi) - Parties assign themselves "Alice" or "Bob" roles by comparing public keys - Parties perform triple-DH with (A,B,Ah,Bh) and derive initial keys: Alice: KDF from triple-DH: RK, HKs, HKr, NHKs, NHKr, CKs, CKr DHIs, DHIr = A, B DHRs, DHRr = <none>, Bi Ns, Nr = 0, 0 PNs = 0 bobs_first_message = False Bob: KDF from triple-DH: RK, HKr, HKs, NHKr, NHKs, CKr, CKs DHIs, DHIr = B, A DHRs, DHRr = Bi, <none> Ns, Nr = 0, 0 PNs = 0 bobs_first_message = True """ self.peer = peer self.DHIr = peer['identitykey'] self.isalice = self.me.identitykey.pk <= peer['identitykey'] mk = self.tripledh() self.RK = nacl.crypto_generichash(mk, "RK",KEY_SIZE) if self.isalice: self.DHRr = peer['DHRs'] self.DHRs = None self.HKs = nacl.crypto_generichash(mk, "HKs", KEY_SIZE) self.HKr = nacl.crypto_generichash(mk, "HKr", KEY_SIZE) self.NHKs = nacl.crypto_generichash(mk, "NHKs", KEY_SIZE) self.NHKr = nacl.crypto_generichash(mk, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(mk, "CKs", KEY_SIZE) self.CKr = nacl.crypto_generichash(mk, "CKr", KEY_SIZE) self.bobs1stmsg = False else: self.HKs = nacl.crypto_generichash(mk, "HKr", KEY_SIZE) self.HKr = nacl.crypto_generichash(mk, "HKs", KEY_SIZE) self.NHKs = nacl.crypto_generichash(mk, "NHKr", KEY_SIZE) self.NHKr = nacl.crypto_generichash(mk, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(mk, "CKr", KEY_SIZE) self.CKr = nacl.crypto_generichash(mk, "CKs", KEY_SIZE) self.bobs1stmsg = True clearmem(mk) mk = None
def main(): # main command line handler for pbp 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('--hash', '-H', dest='action', action='store_const', const='h',help="hashes") 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', '-I', dest='action', action='store_const', const='i',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( '-D1', dest='action', action='store_const', const='d1',help="initiates an ECDH key exchange") group.add_argument( '-D2', dest='action', action='store_const', const='d2',help="responds to an ECDH key request") group.add_argument( '-D3', dest='action', action='store_const', const='d3',help="finalizes an ECDH key exchange") group.add_argument('--dh-start', '-Ds', dest='action', action='store_const', const='ds',help="initiates an ECDH key exchange") group.add_argument('--dh-end', '-De', dest='action', action='store_const', const='de',help="finalizes an ECDH key exchange") group.add_argument('--rand-stream', '-R', dest='action', action='store_const', const='R',help="generate arbitrary random stream") if PITCHFORK: parser.add_argument('--pitchfork', '-P', dest='PITCHFORK', action='store_const', const='P',help="arms PITCHFORK", default=False) parser.add_argument('--signature', '-z', help="sets the pitchfork sig to verify") 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('--max-recipients', help="set the number of recipients to check when decrypting", default=20) parser.add_argument('--sender', help="set the key of the sender") 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('--key', '-k', help="some password or secret") parser.add_argument('--dh-param', '-DP',help="public parameter for ECDH key exchange") parser.add_argument('--dh-exp', '-DE',help="secret exp for final step of a ECDH key exchange") parser.add_argument('--size', '-Rs',help="size of random stream to generate") parser.add_argument('--dh-peers', '-Dp',help="the number of peers participating in a ECDH key exchange") 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 & 0o777 if mode not in [0o700, 0o600]: print('[pbp] ABORT: unsafe permissions %s on basedir %s' % (oct(mode), opts.basedir), file=sys.stderr) # 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 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 PITCHFORK and opts.PITCHFORK: ensure_recipient_specified(opts) pitchfork.init() res=pitchfork.encrypt(opts.recipient[0], infile=opts.infile, outfile=opts.outfile) if res: print(b85encode(res), file=sys.stderr) return 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': if PITCHFORK and opts.PITCHFORK: ensure_recipient_specified(opts) pitchfork.init() res=pitchfork.decrypt(opts.recipient[0], infile=opts.infile, outfile=opts.outfile) else: try: sender = decrypt_handler(infile=opts.infile, outfile=opts.outfile, self=opts.self, max_recipients=int(opts.max_recipients), peer=opts.sender, basedir=opts.basedir) except ValueError as e: print(e) sys.exit(1) else: if sender: print('[pbp] good message from', sender, file=sys.stderr) # sign elif opts.action=='s': if PITCHFORK and opts.PITCHFORK: ensure_recipient_specified(opts) pitchfork.init() res=pitchfork.sign(opts.recipient[0], infile=opts.infile, outfile=opts.outfile) if res: print(b85encode(res[0]), b85encode(res[1]), file=sys.stderr) return 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': if PITCHFORK and opts.PITCHFORK: ensure_signature_specified(opts) ensure_recipient_specified(opts) pitchfork.init() res=pitchfork.verify(opts.signature, opts.recipient[0], infile=opts.infile, outfile=opts.outfile) else: res = verify_handler(infile=opts.infile, outfile=opts.outfile, basedir=opts.basedir) if res: print("[pbp] good message from", res, file=sys.stderr) else: print('[pbp] VERIFICATION FAILED', file=sys.stderr) # key sign elif opts.action=='m': ensure_name_specified(opts) ensure_self_specified(opts) sig = keysign_handler(name=opts.name, self=opts.self, basedir=opts.basedir) if sig: print("[pbp] key signed in", sig) else: print('[pbp] SIGNATURE FAILED', file=sys.stderr) # lists signatures owners on public keys elif opts.action=='C': ensure_name_specified(opts) sigs = keycheck_handler(name=opts.name, basedir=opts.basedir) if sigs: print('[pbp] good signatures on', opts.name, 'from', ', '.join(sigs), file=sys.stderr) else: print('[pbp] NO GOOD SIGS FOUND', file=sys.stderr) # export public key elif opts.action=='x': ensure_self_specified(opts) k = export_handler(opts.self, basedir=opts.basedir) print(k) # import public key elif opts.action=='i': n = import_handler(infile=opts.infile, basedir=opts.basedir) if n: print('[pbp] Success: imported public keys for', n) else: print('[pbp] IMPORT FAILED') # 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, 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': if PITCHFORK and opts.PITCHFORK: ensure_recipient_specified(opts) pitchfork.init() params = pitchfork.start_ecdh(opts.recipient[0]) else: params = dh1_handler() if params: print("[pbp] secret exponent", b85encode(params[0])) print("[pbp] public component", b85encode(params[1])) clearmem(params[0]) # receive ECDH elif opts.action=='d2': ensure_dhparam_specified(opts) if PITCHFORK and opts.PITCHFORK: ensure_recipient_specified(opts) pitchfork.init() params = pitchfork.resp_ecdh(opts.dh_param, opts.recipient[0]) else: params = dh2_handler(binascii.unhexlify(opts.dh_param)) if params: print("[pbp] shared secret", b85encode(params[1])) print("[pbp] public component", b85encode(params[0])) clearmem(params[0]) clearmem(params[1]) # finish ECDH elif opts.action=='d3': ensure_dhparam_specified(opts) ensure_dhexp_specified(opts) if PITCHFORK and opts.PITCHFORK: pitchfork.init() sec = pitchfork.end_ecdh(opts.dh_param, opts.dh_exp) else: sec = dh3_handler(binascii.unhexlify(opts.dh_param), binascii.unhexlify(opts.dh_exp)) if sec: print("[pbp] shared secret", b85encode(sec)) clearmem(sec) # start MPECDH elif opts.action=='ds': ensure_self_specified(opts) ensure_dhpeers_specified(opts) ensure_name_specified(opts) sec = mpecdh_start_handler(opts.name, opts.dh_peers, opts.self, opts.infile, opts.outfile, opts.basedir) if sec: print("[pbp] pushed shared secret, hash", b85encode(nacl.crypto_generichash(sec, outlen=6)), file=sys.stderr) clearmem(sec) sec = None # finish MPECDH elif opts.action=='de': ensure_self_specified(opts) ensure_name_specified(opts) sec = mpecdh_end_handler(opts.name, opts.self, opts.infile, opts.outfile, opts.basedir) if sec: print("[pbp] pushed shared secret, hash", b85encode(nacl.crypto_generichash(sec, outlen=6)), file=sys.stderr) clearmem(sec) sec = None elif opts.action=='R': ensure_size_good(opts) if PITCHFORK and opts.PITCHFORK: pitchfork.init() pitchfork.rng(int(opts.size), opts.outfile) else: random_stream_handler(opts.outfile, opts.size) elif opts.action=='h': hsum = hash_handler(opts.infile, k=load_key(opts.key), outlen=int(opts.size or '16')) if hsum: print(' '.join(split_by_n(binascii.hexlify(hsum),4)))
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=='ds': ensure_self_specified(opts) ensure_dhparam_specified(opts) ensure_name_specified(opts) sec = mpecdh_start_handler(opts.name, opts.dh_peers, opts.self, opts.infile, opts.outfile, opts.basedir) if sec: print >>sys.stderr, "pushed shared secret, hash", b85encode(nacl.crypto_generichash(sec, outlen=6)) clearmem(sec) sec = None # finish ECDH elif opts.action=='de': ensure_self_specified(opts) ensure_name_specified(opts) sec = mpecdh_end_handler(opts.name, opts.self, opts.infile, opts.outfile, opts.basedir) if sec: print >>sys.stderr, "pushed shared secret, hash", b85encode(nacl.crypto_generichash(sec, outlen=6)) clearmem(sec) sec = None elif opts.action=='R': ensure_size_good(opts)
def __init__(self, app, serializer=None, timestamp_key=None): self.key = crypto_generichash(app.secret_key, outlen=crypto_secretbox_KEYBYTES) self.serializer = serializer or TaggedJSONSerializer() self.timestamp_key = timestamp_key or '__session_timestamp__'
def recv(self, msg): """ as per https://github.com/trevp/axolotl/wiki/newversion (Nov 19, 2013 · 41 revisions) Receiving messages ------------------- Local variables: MK : message key Np : Purported message number PNp : Purported previous message number CKp : Purported new chain key DHp : Purported new DHr RKp : Purported new root key NHKp, HKp : Purported new header keys if (plaintext = try_skipped_header_and_message_keys()): return plaintext if Dec(HKr, header): Np = read() CKp, MK = stage_skipped_header_and_message_keys(HKr, Nr, Np, CKr) if not Dec(MK, ciphertext): raise undecryptable if bobs_first_message: DHRr = read() RK = HASH(RK || ECDH(DHRs, DHRr)) HKs = NHKs NHKs, CKs = KDF(RK) erase(DHRs) bobs_first_message = False else: if not Dec(NHKr, header): raise undecryptable() Np, PNp, DHRp = read() stage_skipped_header_and_message_keys(HKr, Nr, PNp, CKr) RKp = HASH(RK || ECDH(DHRs, DHRr)) HKp = NHKr NHKp, CKp = KDF(RKp) CKp, MK = stage_skipped_header_and_message_keys(HKp, 0, Np, CKp) if not Dec(MK, ciphertext): raise undecryptable() RK = RKp HKr = HKp NHKr = NHKp DHRr = DHRp RK = HASH(RK || ECDH(DHRs, DHRr)) HKs = NHKs NHKs, CKs = KDF(RK) erase(DHRs) commit_skipped_header_and_message_keys() Nr = Np + 1 CKr = CKp return read() """ hnonce = msg[:nacl.crypto_secretbox_NONCEBYTES] i = nacl.crypto_secretbox_NONCEBYTES mnonce = msg[i:i+nacl.crypto_secretbox_NONCEBYTES] i += nacl.crypto_secretbox_NONCEBYTES hcrypt = msg[i:i + nacl.crypto_secretbox_MACBYTES + 4 + 4 + nacl.crypto_scalarmult_curve25519_BYTES] i += nacl.crypto_secretbox_MACBYTES + 4 + 4 + nacl.crypto_scalarmult_curve25519_BYTES mcrypt = msg[i:] ret = self.try_skipped_keys(hcrypt, hnonce, mcrypt, mnonce) if ret: return ret headers = None try: headers = nacl.crypto_secretbox_open(hcrypt, hnonce, self.HKr) except: pass if headers: Np = struct.unpack('>I',headers[:4])[0] CKp, MK = self.stage_skipped_keys(self.HKr, self.Nr, Np, self.CKr) msg = nacl.crypto_secretbox_open(mcrypt, mnonce, MK) if self.bobs1stmsg: self.DHRr = headers[8:] self.RK = nacl.crypto_generichash(self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk,self.DHRr), KEY_SIZE) self.HKs = self.NHKs if self.isalice: self.NHKs = nacl.crypto_generichash(self.RK, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKs", KEY_SIZE) else: self.NHKs = nacl.crypto_generichash(self.RK, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKr", KEY_SIZE) self.DHRs.clear() self.DHRs = None self.bobs1stmsg = False else: headers = nacl.crypto_secretbox_open(hcrypt, hnonce, self.NHKr) #unpack header fields Np = struct.unpack('>I',headers[:4])[0] PNp = struct.unpack('>I',headers[4:8])[0] DHRp = headers[8:] self.stage_skipped_keys(self.HKr, self.Nr, PNp, self.CKr) RKp = nacl.crypto_generichash(self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk,self.DHRr), KEY_SIZE) HKp = self.NHKr if self.isalice: NHKp = nacl.crypto_generichash(RKp, "NHKr", KEY_SIZE) CKp = nacl.crypto_generichash(RKp, "CKr", KEY_SIZE) else: NHKp = nacl.crypto_generichash(RKp, "NHKs", KEY_SIZE) CKp = nacl.crypto_generichash(RKp, "CKs", KEY_SIZE) CKp, MK = self.stage_skipped_keys(HKp, 0, Np, CKp) msg = nacl.crypto_secretbox_open(mcrypt, mnonce, MK) self.RK = RKp self.HKr = HKp self.NHKr = NHKp self.DHRr = DHRp self.RK = nacl.crypto_generichash(self.RK, nacl.crypto_scalarmult_curve25519(self.DHRs.sk,self.DHRr), KEY_SIZE) self.HKs = self.NHKs if self.isalice: self.NHKs = nacl.crypto_generichash(self.RK, "NHKs", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKs", KEY_SIZE) else: self.NHKs = nacl.crypto_generichash(self.RK, "NHKr", KEY_SIZE) self.CKs = nacl.crypto_generichash(self.RK, "CKr", KEY_SIZE) self.DHRs.clear() self.DHRs = None # commit_skipped_header_and_message_keys() : Commits any skipped-over message keys from the # staging area to persistent storage (along with their associated header keys). self.skipped_HK_MK.update(self.staged_HK_MK) self.staged_HK_MK = {} self.Nr = Np + 1 self.CKr = CKp return msg
def port_from_private_key(k): h = pysodium.crypto_generichash(k) return (ord(h[-2]) << 8) | ord(h[-1])
def test_crypto_sign_sk_to_seed(self): seed1 = pysodium.crypto_generichash(b'howdy', outlen=pysodium.crypto_sign_SEEDBYTES) _, sk = pysodium.crypto_sign_seed_keypair(seed1) seed2 = pysodium.crypto_sign_sk_to_seed(sk) self.assertEqual(seed1, seed2)
def test_crypto_sign_seed_keypair(self): seed = pysodium.crypto_generichash(b'howdy', outlen=pysodium.crypto_sign_SEEDBYTES) pk, sk = pysodium.crypto_sign_seed_keypair(seed) pk2, sk2 = pysodium.crypto_sign_seed_keypair(seed) self.assertEqual(pk, pk2) self.assertEqual(sk, sk2)
def saferandom(n): if not n: return b'' # hash so we don't print prng output onto the network return pysodium.crypto_generichash(pysodium.randombytes(min(n, 32)), outlen=n)