Beispiel #1
0
 def sign(self, key):
     """
     Signs this block with the given key
     :param key: the key to sign this block with
     """
     crypto = ECCrypto()
     self.signature = crypto.create_signature(key, self.pack(signature=False))
def get_public_key(private_key):
    """
    Get the public key pertaining to a private_key
    :param private_key: The private key, encoded in HEX
    :return: Returns the public key encoded in HEX
    """
    eccrypto = ECCrypto()
    try:
        if eccrypto.is_valid_private_bin(private_key.decode("HEX")):
            priv = eccrypto.key_from_private_bin(private_key.decode("HEX"))
            return priv.pub().key_to_bin().encode("HEX")
        return None
    except TypeError:
        return None
Beispiel #3
0
    def sign(self, api):
        """
        Sign a model by hashing its contents and signing this hash.
        """
        if not self.id:
            raise RuntimeError("Can't sign an unsaved model")

        ec = ECCrypto()
        hash = self.generate_sha1_hash()

        private_key = api.db.backend.get_option('user_key_priv')
        public_key = api.db.backend.get_option('user_key_pub')
        signing_key = ec.key_from_private_bin(private_key.decode('HEX'))

        self._signature = ec.create_signature(signing_key, hash)
        self._signer = public_key
        self._time_signed = int(time.time())

        self.post_or_put(api.db)
def main():
    eccrypto = ECCrypto()

    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)
    parser.add_argument(
        "curves",
        metavar="CURVE",
        nargs="+",
        choices=sorted([str(curve) for curve in eccrypto.security_levels]),
        help="EC curves to create")
    args = parser.parse_args()

    create_key(eccrypto, (unicode(curve) for curve in args.curves))
Beispiel #5
0
        def run():
            crypto = ECCrypto()
            dispersy = Dispersy(
                StandaloneEndpoint(options["port"], options["ip"]),
                options["statedir"], u'dispersy.db', crypto)
            if not dispersy.start():
                raise RuntimeError("Unable to start Dispersy")
            master_member = MarketCommunity.get_master_members(dispersy)[0]
            my_member = dispersy.get_member(private_key=crypto.key_to_bin(
                crypto.generate_key(u"curve25519")))
            MarketCommunity.init_community(dispersy, master_member, my_member)

            self._stopping = False

            def signal_handler(sig, frame):
                logger.info("Received signal '%s' in %s (shutting down)" %
                            (sig, frame))
                if not self._stopping:
                    self._stopping = True
                    dispersy.stop()
                    reactor.stop()

            signal.signal(signal.SIGINT, signal_handler)
            signal.signal(signal.SIGTERM, signal_handler)
    def __init__(self,
                 endpoint,
                 working_directory,
                 database_filename=u"dispersy.db",
                 crypto=ECCrypto()):
        """Provide hooks into the endpoint, otherwise equal to
            the normal Dispersy() constructor.

            Hooks into:
                - Endpoint socket data loop: to establish local port (/peer id)
                - Endpoint packet handler: to log data between peer ids
        """
        self.myid = endpoint._port

        # Eavesdrop on the listen server connection accepting loop
        pt_ep_loop = endpoint._loop
        funcType = type(StandaloneEndpoint._loop)

        def epLoopMim(eself):
            self.myid = eself._port  # This can change at this point, update it accordingly
            pt_ep_loop()

        endpoint._loop = funcType(epLoopMim, endpoint, StandaloneEndpoint)

        # Eavesdrop on the packet delegator
        pt_ep_data_came_in = endpoint.dispersythread_data_came_in
        funcType = type(StandaloneEndpoint.dispersythread_data_came_in)

        def epPacketRcvMim(eself, packets, timestamp, cache=True):
            fakepackets = []
            for sock_addr, data in packets:
                if data.startswith("dpvizidrq"):
                    # On an id request, log our id sending to the id of the
                    # requester
                    community_name = data[9:data.index(',')]
                    oid = int(data[data.index(',') + 1:])
                    report_event(
                        VD_EVT_COMMUNICATION(self.myid, oid, community_name))
                else:
                    # On normal data, request the other's id so we can log
                    # communication
                    try:
                        if data[22] != chr(
                                248):  # dispersy-identity has no community
                            community_name = type(
                                self.get_community(data[2:22], False,
                                                   False)).__name__
                            request = "dpvizidrq" + \
                                community_name + "," + str(self.myid)
                            try:
                                eself._socket.sendto(request, sock_addr)
                            except socket.error:
                                with eself._sendqueue_lock:
                                    did_have_senqueue = bool(eself._sendqueue)
                                    eself._sendqueue.append(
                                        (time(), candidate.sock_addr, request))
                                if not did_have_senqueue:
                                    eself._process_sendqueue()
                    except CommunityNotFoundException:
                        pass  # We have discovered external communities, ignore these

                    fakepackets.append((sock_addr, data))
            # If the incoming packets are more than VisualDispersy id requests
            # forward them to the actual Dispersy object.
            if len(fakepackets) > 0:
                pt_ep_data_came_in(fakepackets, timestamp, cache)

        endpoint.dispersythread_data_came_in = funcType(
            epPacketRcvMim, endpoint, StandaloneEndpoint)

        # Actually init Dispersy with our modified endpoint
        super(VisualDispersy, self).__init__(endpoint, working_directory,
                                             database_filename, crypto)
