def test_sign_test_key_conversion(): """ Taken from test vectors in libsodium """ keypair_seed = unhexlify(b"421151a459faeade3d247115f94aedae" b"42318124095afabe4d1451a559faedee") ed25519_pk, ed25519_sk = c.crypto_sign_seed_keypair(keypair_seed) assert c.crypto_sign_ed25519_sk_to_pk(ed25519_sk) == ed25519_pk with pytest.raises(ValueError): c.crypto_sign_ed25519_sk_to_pk(unhexlify(b"12")) assert c.crypto_sign_ed25519_sk_to_seed(ed25519_sk) == keypair_seed with pytest.raises(ValueError): c.crypto_sign_ed25519_sk_to_seed(unhexlify(b"12")) curve25519_pk = c.crypto_sign_ed25519_pk_to_curve25519(ed25519_pk) with pytest.raises(ValueError): c.crypto_sign_ed25519_pk_to_curve25519(unhexlify(b"12")) with pytest.raises(ValueError): c.crypto_sign_ed25519_sk_to_curve25519(unhexlify(b"12")) curve25519_sk = c.crypto_sign_ed25519_sk_to_curve25519(ed25519_sk) assert tohex(curve25519_pk) == ("f1814f0e8ff1043d8a44d25babff3ced" "cae6c22c3edaa48f857ae70de2baae50") assert tohex(curve25519_sk) == ("8052030376d47112be7f73ed7a019293" "dd12ad910b654455798b4667d73de166")
def test_sign_test_key_conversion(): """ Taken from test vectors in libsodium """ keypair_seed = unhexlify(b"421151a459faeade3d247115f94aedae" b"42318124095afabe4d1451a559faedee") ed25519_pk, ed25519_sk = c.crypto_sign_seed_keypair(keypair_seed) assert c.crypto_sign_ed25519_sk_to_pk(ed25519_sk) == ed25519_pk with pytest.raises(ValueError): c.crypto_sign_ed25519_sk_to_pk(unhexlify(b"12")) assert c.crypto_sign_ed25519_sk_to_seed(ed25519_sk) == keypair_seed with pytest.raises(ValueError): c.crypto_sign_ed25519_sk_to_seed(unhexlify(b"12")) curve25519_pk = c.crypto_sign_ed25519_pk_to_curve25519(ed25519_pk) with pytest.raises(ValueError): c.crypto_sign_ed25519_pk_to_curve25519(unhexlify(b"12")) with pytest.raises(ValueError): c.crypto_sign_ed25519_sk_to_curve25519(unhexlify(b"12")) curve25519_sk = c.crypto_sign_ed25519_sk_to_curve25519(ed25519_sk) assert tohex(curve25519_pk) == ("f1814f0e8ff1043d8a44d25babff3ced" "cae6c22c3edaa48f857ae70de2baae50") assert tohex(curve25519_sk) == ("8052030376d47112be7f73ed7a019293" "dd12ad910b654455798b4667d73de166")
def get_remote_feed(self): remote_feed = None if os.path.isfile(CONFIG_DIR + self.remote_fid + ".pcap"): remote_feed = FEED(CONFIG_DIR + self.remote_fid + ".pcap", bytes.fromhex(self.remote_fid), PublicKey(crypto_sign_ed25519_pk_to_curve25519(bytes.fromhex(self.remote_fid)))) return remote_feed
def get_remote_data_feed(self): remote_feed = None if self.get_data_feed() is not None: if os.path.isfile( DATA_DIR + self.get_data_feed() + ".pcap"): remote_feed = FEED(DATA_DIR + self.get_data_feed() + ".pcap", bytes.fromhex(self.get_data_feed()), PublicKey(crypto_sign_ed25519_pk_to_curve25519(bytes.fromhex(self.get_data_feed())))) return remote_feed
def add_verifying_key(self, vk: str): # Convert to bytes if hex string bvk = bytes.fromhex(vk) try: pk = crypto_sign_ed25519_pk_to_curve25519(bvk) # Error is thrown if the VK is not within the possibility space of the ED25519 algorithm except RuntimeError: self.log.error('ED25519 Cryptographic error. The key provided is not within the cryptographic key space.') return zvk = z85.encode(pk).decode('utf-8') _write_key_file(self.cert_dir / f'{vk}.key', banner=_cert_public_banner, public_key=zvk)
def add_verifying_key(self, vk: bytes): # Convert to bytes if hex string if isinstance(vk, str): vk = bytes.fromhex(vk) try: pk = crypto_sign_ed25519_pk_to_curve25519(vk) # Error is thrown if the VK is not within the possibility space of the ED25519 algorithm except RuntimeError: print('no go') return zvk = z85.encode(pk).decode('utf-8') _write_key_file(self.cert_dir / f'{vk.hex()}.key', banner=_cert_public_banner, public_key=zvk)
def bacnet_watchdog(self): old_seq = {} self.tcp_threads = {} for authorized_feed in self.authorized_feeds: old_seq[authorized_feed] = -1 while True: for authorized_feed in self.authorized_feeds: if os.path.isfile(authorized_feed + ".pcap"): temp_feed = FEED(authorized_feed + ".pcap", bytes.fromhex(authorized_feed), PublicKey(crypto_sign_ed25519_pk_to_curve25519(bytes.fromhex(authorized_feed)))) if old_seq[authorized_feed] != temp_feed.seq and old_seq[authorized_feed] >= 0: temp_feed.seq = 0 temp_feed.hprev = None for e in temp_feed: if not temp_feed.is_valid_extension(e): print(f"-> event {temp_feed.seq + 1}: chaining or signature problem") else: if temp_feed.seq == old_seq[authorized_feed]: e_content = json.loads(e.content()) if e_content['event'] == "tcp/open": host = e_content['content']['host'] port = int(e_content['content']['port']) self.setup_data_feed(authorized_feed) if not authorized_feed in self.tcp_threads.keys(): self.tcp_threads[authorized_feed] = {} self.tcp_threads[authorized_feed]['tasks'] = queue.Queue() self.tcp_threads[authorized_feed]['thread'] = Thread( target=self.tcp_watchdog, args=(authorized_feed, host, port)) self.tcp_threads[authorized_feed]['thread'].start() elif e_content['event'] == "tcp/write": if authorized_feed in self.tcp_threads.keys(): self.tcp_threads[authorized_feed]['tasks'].put(e_content) elif e_content['event'] == "tcp/close": if authorized_feed in self.tcp_threads.keys(): self.tcp_threads[authorized_feed]['tasks'].put(e_content) if old_seq[authorized_feed] < temp_feed.seq: break temp_feed.seq += 1 temp_feed.hprev = e.get_ref() old_seq[authorized_feed] = temp_feed.seq time.sleep(1)
def write_to(self, channel: CHANNEL, event, content, r=None, rekey=0): """ This function creates a write statement after encrypting the message. Parameters ---------- self : USER The user who writes channel : CHANNEL The channel where user writes to event: EVENT The event to write content: str The content of the event r: String The public key of the recipient user rekey: int Indicates which dkey to use (0 = latest, 1 = one before latest, ...) """ # no rekey if r != None: # create a box between owner of a channel and invited user box = Box( self.get_curve_private_key(), PublicKey( crypto_sign_ed25519_pk_to_curve25519(bytes.fromhex(r)))) hkey = bytes.fromhex(self.fid) # rekey necessary else: # create a box containing all members of a channel box = SecretBox(channel.dkeys_bytes()[rekey]) hkey = channel.hkey_bytes() # build message from event and content and encrypt it message = get_message_json(event, content).encode('utf-8') encrypted = box.encrypt(message, encoder=Base64Encoder) # write cyphertext using digest (=cypher) and encrypted message digest = hmac.digest(hkey, encrypted, sha256) self.write_cyphertext(digest, encrypted)
def to_age_public_key(self) -> AgePublicKey: # use pynacl for this conversion ed25519_pk = self._key.public_bytes(Encoding.Raw, PublicFormat.Raw) curve25519_pk = crypto_sign_ed25519_pk_to_curve25519(ed25519_pk) public_key = X25519PublicKey.from_public_bytes(curve25519_pk) return AgePublicKey(public_key)
def sync(self): """ This function completes a synchronization process of a user which gets the updates of the users he follows. Parameters ---------- self : USER The user which does a sync """ synced = {} f = FEED("user-" + self.fid + '.pcap', bytes.fromhex(self.fid), self.get_signer()) if f.pcap == None: return f.seq = 0 f.hprev = None # print(f"Checking feed {f.fid.hex()}") for e in f: # print(e) if not f.is_valid_extension(e): print(f"-> event {f.seq + 1}: chaining or signature problem") else: event = check_sync(e.content()) if (event != None): synced[event.fid.hex()] = event.seq f.seq += 1 f.hprev = e.get_ref() # print(synced) # iterate through the users he follows for follow in self.follows: f = FEED( "user-" + follow + '.pcap', bytes.fromhex(follow), PublicKey( crypto_sign_ed25519_pk_to_curve25519( bytes.fromhex(follow)))) if f.pcap == None: exit(1) f.seq = 0 f.hprev = None # print(f"Checking feed {f.fid.hex()}") new_msg_count = 0 # iterate through events in their feeds for e in f: # print(e) # event not valid if not f.is_valid_extension(e): print( f"-> event {f.seq + 1}: chaining or signature problem") # event valid else: try: syncremote = synced[follow] except: syncremote = -1 # if this event is not synced yet if (syncremote < e.seq): # remember that we have synced this synced[follow] = e.seq eo = e ev = check_sync(e.content()) # if it's a sync entry if (ev != None): # ignore the ones from our log if (ev.fid.hex() == self.fid): f.seq += 1 f.hprev = e.get_ref() continue try: # get sync progress of this synced event syncdeep = synced[ev.fid.hex()] except: syncdeep = -1 # ignore everything not newer if (ev.seq <= syncdeep): f.seq += 1 f.hprev = e.get_ref() continue # remember that we have synced this synced[ev.fid.hex()] = ev.seq eo = ev # write cleartext to log oof sync process self.write_cleartext( get_message_json("log/sync", eo.wire.hex())) new_msg_count += 1 self.decrypt(eo, parse=True) # print("add:",eo.seq,self.getFollowAlias(eo.fid.hex())) # go to next event in feed f.seq += 1 f.hprev = e.get_ref() """ if (new_msg_count > 0):
def decrypt(self, event: EVENT, parse=False): """ Using this function a user tries to decrypt an event. Parameters ---------- self : USER The user decrypting an event event : EVENT The event to decrypt parse : bool Describes if event need to be parsed """ # msg = '{"event": "app/action", "content": "xxx"}' # log_event = '{"hmac": "'+digest.hex()+'", "cyphertext": "'+encrypted.hex()+'"}' # log_event = {"cleartext": {"event": "chat/create", "content": "two"}} # log_event = {"cleartext": {"event": "log/sync", "content": "RAW_BACNET_EVENT"}} # print(event) # determine sender sender = get_alias_by_id(self.fid) # check if need to sync e = check_sync(event.content()) if (e != None): # parse this content event = e sender = get_alias_by_id(e.fid.hex()) # return 'sync: ' + e.fid.hex() + ' ' + e.content().__repr__() data = loads(event.content()) try: # print cleartext return sender + '@all: ' + data['cleartext']['event'] + ' ' + data[ 'cleartext']['content'] except KeyError: # cyphertext --> needs decryption cypher = bytes.fromhex(data['cyphertext']) if bytes.fromhex(data['hmac']) == hmac.digest( event.fid, cypher, sha256): try: # try to decrypt private event box = Box( self.get_curve_private_key(), PublicKey( crypto_sign_ed25519_pk_to_curve25519(event.fid))) cleartext = box.decrypt(cypher, encoder=Base64Encoder) data = loads(cleartext) inv = check_invite(data) if parse and inv != None: self.add_channel(inv) return sender + '@private: ' + data['event'] + ' ' + data[ 'content'] except nacl.exceptions.CryptoError: # not allowed to decrypt private boy return sender + '@privatebox' # loop through other channels hkey for c in self.channels: c = CHANNEL(self, c[0]) channel = get_alias_by_id(c.cid) hkey = c.hkey_bytes() if bytes.fromhex(data['hmac']) == hmac.digest( hkey, cypher, sha256): # print('matched hkey: '+hkey) # print('hmac: '+data['hmac']) # print('unboxing...') for dk in c.dkeys_bytes(): try: # decrypt message in channel box = SecretBox(dk) cleartext = box.decrypt(cypher, encoder=Base64Encoder) data = loads(cleartext) rekey = check_rekey(data) if parse and rekey != None: c.add_dkey(self, rekey) return sender + '@[' + channel + ']: ' + data[ 'event'] + ' ' + data['content'] except nacl.exceptions.CryptoError: # not allowed to decrypt channel message continue # perhaps there is another dkey return sender + '@lock[' + channel + ']' # no dkey found (not a member anymore) return sender + '@secret' # - not cleartext nor matching a channel