def decrypt_message(encrypted_message, keying_material, private_key): encrypted_key = keying_material['encrypted_key'] message_signature = keying_material['message_signature'] temp_public_key = PublicKey( keying_material['temp_public_key'], Base64Encoder) box = PublicBox(private_key, temp_public_key) message_key = box.decrypt( encrypted_key, encoder=Base64Encoder) # We got the key, so let's get the message. message_box = nacl.secret.SecretBox(message_key) message = message_box.decrypt( encrypted_message, encoder=Base64Encoder) # Check the signature. mac_key = sha256(box._shared_key, RawEncoder) signing_key = SigningKey(mac_key) if signing_key.sign(message, Base64Encoder) != message_signature: raise SignatureError("The signature is not valid") return message
def test_message_signing(self, seed, message, signature, expected): signing_key = SigningKey(seed, encoder=HexEncoder) signed = signing_key.sign(binascii.unhexlify(message), encoder=HexEncoder) assert signed == expected assert signed.message == message assert signed.signature == signature
def add_new_channel(self, nA, nB): a_signkey = SigningKey.generate() a_chankey = PrivateKey.generate() a_CIDkey = os.urandom(32) a_transports = nA.agent.individualize_transports(nA.agent.get_transports()) b_signkey = SigningKey.generate() b_chankey = PrivateKey.generate() b_CIDkey = os.urandom(32) b_transports = nB.agent.individualize_transports(nB.agent.get_transports()) a_rec = { "channel_pubkey": a_chankey.public_key.encode().encode("hex"), "CID_key": a_CIDkey.encode("hex"), "transports": a_transports.values(), } b_rec = { "channel_pubkey": b_chankey.public_key.encode().encode("hex"), "CID_key": b_CIDkey.encode("hex"), "transports": b_transports.values(), } q = ("INSERT INTO addressbook" " (petname, acked, next_outbound_seqnum," " my_signkey," " their_channel_record_json," " my_CID_key, next_CID_token," " highest_inbound_seqnum," " my_old_channel_privkey, my_new_channel_privkey," " they_used_new_channel_key, their_verfkey)" " VALUES(?,?,?,?,?,?,?,?,?,?,?,?)") vA=("petname-from-A", 1, 1, a_signkey.encode().encode("hex"), json.dumps(b_rec), a_CIDkey.encode("hex"), None, 0, a_chankey.encode().encode("hex"), a_chankey.encode().encode("hex"), 0, b_signkey.verify_key.encode().encode("hex"), ) vB=("petname-from-A", 1, 1, b_signkey.encode().encode("hex"), json.dumps(a_rec), b_CIDkey.encode("hex"), None, 0, b_chankey.encode().encode("hex"), b_chankey.encode().encode("hex"), 0, a_signkey.verify_key.encode().encode("hex"), ) nA.db.execute(q, vA) nA.db.commit() nB.db.execute(q, vB) nA.db.commit() entA = nA.db.execute("SELECT * FROM addressbook").fetchone() entB = nB.db.execute("SELECT * FROM addressbook").fetchone() return entA, entB
def test_key_conversion(self): keypair_seed = (b"421151a459faeade3d247115f94aedae" b"42318124095afabe4d1451a559faedee") signing_key = SigningKey(binascii.unhexlify(keypair_seed)) verify_key = signing_key.verify_key private_key = bytes(signing_key.to_curve25519_private_key()) public_key = bytes(verify_key.to_curve25519_public_key()) assert tohex(private_key) == ("8052030376d47112be7f73ed7a019293" "dd12ad910b654455798b4667d73de166") assert tohex(public_key) == ("f1814f0e8ff1043d8a44d25babff3ced" "cae6c22c3edaa48f857ae70de2baae50")
def test_verify_with_prefix(self): sk = SigningKey.generate() vk = sk.verify_key m = "body" prefix = "prefix:" sk2 = SigningKey.generate() sm1 = sk.sign(prefix+m) sm2 = sk.sign("not the prefix"+m) sm3 = sk2.sign(prefix+m) self.failUnlessEqual(util.verify_with_prefix(vk, sm1, prefix), m) self.failUnlessRaises(errors.BadSignatureError, util.verify_with_prefix, vk, sm2, prefix) self.failUnlessRaises(CryptoError, util.verify_with_prefix, vk, sm3, prefix)
def __enter__(self) -> typing.Tuple[PrivateKey, PrivateKey]: """ Provides a pair of private keys. """ # Derive the key from the passphrase. derived = util.derive_passphrase(self.passphrase) sign_box = SecretBox(derived) enc_box = SecretBox(derived) # Decrypt, using the two nonces. s_d = sign_box.decrypt(self.key._private_signing_seed, self.key._private_signing_nonce) e_d = enc_box.decrypt(self.key._private_key_raw, self.key._private_nonce) # Generate a SigningKey out of the seed. self.sign = SigningKey(s_d) self.encrypt = PrivateKey(e_d) # Update the key's public keys. if self.key._public_key is None: self.key._public_key = self.encrypt.public_key if self.key._public_signing_key is None: self.key._public_signing_key = self.sign.verify_key return self.encrypt, self.sign
def sign(self, message, private_key): """ Sign the message. This method will take the currently configured values for the message prefix and suffix and create a signature using the provided Ed25519 private key. Args: message (bytes): message to be signed private_key (bytes) Ed25519 private key """ sk = SigningKey(private_key) self.public_key = sk.verify_key.encode() self.signature = sk.sign(message).signature return self.signature
def test_wrong_types(): sk = SigningKey.generate() check_type_error("SigningKey must be created from a 32 byte seed", SigningKey, 12) check_type_error("SigningKey must be created from a 32 byte seed", SigningKey, sk) check_type_error("SigningKey must be created from a 32 byte seed", SigningKey, sk.verify_key) check_type_error("VerifyKey must be created from 32 bytes", VerifyKey, 13) check_type_error("VerifyKey must be created from 32 bytes", VerifyKey, sk) check_type_error("VerifyKey must be created from 32 bytes", VerifyKey, sk.verify_key)
def encrypt_message(message, identifier): """Encrypts a message so that it can be read by all the devices of the given identifier. :param message: the message itself, in clear text. :param identifier: the identifier of the message recipient. """ # Cipher the message with a brand new random key. message_key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE) message_box = nacl.secret.SecretBox(message_key) message_nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE) encrypted_message = message_box.encrypt(message, message_nonce, Base64Encoder) returned = [] # Encrypt the message key with each recipient's public key. for recipient_device_pub_key in get_public_keys(identifier): # Generate a new keypair & cipher the key with it. temp_private_key, temp_public_key = generate_keypair() box = PublicBox(temp_private_key, recipient_device_pub_key) nonce = nacl.utils.random(PublicBox.NONCE_SIZE) encrypted_key = box.encrypt(message_key, nonce, Base64Encoder) # Sign the message. mac_key = sha256(box._shared_key, RawEncoder) signing_key = SigningKey(mac_key) message_sig = signing_key.sign(message, Base64Encoder) # Return the public key used to cipher the message key. returned.append({ 'encrypted_key': encrypted_key, 'temp_public_key': temp_public_key.encode(Base64Encoder), 'message_signature': message_sig }) return { 'encrypted_message': encrypted_message, 'recipients': returned }
def test_invalid_signed_message(self): skey = SigningKey.generate() smessage = skey.sign(b"A Test Message!") signature, message = smessage.signature, b"A Forged Test Message!" # Small sanity check assert skey.verify_key.verify(smessage) with pytest.raises(BadSignatureError): skey.verify_key.verify(message, signature) with pytest.raises(BadSignatureError): forged = SignedMessage(signature + message) skey.verify_key.verify(forged)
def test_hex_smessage_with_detached_sig_matches_with_attached_sig(self): sk = SigningKey.generate() vk = sk.verify_key smsg = sk.sign(b"Hello World in hex", encoder=HexEncoder) msg = smsg.message hexsig = smsg.signature sig = HexEncoder.decode(hexsig) assert vk.verify(msg, sig, encoder=HexEncoder) == \ vk.verify(smsg, encoder=HexEncoder) assert HexEncoder.decode(msg) == b"Hello World in hex"
def test_base64_smessage_with_detached_sig_matches_with_attached_sig(self): sk = SigningKey.generate() vk = sk.verify_key smsg = sk.sign(b"Hello World in base64", encoder=Base64Encoder) msg = smsg.message b64sig = smsg.signature sig = Base64Encoder.decode(b64sig) assert vk.verify(msg, sig, encoder=Base64Encoder) == \ vk.verify(smsg, encoder=Base64Encoder) assert Base64Encoder.decode(msg) == b"Hello World in base64"
def test_initalization(): from nacl.encoding import HexEncoder from nacl.signing import SigningKey _generated_signing_key = SigningKey.generate() verification_key = _generated_signing_key.verify_key.encode( encoder=HexEncoder) assert (isinstance( Dispike( client_public_key=verification_key.decode(), bot_token="BOTTOKEN", application_id="APPID", ), Dispike, ) == True)
def __init__(self, kp): ''' Initialize the Whisper class using your Stellar. Args: kp: This is your Stellar keypair, as encoded by the stellar_base.keypair class. Returns: Instance of the object. ''' self.__kp = kp self.__sk = SigningKey(kp.raw_seed()).to_curve25519_private_key()._private_key self.__pk = VerifyKey(kp.raw_public_key()).to_curve25519_public_key()._public_key self.__address = kp.address().decode() self.__seed = kp.seed().decode()
def test_service_auth_admin_fails() -> None: node = sy.Device() msg = sy.ReprMessage(address=node.address) random_signing_key = SigningKey.generate() random_verify_key = random_signing_key.verify_key # Administrator only @service_auth(admin_only=True) def process(node: sy.Device, msg: sy.ReprMessage, verify_key: VerifyKey) -> None: pass with pytest.raises(AuthorizationException, match="User lacks Administrator credentials."): process(node=node, msg=msg, verify_key=random_verify_key)
def test_service_auth_cpl_ofcr_success() -> None: node = sy.Device() msg = sy.ReprMessage(address=node.address) random_signing_key = SigningKey.generate() random_verify_key = random_signing_key.verify_key # Compliance Officer only @service_auth(cpl_ofcr_only=True) def process(node: sy.Device, msg: sy.ReprMessage, verify_key: VerifyKey) -> None: pass # NOTE didn't find a method to add a key to cpl_ofcr_verify_key_registry node.cpl_ofcr_verify_key_registry.add(random_verify_key) process(node=node, msg=msg, verify_key=random_verify_key)
def test_hex_smessage_with_detached_sig_matches_with_attached_sig(self): sk = SigningKey.generate() vk = sk.verify_key smsg = sk.sign(b"Hello World in hex", encoder=HexEncoder) msg = smsg.message hexsig = smsg.signature sig = HexEncoder.decode(hexsig) assert vk.verify(msg, sig, encoder=HexEncoder) == vk.verify(smsg, encoder=HexEncoder) assert HexEncoder.decode(msg) == b"Hello World in hex"
def build(self, pri_key_arg=None, pub_key_arg=None): # kivy stuff Clock.schedule_interval(self.generateSignature, 1) self.title = "fathom" self.layout = BoxLayout(orientation="vertical") self.image = Image(source="") self.image.allow_stretch = True self.layout.add_widget(self.image) self.signing_key = SigningKey.generate() # # generate keys if necessary # if not pri_key_arg: # self.pri_key_arg = "private.pem" # else: # self.pri_key_arg = pri_key_arg # if os.path.isfile(self.pri_key_arg): # self.pri_key = RSA.import_key(open(self.pri_key_arg)) # else: # print(("generating private key: {}".format(self.pri_key_arg))) # self.pri_key = SigningKey.generate() # file_out = open(self.pri_key_arg, "wb") # file_out.write(self.pri_key) # if not pub_key_arg: # self.pub_key_arg = "public.pem" # else: # self.pub_key_arg = pub_key_arg # if os.path.isfile(self.pub_key_arg): # self.pub_key = RSA.import_key(open(self.pub_key_arg)) # else: # print(("generating public key: {}".format(self.pub_key_arg))) # self.pub_key = self.pri_key_raw.publickey().export_key() # file_out = open(self.pub_key_arg, "wb") # file_out.write(self.pub_key) # signature objects self.time = None self.hash = None self.signature = None self.msg = None # generate initial signature immediately self.generateSignature(dt=None) return self.layout
def create_network_app(app, args, testing=False): test_config = None if args.start_local_db: test_config = {"SQLALCHEMY_DATABASE_URI": "sqlite:///nodedatabase.db"} app.register_blueprint(roles_blueprint, url_prefix=r"/roles") app.register_blueprint(users_blueprint, url_prefix=r"/users") app.register_blueprint(setup_blueprint, url_prefix=r"/setup") app.register_blueprint(root_blueprint, url_prefix=r"/") app.register_blueprint(search_blueprint, url_prefix=r"/search") app.register_blueprint(association_requests_blueprint, url_prefix=r"/association-requests/") # Register WebSocket blueprints # Here you should add all the blueprints related to WebSocket routes. # sockets.register_blueprint() from .database import db, set_database_config, seed_network_db, User, Role global node node = GridNetwork(name=args.name) # Set SQLAlchemy configs set_database_config(app, test_config=test_config) s = app.app_context().push() db.create_all() if not testing: if len(db.session.query(Role).all()) == 0: seed_network_db() role = db.session.query(Role.id).filter_by(name="Owner").first() user = User.query.filter_by(role=role.id).first() if user: signing_key = SigningKey(user.private_key.encode("utf-8"), encoder=HexEncoder) node.signing_key = signing_key node.verify_key = node.signing_key.verify_key node.root_verify_key = node.verify_key db.session.commit() app.config["EXECUTOR_PROPAGATE_EXCEPTIONS"] = True app.config["EXECUTOR_TYPE"] = "thread" executor.init_app(app) return app
def _signing_key_generate(self): """ Generate an ed25519 signing key if words if specified, words are used as seed to rengerate a known key if words is None, a random seed is generated once the key is generated it is stored in chosen path encrypted using the local secret """ key = SigningKey.generate() # seed = key._seed # encrypted_seed = j.myidentities.encrypt(seed) self._signing_key = key self.me.signing_key = self.signing_key_hex self.me.verify_key = self.verify_key_hex self._signing_key_load() self.me.save()
def test_service_auth_existing_user() -> None: node = sy.Device() msg = sy.ReprMessage(address=node.address) random_signing_key = SigningKey.generate() random_verify_key = random_signing_key.verify_key # existing_users_only @service_auth(existing_users_only=True) def process(node: sy.Device, msg: sy.ReprMessage, verify_key: VerifyKey) -> None: pass with pytest.raises(AuthorizationException, match="User not known."): process(node=node, msg=msg, verify_key=random_verify_key) # NOTE didn't find a method to add a key to guest_verify_key_registry node.guest_verify_key_registry.add(random_verify_key) process(node=node, msg=msg, verify_key=random_verify_key)
def main(): """ main function for keygen """ argparser = AP() argparser.add_argument('--keyfile', type=str, required=True, help='place to put generated keys') args = argparser.parse_args() secret = SigningKey.generate() with open(args.keyfile, 'wb') as wfile: wfile.write(b'd1:s64:') wfile.write(secret.encode()) wfile.write(secret.verify_key.encode()) wfile.write(b'e') print("{}.loki".format(base32z(secret.verify_key.encode())))
def new_lease( self, router_id: bytes, tags: List[str], before: int ) -> Tuple[ Lease, SigningKey]: # TODO (rubicon): use RouterInfo instead router_id in parameters new_signing_key = SigningKey.generate() new_id = new_signing_key.verify_key.encode() assert isinstance(new_id, bytes) lease = Lease( router_id=router_id, identity=new_id, # TODO (rubicon): verifiable lease identity tags=tags, physical_addresses=[], before=c_int64(before), ) self.leaseset[new_id] = lease return lease, new_signing_key
def from_seed(cls, path): """ Provide a path to a seed file as generated by the tfuser tool """ with open(path, 'r') as f: content = f.read() dec = json.JSONDecoder() version, index = dec.raw_decode(content) if version != "1.1.0": raise Exception("invalid seed file, wrong version") identity = dec.decode(content[index:]) entropy = EnglishMnemonic.to_entropy(identity["mnemonic"]) signing_key = SigningKey(bytes(entropy)) return cls(identity['threebotid'], signing_key)
def load_from_keystore(path, password): """ Load an account from a Keystore/JSON file :param path: the path to the keystore :param password: the password to decrypt the keystore :return: the account raise an error if the account cannot be opened """ with open(path, 'r') as fp: j = json.load(fp) raw_priv = keystore.decode_keyfile_json(j, password.encode("utf-8")) signing_key = SigningKey(seed=raw_priv[0:32], encoder=RawEncoder) kp = Account(signing_key, signing_key.verify_key) return kp
def test_no_guild_id_passed_but_guild_only_argument_for_edit_command(): from nacl.encoding import HexEncoder from nacl.signing import SigningKey _generated_signing_key = SigningKey.generate() verification_key = _generated_signing_key.verify_key.encode(encoder=HexEncoder) _current_dispike_object = Dispike( client_public_key=verification_key.decode(), bot_token="BOTTOKEN", application_id="APPID", ) with pytest.raises(TypeError): _current_dispike_object.edit_command( new_command=[], guild_only=True, command_id=1122122 )
def create_custom_user(): if _role != _admin_role.name: # Generate a new signing key _private_key = SigningKey.generate() _user = users.signup( email=_email, password=_password, role=node.roles.first(name=_role).id, private_key=_private_key.encode( encoder=HexEncoder).decode("utf-8"), verify_key=_private_key.verify_key.encode( encoder=HexEncoder).decode("utf-8"), ) # If purposed role is Owner else: raise AuthorizationError( message='You can\'t create a new User with "Owner" role!')
def test_invalid_signature_length(self): skey = SigningKey.generate() message = b"hello" signature = skey.sign(message).signature # Sanity checks assert skey.verify_key.verify(message, signature) assert skey.verify_key.verify(signature + message) with pytest.raises(ValueError): skey.verify_key.verify(message, b"") with pytest.raises(ValueError): skey.verify_key.verify(message, signature * 2) with pytest.raises(ValueError): skey.verify_key.verify(signature + message, b"")
def test_invalid_reset_registration(dispike_object: Dispike): from nacl.encoding import HexEncoder from nacl.signing import SigningKey _generated_signing_key = SigningKey.generate() verification_key = _generated_signing_key.verify_key.encode(encoder=HexEncoder) _current_dispike_object = Dispike( client_public_key=verification_key.decode(), bot_token="BOTTOKEN", application_id="APPID", ) with pytest.raises(Exception): _current_dispike_object.reset_registration( new_bot_token=tuple(0, 0, 0), new_application_id={1: None} )
def _parse_tx_data(self, tx): """ transaction data is a hash expected notary format: content: encrypted content signature: hex encoded signature 3bot id: id of the 3bot """ data_key = tx.data if not data_key: self.logger.info("no data key found in transaction %s", tx.id) return key = data_key.decode('utf-8') data = self._get_data(key) if not data: self.logger.info("no data found in transaction %s", tx.id) return # base64 decode content and signature data['content'] = base64.b64decode(data.get('content', "")) data['content_signature'] = base64.b64decode( data.get('content_signature', "")) # verify signature verification_key = self._get_3bot_key(data['threebot_id']) if not self._verify_signature(verification_key, data['content'], data['content_signature']): self.logger.info("fail to verify transaction %s content signature", tx.id) return # decrypt data signing_key = self._wallet.private_key(tx.to_address) if not signing_key: self.logger.info("fail to get signing key for transaction %s", tx.id) return # ed25519 private keys actually hold an appended copy of the pub key, we only care for the first 32 bytes signing_key = SigningKey(signing_key[:32]) decrypted_data = self._decrypt_data(verification_key, signing_key, data['content']) data_dict = j.data.serializer.msgpack.loads(decrypted_data) data_dict['txId'] = tx.id data_dict['amount'] = tx.amount return data['threebot_id'], data_dict
def new_user(args): """Creates a brand new KeyField user identity. """ if not args.username.isprintable(): raise ValueError(f"Username must be text characters.") # TODO check username against spec username = args.username if LocalStorage.exists(username): print("It appears this user has already been initialized:") print( f"User {username} with public key {_get_user_publickey(username).encode(URLSafeBase64Encoder)}" ) if not args.force: print(f"Pass --force to overwrite and create a new user identity.") return else: print(f"Overwriting data for {username}") LocalStorage.create_new_storage(username) user_storage = LocalStorage(username) device_storage = LocalStorage('device') with user_storage as us, device_storage as ds: us["username"] = username ds["username"] = username us["homeserver"] = { "address": "", "public": "", "verify": "", } us["signingkey"] = SigningKey.generate().encode() us["privatekey"] = PrivateKey.generate().encode() us["previous_keys"] = { get_timestamp_seconds(): { "signingkey": us["signingkey"], "privatekey": us["privatekey"], } } us["devices"] = { ds["devicename"]: { "added": get_timestamp_seconds(), "publickey": _get_device_publickey().encode(), } } print( f"Identity created: {_get_user_verifykey(username).encode(URLSafeBase64Encoder)} with username {username}" )
def update_tensor_msg( msg: UpdateTensorMessage, node: AbstractNode, ) -> UpdateTensorResponse: try: payload = msg.content new_tensor = th.tensor(payload["tensor"]) new_tensor.tag(*payload.get("tags", [])) new_tensor.describe(payload.get("description", "")) key = UID.from_string(value=payload["tensor_id"]) # Step 2: create message which contains object to send storable = StorableObject( id=key, data=new_tensor, tags=new_tensor.tags, description=new_tensor.description, search_permissions={VerifyAll(): None} if payload.get("searchable", False) else {}, ) obj_msg = SaveObjectAction(obj=storable, address=node.address) signed_message = obj_msg.sign( signing_key=SigningKey( payload["internal_key"].encode("utf-8"), encoder=HexEncoder ) ) node.recv_immediate_msg_without_reply(msg=signed_message) return UpdateTensorResponse( address=msg.reply_to, status_code=200, content={"msg": "Tensor modified succesfully!"}, ) except Exception as e: return UpdateTensorResponse( address=msg.reply_to, status_code=200, content={"error": str(e)}, )
class Ed25519PrivateKey(ed25519.Ed25519PrivateKey): def __init__(self, data: bytes): self._key = SigningKey(data) def __bytes__(self) -> bytes: return bytes(self._key) def __hash__(self) -> int: return hash(bytes(self)) def __eq__(self, other: object) -> bool: if not isinstance(other, self.__class__): return False return self._key == other._key def __ne__(self, other: object) -> bool: return not (self == other) @classmethod def generate(cls) -> ed25519.Ed25519PrivateKey: return cls(bytes(SigningKey.generate())) @classmethod def from_private_bytes(cls, data: bytes) -> ed25519.Ed25519PrivateKey: return cls(data) def public_key(self) -> ed25519.Ed25519PublicKey: return Ed25519PublicKey(bytes(self._key.verify_key)) def private_bytes( self, encoding: serialization.Encoding, format: serialization.PrivateFormat, encryption_algorithm: serialization.KeySerializationEncryption, ) -> bytes: if (encoding is not serialization.Encoding.Raw or format is not serialization.PrivateFormat.Raw or not isinstance(encryption_algorithm, serialization.NoEncryption)): raise ValueError("Encoding and format must be Raw and " "encryption_algorithm must be NoEncryption") return bytes(self) def sign(self, data: bytes) -> bytes: return self._key.sign(data).signature
def test_service_auth_root_fails() -> None: node = sy.Device() msg = sy.ReprMessage(address=node.address) random_signing_key = SigningKey.generate() random_verify_key = random_signing_key.verify_key # root_only @service_auth(root_only=True) def process(node: sy.Device, msg: sy.ReprMessage, verify_key: VerifyKey) -> None: pass process(node=node, msg=msg, verify_key=node.root_verify_key) with pytest.raises(AuthorizationException, match="You are not Authorized to access this service"): process(node=node, msg=msg, verify_key=random_verify_key)
def create_role(current_user, role_fields, private_key=None): user_role = db.session.query(Role).get(current_user.role) private_key = SigningKey.generate() for field in expected_fields: if role_fields.get(field) is None: raise MissingRequestKeyError if user_role is None: raise RoleNotFoundError if not user_role.can_edit_roles: raise AuthorizationError new_role = Role(**role_fields) db.session.add(new_role) db.session.commit() return model_to_json(new_role)
def __init__(self, application_namespace): # Save the application namespace self.application_namespace = application_namespace # Generate a private key self.private_key = PrivateKey.generate() # Generate a signing key self.signing_key = SigningKey.generate() # Create subject for incoming payloads self.incoming_payload = rx.subject.Subject() # Create a set of reachable instances self.reachable_peers: Set[InstanceReference] = set() # Create subject for newly reachable instances self.incoming_greeting = rx.subject.Subject()
def startInvitation(self, petname, code, transports): #print "invite", petname, code.encode("hex") stretched = stretch(code) inviteKey = SigningKey(stretched) inviteID = inviteKey.verify_key.encode(Hex) mySigningKey = SigningKey.generate() myCIDkey = os.urandom(32) myTempPrivkey = PrivateKey.generate() # create my channel record tids = ",".join([str(tid) for tid in sorted(transports.keys())]) channel_key = PrivateKey.generate() pub_crec = { "channel_pubkey": channel_key.public_key.encode(Hex), "CID_key": myCIDkey.encode("hex"), "transports": transports.values(), } priv_data = { "my_signkey": mySigningKey.encode(Hex), "my_CID_key": myCIDkey.encode("hex"), "my_old_channel_privkey": channel_key.encode(Hex), "my_new_channel_privkey": channel_key.encode(Hex), "transport_ids": tids, } db = self.db c = db.execute("SELECT inviteID FROM invitations") if inviteID in [str(row[0]) for row in c.fetchall()]: raise CommandError("invitation code already in use") iid = db.insert("INSERT INTO `invitations`" " (code, petname, inviteKey," " inviteID," " myTempPrivkey, mySigningKey," " my_channel_record, my_private_channel_data," " myMessages, theirMessages, nextExpectedMessage)" " VALUES (?,?,?, ?, ?,?, ?,?, ?,?,?)", (code.encode("hex"), petname, stretched.encode("hex"), inviteID, myTempPrivkey.encode(Hex), mySigningKey.encode(Hex), json.dumps(pub_crec), json.dumps(priv_data), "", "", 1), "invitations") self.subscribe(inviteID) i = Invitation(iid, self.db, self) i.sendFirstMessage() self.db.commit()
def __init__(self, conf_file, privkey_file=None, elem_id=None): self.my_id = elem_id with open(conf_file, "rb") as f: dict_ = cbor.loads(f.read()) self.threshold = dict_["threshold"] self.logs = {} for log_id in dict_["logs"]: self.logs[log_id] = ConfElem(*dict_["logs"][log_id]) self.monitors = {} for monitor_id in dict_["monitors"]: self.monitors[monitor_id] = ConfElem( *dict_["monitors"][monitor_id]) self.privkey = None if privkey_file: with open(privkey_file, "rb") as f: self.privkey = SigningKey(f.read())
def test_reset_registeration(dispike_object: Dispike): from nacl.encoding import HexEncoder from nacl.signing import SigningKey _generated_signing_key = SigningKey.generate() verification_key = _generated_signing_key.verify_key.encode( encoder=HexEncoder) _current_dispike_object = Dispike( client_public_key=verification_key.decode(), bot_token="BOTTOKEN", application_id="APPID", ) assert _current_dispike_object.reset_registration( new_bot_token="NewBotToken", new_application_id="newApplicationId") == True assert _current_dispike_object._registrator.request_headers != dispike_object._registrator.request_headers assert _current_dispike_object._application_id != dispike_object._application_id
def from_keystore(cls, path, password): """ Load an account from a Keystore/JSON file :param path: the path to the keystore :param password: the password to decrypt the keystore :return: the account raise an error if the account cannot be opened """ try: with open(path) as fp: j = json.load(fp) raw_private_key = keystore_open(j, password) signing_key = SigningKey(seed=raw_private_key[0:32], encoder=RawEncoder) kp = Account(signing_key, signing_key.verify_key) return kp except CryptoError as e: raise ValueError(e)
class Signer(object): """ Only supported signing algorithm is ed25519 When using ed25519 algorithm, the secret is the base64-encoded private key """ def __init__(self, secret): if isinstance(secret, str): secret = secret.encode() self._key = SigningKey(secret, encoder=Base64Encoder) @property def algorithm(self): return "ed25519" def sign(self, data): if isinstance(data, str): data = data.encode(encode) signed = self._key.sign(data).signature return base64.b64encode(signed).decode()
def send_signed_post_request(*, data, ip_address, port, protocol, url_path): """ Sign data and send to recipient """ network_signing_key = get_environment_variable('NETWORK_SIGNING_KEY') signing_key = SigningKey(network_signing_key, encoder=HexEncoder) signed_request = generate_signed_request( data=data, nid_signing_key=signing_key ) node_address = format_address(ip_address=ip_address, port=port, protocol=protocol) url = f'{node_address}{url_path}' try: post(url=url, body=signed_request) except Exception as e: logger.exception(e)
def __init__(self, iid, db, manager): self.iid = iid self.db = db self.manager = manager c = self.db.execute("SELECT petname, inviteID, inviteKey," # 0,1,2 " theirTempPubkey," # 3 " nextExpectedMessage," # 4 " myMessages," # 5 " theirMessages" # 6 " FROM invitations WHERE id = ?", (iid,)) res = c.fetchone() if not res: raise KeyError("no pending Invitation for '%d'" % iid) self.petname = res[0] self.inviteID = res[1] self.inviteKey = SigningKey(res[2].decode("hex")) self.theirTempPubkey = None if res[3]: self.theirTempPubkey = PublicKey(res[3].decode("hex")) self.nextExpectedMessage = int(res[4]) self.myMessages = splitMessages(res[5]) self.theirMessages = splitMessages(res[6])
def maybe_generate_key(log, cbdir, privkey_path=u'node.key'): if not HAS_NACL: log.warn("Skipping node key generation - NaCl package not installed!") return from nacl.signing import SigningKey from nacl.encoding import HexEncoder privkey = None privkey_path = os.path.join(cbdir, privkey_path) if os.path.exists(privkey_path): # node private key seems to exist already .. check! if os.path.isfile(privkey_path): with open(privkey_path, 'r') as privkey_file: privkey = None # parse key file lines, looking for tag "ed25519-privkey" got_blankline = False for line in privkey_file.read().splitlines(): if line.strip() == '': got_blankline = True elif got_blankline: tag, value = line.split(':', 1) tag = tag.strip().lower() value = value.strip() if tag not in [u'private-key-ed25519', u'public-key-ed25519', u'machine-id', u'created-at', u'creator']: raise Exception("Invalid tag '{}' in node private key file {}".format(tag, privkey_path)) if tag == u'private-key-ed25519': privkey = value break if not privkey: raise Exception("Node private key file lacks a 'ed25519-privkey' tag!") # recreate a signing key from the base64 encoding privkey_obj = SigningKey(privkey, encoder=HexEncoder) pubkey = privkey_obj.verify_key.encode(encoder=HexEncoder).decode('ascii') log.debug("Node key already exists (public key: {})".format(pubkey)) else: raise Exception("Node private key path '{}' exists, but isn't a file".format(privkey_path)) else: # node private key does NOT yet exist: generate one privkey_obj = SigningKey.generate() privkey = privkey_obj.encode(encoder=HexEncoder).decode('ascii') privkey_created_at = utcnow() pubkey = privkey_obj.verify_key.encode(encoder=HexEncoder).decode('ascii') # for informational purposes, try to get a machine unique id thing .. machine_id = None try: # why this? see: http://0pointer.de/blog/projects/ids.html with open('/var/lib/dbus/machine-id', 'r') as f: machine_id = f.read().strip() except: pass # for informational purposes, try to identify the creator (user@hostname) creator = None try: creator = u'{}@{}'.format(getpass.getuser(), socket.gethostname()) except: pass # write out the private key file with open(privkey_path, 'w') as privkey_file: privkey_file.write(u'Crossbar.io private key for node authentication - KEEP THIS SAFE!\n\n') if creator: privkey_file.write(u'creator: {}\n'.format(creator)) privkey_file.write(u'created-at: {}\n'.format(privkey_created_at)) if machine_id: privkey_file.write(u'machine-id: {}\n'.format(machine_id)) privkey_file.write(u'public-key-ed25519: {}\n'.format(pubkey)) privkey_file.write(u'private-key-ed25519: {}\n'.format(privkey)) # set file mode to read only for owner # 384 (decimal) == 0600 (octal) - we use that for Py2/3 reasons os.chmod(privkey_path, 384) log.info("New node key generated!") return pubkey
class PrivateKeyProvider(object): """ Decrypts private keys. """ def __init__(self, key, passphrase: bytes): self.key = key # Secure! self.passphrase = passphrase self.sign = None self.encrypt = None def __enter__(self) -> typing.Tuple[PrivateKey, PrivateKey]: """ Provides a pair of private keys. """ # Derive the key from the passphrase. derived = util.derive_passphrase(self.passphrase) sign_box = SecretBox(derived) enc_box = SecretBox(derived) # Decrypt, using the two nonces. s_d = sign_box.decrypt(self.key._private_signing_seed, self.key._private_signing_nonce) e_d = enc_box.decrypt(self.key._private_key_raw, self.key._private_nonce) # Generate a SigningKey out of the seed. self.sign = SigningKey(s_d) self.encrypt = PrivateKey(e_d) # Update the key's public keys. if self.key._public_key is None: self.key._public_key = self.encrypt.public_key if self.key._public_signing_key is None: self.key._public_signing_key = self.sign.verify_key return self.encrypt, self.sign def __exit__(self, exc_type, exc_val, exc_tb): """ Re-encrypt. """ # Derive the key from the passphrase. derived = util.derive_passphrase(self.passphrase) # Generate two random nonces. nonce1 = random(SecretBox.NONCE_SIZE) nonce2 = random(SecretBox.NONCE_SIZE) sign_box = SecretBox(derived) enc_box = SecretBox(derived) s_p = self.sign.encode() e_p = self.encrypt.encode() s_e = sign_box.encrypt(s_p, nonce1) e_e = enc_box.encrypt(e_p, nonce2) # Update `self.key`. self.key._private_key_raw = e_e.ciphertext self.key._private_signing_key_raw = s_e.ciphertext # Bit of a mixed up name. self.key._private_nonce = e_e.nonce self.key._private_signing_nonce = s_e.nonce if exc_type is not None: raise exc_type(exc_val)
def maybe_generate_key(log, cbdir, privkey_path=u'key.priv', pubkey_path=u'key.pub'): if not HAS_NACL: log.warn("Skipping node key generation - NaCl package not installed!") return from nacl.signing import SigningKey from nacl.encoding import HexEncoder privkey = None pubkey = None privkey_path = os.path.join(cbdir, privkey_path) pubkey_path = os.path.join(cbdir, pubkey_path) if os.path.exists(privkey_path): # node private key seems to exist already .. check! tags = _parse_keyfile(privkey_path, private=True) if u'private-key-ed25519' not in tags: raise Exception("Node private key file lacks a 'private-key-ed25519' tag!") privkey = tags[u'private-key-ed25519'] # recreate a signing key from the base64 encoding privkey_obj = SigningKey(privkey, encoder=HexEncoder) pubkey = privkey_obj.verify_key.encode(encoder=HexEncoder).decode('ascii') # confirm we have the public key in the file, and that it is # correct if u'public-key-ed25519' in tags: if tags[u'public-key-ed25519'] != pubkey: raise Exception( ("Inconsistent key file '{}': 'public-key-ed25519' doesn't" " correspond to private-key-ed25519").format(privkey_path) ) log.debug("Node key already exists (public key: {})".format(pubkey)) if os.path.exists(pubkey_path): pubtags = _parse_keyfile(pubkey_path, private=False) if u'public-key-ed25519' not in pubtags: raise Exception( ("Pubkey file '{}' exists but lacks 'public-key-ed25519'" " tag").format(pubkey_path) ) if pubtags[u'public-key-ed25519'] != pubkey: raise Exception( ("Inconsistent key file '{}': 'public-key-ed25519' doesn't" " correspond to private-key-ed25519").format(pubkey_path) ) else: log.info("'{}' not found; re-creating from '{}'".format(pubkey_path, privkey_path)) tags = OrderedDict([ (u'creator', _creator()), (u'created-at', utcnow()), (u'machine-id', _machine_id()), (u'public-key-ed25519', pubkey), ]) msg = u'Crossbar.io public key for node authentication\n\n' _write_node_key(pubkey_path, tags, msg) else: # node private key does NOT yet exist: generate one privkey_obj = SigningKey.generate() privkey = privkey_obj.encode(encoder=HexEncoder).decode('ascii') pubkey = privkey_obj.verify_key.encode(encoder=HexEncoder).decode('ascii') # first, write the public file tags = OrderedDict([ (u'creator', _creator()), (u'created-at', utcnow()), (u'machine-id', _machine_id()), (u'public-key-ed25519', pubkey), ]) msg = u'Crossbar.io public key for node authentication\n\n' _write_node_key(pubkey_path, tags, msg) # now, add the private key and write the private file tags[u'private-key-ed25519'] = privkey msg = u'Crossbar.io private key for node authentication - KEEP THIS SAFE!\n\n' _write_node_key(privkey_path, tags, msg) log.info("New node key generated!") return pubkey
def _prepare_node_keys(self): from nacl.signing import SigningKey from nacl.encoding import HexEncoder # make sure CBDIR/.cdc exists # cdc_dir = os.path.join(self._cbdir, '.cdc') if os.path.isdir(cdc_dir): pass elif os.path.exists(cdc_dir): raise Exception(".cdc exists, but isn't a directory") else: os.mkdir(cdc_dir) self.log.info("CDC directory created") # load node ID, either from .cdc/node.id or from CDC_NODE_ID # def split_nid(nid_s): nid_c = nid_s.strip().split('@') if len(nid_c) != 2: raise Exception("illegal node principal '{}' - must follow the form <node id>@<management realm>".format(nid_s)) node_id, realm = nid_c # FIXME: regex check node_id and realm return node_id, realm nid_file = os.path.join(cdc_dir, 'node.id') node_id, realm = None, None if os.path.isfile(nid_file): with open(nid_file, 'r') as f: node_id, realm = split_nid(f.read()) elif os.path.exists(nid_file): raise Exception("{} exists, but isn't a file".format(nid_file)) else: if 'CDC_NODE_ID' in os.environ: node_id, realm = split_nid(os.environ['CDC_NODE_ID']) else: raise Exception("Neither node ID file {} exists nor CDC_NODE_ID environment variable set".format(nid_file)) # Load the node key, either from .cdc/node.key or from CDC_NODE_KEY. # The node key is a Ed25519 key in either raw format (32 bytes) or in # hex-encoded form (64 characters). # # Actually, what's loaded is not the secret Ed25519 key, but the _seed_ # for that key. Private keys are derived from this 32-byte (256-bit) # random seed value. It is thus the seed value which is sensitive and # must be protected. # skey_file = os.path.join(cdc_dir, 'node.key') skey = None if os.path.isfile(skey_file): # FIXME: check file permissions are 0600! # This value is read in here. skey_len = os.path.getsize(skey_file) if skey_len in (32, 64): with open(skey_file, 'r') as f: skey_seed = f.read() encoder = None if skey_len == 64: encoder = HexEncoder skey = SigningKey(skey_seed, encoder=encoder) self.log.info("Existing CDC node key loaded from {skey_file}.", skey_file=skey_file) else: raise Exception("invalid node key length {} (key must either be 32 raw bytes or hex encoded 32 bytes, hence 64 byte char length)") elif os.path.exists(skey_file): raise Exception("{} exists, but isn't a file".format(skey_file)) else: skey = SigningKey.generate() skey_seed = skey.encode(encoder=HexEncoder) with open(skey_file, 'w') as f: f.write(skey_seed) # set file mode to read only for owner # 384 (decimal) == 0600 (octal) - we use that for Py2/3 reasons os.chmod(skey_file, 384) self.log.info("New CDC node key {skey_file} generated.", skey_file=skey_file) return realm, node_id, skey
def test_initialize_with_generate(self): SigningKey.generate()
def command_invite(self, petname, maybe_code=None, reqid=None, override_transports=None, offer_mailbox=False, accept_mailbox_offer=False, _debug_when_done=None): #if offer_mailbox: # code = "mailbox-" + code if maybe_code: count = self.db.execute("SELECT COUNT(*) FROM addressbook" " WHERE invitation_state != ?" " AND invitation_code=?", (invitation.INVITE_COMPLETE, maybe_code) ).fetchone()[0] if count: raise CommandError("invitation code already in use") my_signkey = SigningKey.generate() channel_key = PrivateKey.generate() my_CID_key = os.urandom(32) base_transports = self.get_transports() if override_transports: base_transports = override_transports transports = self.individualize_transports(base_transports) channel = { "channel_pubkey": channel_key.public_key.encode(Hex), "CID_key": my_CID_key.encode("hex"), "transports": transports.values(), } payload = { "channel": channel } if offer_mailbox: tid = self.mailbox_server.allocate_transport(remote=True) payload["mailbox"] = self.mailbox_server.get_mailbox_record(tid) encoded_payload = json.dumps(payload).encode("utf-8") sigkeypayload = (b"i0:" + my_signkey.verify_key.encode() + my_signkey.sign(encoded_payload)) cid = self.db.insert( "INSERT INTO addressbook" " (petname, accept_mailbox_offer," " invitation_state, when_invited, invitation_code," " wormhole_payload," " next_outbound_seqnum, my_signkey," " my_CID_key, next_CID_token," " highest_inbound_seqnum," " my_old_channel_privkey," " my_new_channel_privkey)" " VALUES (?,?, ?,?,?, ?, ?,?, ?,?, ?, ?, ?)", (petname, accept_mailbox_offer, invitation.INVITE_WAITING_FOR_CODE, time.time(), maybe_code, sigkeypayload.encode("hex"), 1, my_signkey.encode(Hex), my_CID_key.encode("hex"), None, 0, channel_key.encode(Hex), channel_key.encode(Hex), # at beginning, old=new ), "addressbook", {"reqid": reqid}) i = self.im.create_invitation(cid) self.db.commit() self._activate_invitation(i, cid, _debug_when_done) return {"contact-id": cid, "petname": petname, "ok": "invitation for %s started: cid=%d" % (petname, cid)}
def init(server, username, keydir, action, message, recipients): """ SHSM CLI client. """ global serverurl serverurl = server if action == "register": master_signing_key = SigningKey.generate() device_signing_key = SigningKey.generate() device_private_key = PrivateKey.generate() enc_master_verify_key = master_signing_key.verify_key.encode(encoder=HexEncoder) register(username, enc_master_verify_key) # TODO: make sure keydir exists save_key(master_signing_key.encode(encoder=HexEncoder), keydir + "/master_signing_key") save_key(device_signing_key.encode(encoder=HexEncoder), keydir + "/device_signing_key") save_key(device_private_key.encode(encoder=HexEncoder), keydir + "/device_private_key") else: try: master_signing_key = SigningKey(load_key(keydir + "/master_signing_key"), encoder=HexEncoder) device_signing_key = SigningKey(load_key(keydir + "/device_signing_key"), encoder=HexEncoder) device_private_key = PrivateKey(load_key(keydir + "/device_private_key"), encoder=HexEncoder) except TypeError: print "bad key, exiting." exit() if action == "add-device": enc_device_verify_key = device_signing_key.verify_key.encode(encoder=HexEncoder) enc_signed_device_verify_key = b64encode(master_signing_key.sign(enc_device_verify_key)) enc_device_public_key = device_private_key.public_key.encode(encoder=HexEncoder) enc_signed_device_public_key = b64encode(master_signing_key.sign(enc_device_public_key)) add_device(username, enc_signed_device_verify_key, enc_signed_device_public_key) if action == "send-message": ephemeral_key = PrivateKey.generate() enc_ephemeral_public_key = b64encode( device_signing_key.sign(ephemeral_key.public_key.encode(encoder=HexEncoder)) ) # TODO:: should sign binary text, no? b"bob" destination_usernames = recipients.split(",") enc_dest_usernames = b64encode( device_signing_key.sign(json.dumps({"destination_usernames": destination_usernames})) ) symmetric_key = random(SecretBox.KEY_SIZE) symmetric_box = SecretBox(symmetric_key) nonce = random(SecretBox.NONCE_SIZE) msg_manifest = {} msg_manifest["recipients"] = {} msg_manifest["msg"] = b64encode(symmetric_box.encrypt(str(message), nonce)) for dest_user in destination_usernames: msg_manifest["recipients"][dest_user] = {} for recipient_key in get_recipient_keys( device_signing_key.verify_key.encode(encoder=HexEncoder), b64encode(device_signing_key.sign(str(dest_user))), ): # TODO:: should sign binary text, no? crypt_box = Box(ephemeral_key, recipient_key) nonce = random(Box.NONCE_SIZE) crypt_key = b64encode(crypt_box.encrypt(symmetric_key, nonce)) dest_key = recipient_key.encode(encoder=HexEncoder) msg_manifest["recipients"][dest_user][dest_key] = crypt_key enc_signed_crypt_msg = b64encode(device_signing_key.sign(json.dumps(msg_manifest))) send_message( device_signing_key.verify_key.encode(encoder=HexEncoder), enc_dest_usernames, enc_signed_crypt_msg, enc_ephemeral_public_key, ) if action == "get-messages": enc_device_verify_key = device_signing_key.verify_key.encode(encoder=HexEncoder) enc_signed_device_verify_key = b64encode(device_signing_key.sign(enc_device_verify_key)) messages = get_messages(enc_device_verify_key, enc_signed_device_verify_key) for message_public_key in messages["messages"].keys(): try: crypto_box = Box(device_private_key, PublicKey(b64decode(message_public_key), encoder=HexEncoder)) except TypeError: print "not a valid public key" exit() packed_msg = json.loads(messages["messages"][message_public_key]) msg_manifest = json.loads(b64decode(packed_msg["message_manifest"])) dest_pub_key = device_private_key.public_key.encode(encoder=HexEncoder) symmetric_key = crypto_box.decrypt(b64decode(msg_manifest["recipients"][username][dest_pub_key])) symmetric_box = SecretBox(symmetric_key) print ("From: %s\nMessage: %s") % ( packed_msg["reply_to"], symmetric_box.decrypt(b64decode(msg_manifest["msg"])), )
class Invitation: # This has a brief lifetime: one is created in response to the rendezvous # client discovering new messages for us, used for one reactor tick, then # dereferenced. It holds onto a few values during that tick (which may # process multiple messages for a single invitation, e.g. A's second poll # will receive both B-m1 and B-m2 together). But all persistent state # beyond that one tick is stored in the database. def __init__(self, iid, db, manager): self.iid = iid self.db = db self.manager = manager c = self.db.execute("SELECT petname, inviteID, inviteKey," # 0,1,2 " theirTempPubkey," # 3 " nextExpectedMessage," # 4 " myMessages," # 5 " theirMessages" # 6 " FROM invitations WHERE id = ?", (iid,)) res = c.fetchone() if not res: raise KeyError("no pending Invitation for '%d'" % iid) self.petname = res[0] self.inviteID = res[1] self.inviteKey = SigningKey(res[2].decode("hex")) self.theirTempPubkey = None if res[3]: self.theirTempPubkey = PublicKey(res[3].decode("hex")) self.nextExpectedMessage = int(res[4]) self.myMessages = splitMessages(res[5]) self.theirMessages = splitMessages(res[6]) def getAddressbookID(self): c = self.db.execute("SELECT addressbook_id FROM invitations" " WHERE id = ?", (self.iid,)) return c.fetchone()[0] def getMyTempPrivkey(self): c = self.db.execute("SELECT myTempPrivkey FROM invitations" " WHERE id = ?", (self.iid,)) return PrivateKey(c.fetchone()[0].decode("hex")) def getMySigningKey(self): c = self.db.execute("SELECT mySigningKey FROM invitations" " WHERE id = ?", (self.iid,)) return SigningKey(c.fetchone()[0].decode("hex")) def getMyPublicChannelRecord(self): c = self.db.execute("SELECT my_channel_record FROM invitations" " WHERE id = ?", (self.iid,)) return c.fetchone()[0] def getMyPrivateChannelData(self): c = self.db.execute("SELECT my_private_channel_data FROM invitations" " WHERE id = ?", (self.iid,)) return json.loads(c.fetchone()[0]) def sendFirstMessage(self): pub = self.getMyTempPrivkey().public_key.encode() self.send("i0:m1:"+pub) self.db.update("UPDATE invitations SET myMessages=? WHERE id=?", (",".join(self.myMessages), self.iid), "invitations", self.iid) # that will be commited by our caller def processMessages(self, messages): # These messages are neither version-checked nor signature-checked. # Also, we may have already processed some of them. #print "processMessages", messages #print " my", self.myMessages #print " theirs", self.theirMessages assert isinstance(messages, set), type(messages) assert None not in messages, messages assert None not in self.myMessages, self.myMessages assert None not in self.theirMessages, self.theirMessages # Send anything that didn't make it to the server. This covers the # case where we commit our outbound message in send() but crash # before finishing delivery. for m in self.myMessages - messages: #print "resending", m self.manager.sendToAll(self.inviteID, m) newMessages = messages - self.myMessages - self.theirMessages #print " %d new messages" % len(newMessages) if not newMessages: print " huh, no new messages, stupid rendezvous client" # check signatures, extract bodies. invalid messages kill the channel # and the invitation. MAYBE TODO: lose the one channel, keep using # the others. bodies = set() for m in newMessages: #print " new inbound message", m try: if not m.startswith("r0:"): print "unrecognized rendezvous message prefix" if not VALID_MESSAGE.search(m): raise CorruptChannelError() m = m[len("r0:"):].decode("hex") bodies.add(self.inviteKey.verify_key.verify(m)) except (BadSignatureError, CorruptChannelError) as e: print "channel %s is corrupt" % self.inviteID if isinstance(e, BadSignatureError): print " (bad sig)" self.unsubscribe(self.inviteID) # TODO: mark invitation as failed, destroy it return #print " new inbound bodies:", ", ".join([repr(b[:10])+" ..." for b in bodies]) # these handlers will update self.myMessages with sent messages, and # will increment self.nextExpectedMessage. We can handle multiple # (sequential) messages in a single pass. if self.nextExpectedMessage == 1: self.findPrefixAndCall("i0:m1:", bodies, self.processM1) # no elif here: self.nextExpectedMessage may have incremented if self.nextExpectedMessage == 2: self.findPrefixAndCall("i0:m2:", bodies, self.processM2) if self.nextExpectedMessage == 3: self.findPrefixAndCall("i0:m3:", bodies, self.processM3) self.db.update("UPDATE invitations SET" " myMessages=?," " theirMessages=?," " nextExpectedMessage=?" " WHERE id=?", (",".join(self.myMessages), ",".join(self.theirMessages | newMessages), self.nextExpectedMessage, self.iid), "invitations", self.iid) #print " db.commit" self.db.commit() def findPrefixAndCall(self, prefix, bodies, handler): for msg in bodies: if msg.startswith(prefix): return handler(msg[len(prefix):]) return None def send(self, msg, persist=True): #print "send", repr(msg[:10]), "..." signed = "r0:%s" % self.inviteKey.sign(msg).encode("hex") if persist: # m4-destroy is not persistent self.myMessages.add(signed) # will be persisted by caller # This will be added to the DB, and committed, by our caller, to # get it into the same transaction as the update to which inbound # messages we've processed. assert VALID_MESSAGE.search(signed), signed self.manager.sendToAll(self.inviteID, signed) def processM1(self, msg): #print "processM1", self.petname self.theirTempPubkey = PublicKey(msg) self.db.update("UPDATE invitations SET theirTempPubkey=?" " WHERE id=?", (self.theirTempPubkey.encode(Hex), self.iid), "invitations", self.iid) # theirTempPubkey will committed by our caller, in the same txn as # the message send my_privkey = self.getMyTempPrivkey() my_channel_record = self.getMyPublicChannelRecord() b = Box(my_privkey, self.theirTempPubkey) signedBody = b"".join([self.theirTempPubkey.encode(), my_privkey.public_key.encode(), my_channel_record.encode("utf-8")]) my_sign = self.getMySigningKey() body = b"".join([b"i0:m2a:", my_sign.verify_key.encode(), my_sign.sign(signedBody) ]) nonce = os.urandom(Box.NONCE_SIZE) nonce_and_ciphertext = b.encrypt(body, nonce) #print "ENCRYPTED n+c", len(nonce_and_ciphertext), nonce_and_ciphertext.encode("hex") #print " nonce", nonce.encode("hex") msg2 = "i0:m2:"+nonce_and_ciphertext self.send(msg2) self.nextExpectedMessage = 2 def processM2(self, msg): #print "processM2", repr(msg[:10]), "...", self.petname assert self.theirTempPubkey nonce_and_ciphertext = msg my_privkey = self.getMyTempPrivkey() b = Box(my_privkey, self.theirTempPubkey) #nonce = msg[:Box.NONCE_SIZE] #ciphertext = msg[Box.NONCE_SIZE:] #print "DECRYPTING n+ct", len(msg), msg.encode("hex") body = b.decrypt(nonce_and_ciphertext) if not body.startswith("i0:m2a:"): raise ValueError("expected i0:m2a:, got '%r'" % body[:20]) verfkey_and_signedBody = body[len("i0:m2a:"):] theirVerfkey = VerifyKey(verfkey_and_signedBody[:32]) signedBody = verfkey_and_signedBody[32:] body = theirVerfkey.verify(signedBody) check_myTempPubkey = body[:32] check_theirTempPubkey = body[32:64] their_channel_record_json = body[64:].decode("utf-8") #print " binding checks:" #print " check_myTempPubkey", check_myTempPubkey.encode("hex") #print " my real tempPubkey", my_privkey.public_key.encode(Hex) #print " check_theirTempPubkey", check_theirTempPubkey.encode("hex") #print " first theirTempPubkey", self.theirTempPubkey.encode(Hex) if check_myTempPubkey != my_privkey.public_key.encode(): raise ValueError("binding failure myTempPubkey") if check_theirTempPubkey != self.theirTempPubkey.encode(): raise ValueError("binding failure theirTempPubkey") them = json.loads(their_channel_record_json) me = self.getMyPrivateChannelData() addressbook_id = self.db.insert( "INSERT INTO addressbook" " (petname, acked," " next_outbound_seqnum, my_signkey," " their_channel_record_json," " my_CID_key, next_CID_token," " highest_inbound_seqnum," " my_old_channel_privkey, my_new_channel_privkey," " they_used_new_channel_key, their_verfkey)" " VALUES (?,?, " " ?,?," " ?," " ?,?," # my_CID_key, next_CID_token " ?," # highest_inbound_seqnum " ?,?," " ?,?)", (self.petname, 0, 1, me["my_signkey"], json.dumps(them), me["my_CID_key"], None, 0, me["my_old_channel_privkey"], me["my_new_channel_privkey"], 0, theirVerfkey.encode(Hex) ), "addressbook") self.db.update("UPDATE invitations SET addressbook_id=?" " WHERE id=?", (addressbook_id, self.iid), "invitations", self.iid) msg3 = "i0:m3:ACK-"+os.urandom(16) self.send(msg3) self.nextExpectedMessage = 3 def processM3(self, msg): #print "processM3", repr(msg[:10]), "..." if not msg.startswith("ACK-"): raise ValueError("bad ACK") cid = self.getAddressbookID() self.db.update("UPDATE addressbook SET acked=1 WHERE id=?", (cid,), "addressbook", cid ) self.db.delete("DELETE FROM invitations WHERE id=?", (self.iid,), "invitations", self.iid) # we no longer care about the channel msg4 = "i0:destroy:"+os.urandom(16) self.send(msg4, persist=False) self.manager.unsubscribe(self.inviteID)
def create_new_key(): # We use a signkey to get a 64bit key, instead of a 32bit key... # because nacl? key = SigningKey.generate() return str(key._signing_key)
def maybe_generate_key(self, cbdir, privkey_path=u'key.priv', pubkey_path=u'key.pub'): privkey_path = os.path.join(cbdir, privkey_path) pubkey_path = os.path.join(cbdir, pubkey_path) if os.path.exists(privkey_path): # node private key seems to exist already .. check! priv_tags = _parse_keyfile(privkey_path, private=True) for tag in [u'creator', u'created-at', u'machine-id', u'public-key-ed25519', u'private-key-ed25519']: if tag not in priv_tags: raise Exception("Corrupt node private key file {} - {} tag not found".format(privkey_path, tag)) privkey_hex = priv_tags[u'private-key-ed25519'] privkey = SigningKey(privkey_hex, encoder=HexEncoder) pubkey = privkey.verify_key pubkey_hex = pubkey.encode(encoder=HexEncoder).decode('ascii') if priv_tags[u'public-key-ed25519'] != pubkey_hex: raise Exception( ("Inconsistent node private key file {} - public-key-ed25519 doesn't" " correspond to private-key-ed25519").format(pubkey_path) ) if os.path.exists(pubkey_path): pub_tags = _parse_keyfile(pubkey_path, private=False) for tag in [u'creator', u'created-at', u'machine-id', u'public-key-ed25519']: if tag not in pub_tags: raise Exception("Corrupt node public key file {} - {} tag not found".format(pubkey_path, tag)) if pub_tags[u'public-key-ed25519'] != pubkey_hex: raise Exception( ("Inconsistent node public key file {} - public-key-ed25519 doesn't" " correspond to private-key-ed25519").format(pubkey_path) ) else: self.log.info( "Node public key file {pub_path} not found - re-creating from node private key file {priv_path}", pub_path=pubkey_path, priv_path=privkey_path, ) pub_tags = OrderedDict([ (u'creator', priv_tags[u'creator']), (u'created-at', priv_tags[u'created-at']), (u'machine-id', priv_tags[u'machine-id']), (u'public-key-ed25519', pubkey_hex), ]) msg = u'Crossbar.io node public key\n\n' _write_node_key(pubkey_path, pub_tags, msg) self.log.debug("Node key already exists (public key: {hex})", hex=pubkey_hex) else: # node private key does not yet exist: generate one privkey = SigningKey.generate() privkey_hex = privkey.encode(encoder=HexEncoder).decode('ascii') pubkey = privkey.verify_key pubkey_hex = pubkey.encode(encoder=HexEncoder).decode('ascii') # first, write the public file tags = OrderedDict([ (u'creator', _creator()), (u'created-at', utcnow()), (u'machine-id', _machine_id()), (u'public-key-ed25519', pubkey_hex), ]) msg = u'Crossbar.io node public key\n\n' _write_node_key(pubkey_path, tags, msg) # now, add the private key and write the private file tags[u'private-key-ed25519'] = privkey_hex msg = u'Crossbar.io node private key - KEEP THIS SAFE!\n\n' _write_node_key(privkey_path, tags, msg) self.log.info("New node key pair generated!") # fix file permissions on node public/private key files # note: we use decimals instead of octals as octal literals have changed between Py2/3 # if os.stat(pubkey_path).st_mode & 511 != 420: # 420 (decimal) == 0644 (octal) os.chmod(pubkey_path, 420) self.log.info("File permissions on node public key fixed!") if os.stat(privkey_path).st_mode & 511 != 384: # 384 (decimal) == 0600 (octal) os.chmod(privkey_path, 384) self.log.info("File permissions on node private key fixed!") self._node_key = cryptosign.SigningKey(privkey) return pubkey_hex
def key_generate(): return SigningKey.generate() def key_test( msg='test',