Beispiel #7
0
 def signature_valid(cls, obj):
     ec = ECCrypto()
     signing_key = ec.key_from_public_bin(obj._signer.decode("HEX"))
     signature_valid = ec.is_valid_signature(signing_key, obj.generate_sha1_hash(), obj.signature)
     return signature_valid
Beispiel #8
0
    def validate(self, database):
        """
        Validates this block against what is known in the database
        :param database: the database to check against
        :return: A tuple consisting of a ValidationResult and a list of user string errors
        """

        # we start off thinking everything is hunky dory
        result = [ValidationResult.valid]
        errors = []
        crypto = ECCrypto()

        # short cut for invalidating so we don't have repeating similar code for every error.
        # this is also the reason result is a list, we need a mutable container. Assignments in err are limited to its
        # scope. So setting result directly is not possible.
        def err(reason):
            result[0] = ValidationResult.invalid
            errors.append(reason)

        # Step 1: get all related blocks from the database.
        # The validity of blocks is immutable. Once they are accepted they cannot change validation result. In such
        # cases subsequent blocks can get validation errors and will not get inserted into the database. Thus we can
        # assume that all retrieved blocks are not invalid themselves. Blocks can get inserted into the database in any
        # order, so we need to find successors, predecessors as well as the block itself and its linked block.
        blk = database.get(self.public_key, self.sequence_number)
        link = database.get_linked(self)
        prev_blk = database.get_block_before(self)
        next_blk = database.get_block_after(self)

        # Step 2: determine the maximum validation level
        # Depending on the blocks we get from the database, we can decide to reduce the validation level. We must do
        # this prior to flagging any errors. This way we are only ever reducing the validation level without having to
        # resort to min()/max() every time we set it. We first determine some booleans to make everything readable.
        is_genesis = self.sequence_number == GENESIS_SEQ or self.previous_hash == GENESIS_HASH
        is_prev_gap = prev_blk.sequence_number != self.sequence_number - 1 if prev_blk else True
        is_next_gap = next_blk.sequence_number != self.sequence_number + 1 if next_blk else True
        if not prev_blk and not next_blk:
            # Is this block a non genesis block? If so, we know nothing about this public key, else pretend the
            # prev_blk exists
            if not is_genesis:
                result[0] = ValidationResult.no_info
            else:
                # We pretend prev_blk exists. This leaves us with next missing, which means partial-next at best.
                result[0] = ValidationResult.partial_next
        elif not prev_blk and next_blk:
            # Is this block a non genesis block?
            if not is_genesis:
                # We are really missing prev_blk. So now partial-prev at best.
                result[0] = ValidationResult.partial_previous
                if is_next_gap:
                    # Both sides are unknown or non-contiguous return a full partial result.
                    result[0] = ValidationResult.partial
            elif is_next_gap:
                # This is a genesis block, so the missing previous is expected. If there is a gap to the next block
                # this reduces the validation result to partial-next
                result[0] = ValidationResult.partial_next
        elif prev_blk and not next_blk:
            # We are missing next_blk, so now partial-next at best.
            result[0] = ValidationResult.partial_next
            if is_prev_gap:
                # Both sides are unknown or non-contiguous return a full partial result.
                result[0] = ValidationResult.partial
        else:
            # both sides have known blocks, see if there are gaps
            if is_prev_gap and is_next_gap:
                result[0] = ValidationResult.partial
            elif is_prev_gap:
                result[0] = ValidationResult.partial_previous
            elif is_next_gap:
                result[0] = ValidationResult.partial_next

        # Step 3: validate that the block is sane, including the validity of the transaction
        # Some basic self tests. It is possible to violate these when constructing a block in code or getting a block
        # from the database. The wire format is such that it impossible to hit many of these for blocks that went over
        # the network.
        tx_validate_res, tx_errors = self.validate_transaction(database)
        if tx_validate_res != ValidationResult.valid:
            result[0] = tx_validate_res
            errors += tx_errors

        if self.sequence_number < GENESIS_SEQ:
            err("Sequence number is prior to genesis")
        if self.link_sequence_number < GENESIS_SEQ and self.link_sequence_number != UNKNOWN_SEQ:
            err("Link sequence number not empty and is prior to genesis")
        if not crypto.is_valid_public_bin(self.public_key):
            err("Public key is not valid")
        else:
            # If the public key is valid, we can use it to check the signature. We want just a yes/no answer here, and
            # we want to keep checking for more errors, so just catch all packing exceptions and err() if any happen.
            try:
                pck = self.pack(signature=False)
            except:
                pck = None
            if pck is None or not crypto.is_valid_signature(
                    crypto.key_from_public_bin(self.public_key), pck, self.signature):
                err("Invalid signature")
        if not crypto.is_valid_public_bin(self.link_public_key):
            err("Linked public key is not valid")
        if self.public_key == self.link_public_key:
            # Blocks to self serve no purpose and are thus invalid.
            err("Self signed block")
        if is_genesis:
            if self.sequence_number == GENESIS_SEQ and self.previous_hash != GENESIS_HASH:
                err("Sequence number implies previous hash should be Genesis ID")
            if self.sequence_number != GENESIS_SEQ and self.previous_hash == GENESIS_HASH:
                err("Sequence number implies previous hash should not be Genesis ID")

        # Step 4: does the database already know about this block? If so it should be equal or else we caught a
        # branch in someones trustchain.
        if blk:
            # Sanity check to see if the database returned the expected block, we want to cover all our bases before
            # crying wolf and making a fraud claim.
            assert blk.public_key == self.public_key and blk.sequence_number == self.sequence_number, \
                "Database returned unexpected block"
            if blk.link_public_key != self.link_public_key:
                err("Link public key does not match known block")
            if blk.link_sequence_number != self.link_sequence_number:
                err("Link sequence number does not match known block")
            if blk.previous_hash != self.previous_hash:
                err("Previous hash does not match known block")
            if blk.signature != self.signature:
                err("Signature does not match known block")
            # if the known block is not equal, and the signatures are valid, we have a double signed PK/seq. Fraud!
            if self.hash != blk.hash and "Invalid signature" not in errors and "Public key is not valid" not in errors:
                err("Double sign fraud")

        # Step 5: does the database have the linked block? If so do the values match up? If the values do not match up
        # someone comitted fraud, but it is impossible to decide who. So we just invalidate the block that is the latter
        # to get validated. We can also detect double counter sign fraud at this point.
        if link:
            # Sanity check to see if the database returned the expected block, we want to cover all our bases before
            # crying wolf and making a fraud claim.
            assert link.public_key == self.link_public_key and \
                   (link.link_sequence_number == self.sequence_number or
                    link.sequence_number == self.link_sequence_number), \
                   "Database returned unexpected block"
            if self.public_key != link.link_public_key:
                err("Public key mismatch on linked block")
            elif self.link_sequence_number != UNKNOWN_SEQ:
                # self counter signs another block (link). If link has a linked block that is not equal to self,
                # then self is fraudulent, since it tries to countersign a block that is already countersigned
                linklinked = database.get_linked(link)
                if linklinked is not None and linklinked.hash != self.hash:
                    err("Double countersign fraud")

        # Step 6: Did we get blocks from the database before or after self? They should be checked for violations too.
        if prev_blk:
            # Sanity check of the block the database gave us.
            assert prev_blk.public_key == self.public_key and prev_blk.sequence_number < self.sequence_number,\
                "Database returned unexpected block"
            if not is_prev_gap and prev_blk.hash != self.previous_hash:
                err("Previous hash is not equal to the hash id of the previous block")
                # Is this fraud? It is certainly an error, but fixing it would require a different signature on the same
                # sequence number which is fraud.

        if next_blk:
            # Sanity check of the block the database gave us.
            assert next_blk.public_key == self.public_key and next_blk.sequence_number > self.sequence_number,\
                "Database returned unexpected block"
            if not is_next_gap and next_blk.previous_hash != self.hash:
                err("Next hash is not equal to the hash id of the block")
                # Again, this might not be fraud, but fixing it can only result in fraud.

        return result[0], errors