Exemple #1
0
def encode_memo(priv, pub, nonce, message, **kwargs):
    """ Encode a message with a shared secret between Alice and Bob

        :param PrivateKey priv: Private Key (of Alice)
        :param PublicKey pub: Public Key (of Bob)
        :param int nonce: Random nonce
        :param str message: Memo message
        :return: Encrypted message
        :rtype: hex
    """
    shared_secret = get_shared_secret(priv, pub)

    aes, check = init_aes(shared_secret, nonce)
    raw = py23_bytes(message, 'utf8')
    # Padding
    BS = 16
    if len(raw) % BS:
        raw = _pad(raw, BS)
    # Encryption
    cipher = hexlify(aes.encrypt(raw)).decode('ascii')
    prefix = kwargs.pop("prefix", default_prefix)
    s = {
        "from": format(priv.pubkey, prefix),
        "to": format(pub, prefix),
        "nonce": nonce,
        "check": check,
        "encrypted": cipher,
        "prefix": prefix
    }
    tx = Memo(**s)
    return "#" + base58encode(hexlify(py23_bytes(tx)).decode("ascii"))
Exemple #2
0
 def test_bytes_int(self):
     """
     In Py3, bytes(int) -> bytes object of size given by the parameter initialized with null
     """
     self.assertEqual(py23_bytes(5), b'\x00\x00\x00\x00\x00')
     # Test using newint:
     self.assertEqual(py23_bytes(int(5)), b'\x00\x00\x00\x00\x00')
     self.assertTrue(isinstance(py23_bytes(int(5)), bytes_types))
Exemple #3
0
    def test_isinstance_bytes_subclass(self):
        """
        Issue #89
        """
        value = py23_bytes(b'abc')

        class Magic():
            def __bytes__(self):
                return py23_bytes(b'abc')

        self.assertEqual(value, py23_bytes(Magic()))
Exemple #4
0
 def test_bytes_encoding_arg_non_kwarg(self):
     """
     As above, but with a positional argument
     """
     u = u'Unicode string: \u5b54\u5b50'
     b = py23_bytes(u, 'utf-8')
     self.assertEqual(b, u.encode('utf-8'))
Exemple #5
0
 def test_bytes_encoding_arg(self):
     """
     The bytes class has changed in Python 3 to accept an
     additional argument in the constructor: encoding.
     It would be nice to support this without breaking the
     isinstance(..., bytes) test below.
     """
     u = u'Unicode string: \u5b54\u5b50'
     b = py23_bytes(u, encoding='utf-8')
     self.assertEqual(b, u.encode('utf-8'))
Exemple #6
0
    def verify(self, pubkeys=[], chain=None, recover_parameter=False):
        """Returned pubkeys have to be checked if they are existing"""
        if not chain:
            raise
        chain_params = self.getChainParams(chain)
        self.deriveDigest(chain)
        signatures = self.data["signatures"].data
        pubKeysFound = []

        for signature in signatures:
            if recover_parameter:
                p = verify_message(
                    self.message,
                    py23_bytes(signature)
                )
            else:
                p = None
            if p is None:
                for i in range(4):
                    try:
                        p = verify_message(
                            self.message,
                            py23_bytes(signature),
                            recover_parameter=i
                        )
                        phex = hexlify(p).decode('ascii')
                        pubKeysFound.append(phex)
                    except Exception:
                        p = None
            else:
                phex = hexlify(p).decode('ascii')
                pubKeysFound.append(phex)

        for pubkey in pubkeys:
            if not isinstance(pubkey, PublicKey):
                raise Exception("Pubkeys must be array of 'PublicKey'")

            k = pubkey.unCompressed()[2:]
            if k not in pubKeysFound and repr(pubkey) not in pubKeysFound:
                k = PublicKey(PublicKey(k).compressed())
                f = format(k, chain_params["prefix"])
                raise Exception("Signature for %s missing!" % f)
        return pubKeysFound
Exemple #7
0
 def doit(self, printWire=False, ops=None):
     if ops is None:
         ops = [Operation(self.op)]
     tx = Signed_Transaction(ref_block_num=self.ref_block_num,
                             ref_block_prefix=self.ref_block_prefix,
                             expiration=self.expiration,
                             operations=ops)
     tx = tx.sign([self.wif], chain=self.prefix)
     tx.verify([PrivateKey(self.wif, prefix=u"DWB").pubkey], self.prefix)
     txWire = hexlify(py23_bytes(tx)).decode("ascii")
Exemple #8
0
 def hash_op(event):
     """ This method generates a hash of blockchain operation. """
     if isinstance(event, dict) and "type" in event and "value" in event:
         op_type = event["type"]
         if len(op_type) > 10 and op_type[len(op_type) -
                                          10:] == "_operation":
             op_type = op_type[:-10]
         op = event["value"]
         event = [op_type, op]
     data = json.dumps(event, sort_keys=True)
     return hashlib.sha1(py23_bytes(data, 'utf-8')).hexdigest()
Exemple #9
0
    def __init__(self, url="https://api.dsite.io", dpay_instance=None):
        """ Initialize a Conveyor instance
            :param str url: (optional) URL to the dSite API, defaults to
                https://api.dsite.io
            :param dpaygo.dpay.DPay dpay_instance: DPay instance

        """

        self.url = url
        self.dpay = dpay_instance or shared_dpay_instance()
        self.id = 0
        self.ENCODING = 'utf-8'
        self.TIMEFORMAT = '%Y-%m-%dT%H:%M:%S.%f'
        self.K = hashlib.sha256(py23_bytes('dpay_jsonrpc_auth',
                                           self.ENCODING)).digest()
Exemple #10
0
 def test_sign_message(self, module):
     if module == "cryptography":
         if not ecda.CRYPTOGRAPHY_AVAILABLE:
             return
         ecda.SECP256K1_MODULE = "cryptography"
     elif module == "secp256k1":
         if not ecda.SECP256K1_AVAILABLE:
             return
         ecda.SECP256K1_MODULE = "secp256k1"
     else:
         ecda.SECP256K1_MODULE = module
     pub_key = py23_bytes(repr(PrivateKey(wif).pubkey), "latin")
     signature = ecda.sign_message("Foobar", wif)
     pub_key_sig = ecda.verify_message("Foobar", signature)
     self.assertEqual(hexlify(pub_key_sig), pub_key)
Exemple #11
0
    def prehash_message(self, timestamp, account, method, params, nonce):
        """ Prepare a hash for the dSite API request with SHA256 according
            to https://github.com/dpays/dpay-rpc-auth
            Hashing of `second` is then done inside `ecdsasig.sign_message()`.

            :param str timestamp: valid iso8601 datetime ending in "Z"
            :param str account: valid dPay blockchain account name
            :param str method: Conveyor method name to be called
            :param bytes param: base64 encoded request parameters
            :param bytes nonce: random 8 bytes

        """
        first = hashlib.sha256(
            py23_bytes(timestamp + account + method + params, self.ENCODING))
        return self.K + first.digest() + nonce
Exemple #12
0
    def id(self):
        """ The transaction id of this transaction
        """
        # Store signatures temporarily since they are not part of
        # transaction id
        sigs = self.data["signatures"]
        self.data.pop("signatures", None)

        # Generage Hash of the seriliazed version
        h = hashlib.sha256(py23_bytes(self)).digest()

        # recover signatures
        self.data["signatures"] = sigs

        # Return properly truncated tx hash
        return hexlify(h[:20]).decode("ascii")
Exemple #13
0
    def deriveDigest(self, chain):
        chain_params = self.getChainParams(chain)
        # Chain ID
        self.chainid = chain_params["chain_id"]

        # Do not serialize signatures
        sigs = self.data["signatures"]
        self.data["signatures"] = []

        # Get message to sign
        #   bytes(self) will give the wire formated data according to
        #   GrapheneObject and the data given in __init__()
        self.message = unhexlify(self.chainid) + py23_bytes(self)
        self.digest = hashlib.sha256(self.message).digest()

        # restore signatures
        self.data["signatures"] = sigs
Exemple #14
0
def decode_memo(priv, message):
    """ Decode a message with a shared secret between Alice and Bob

        :param PrivateKey priv: Private Key (of Bob)
        :param base58encoded message: Encrypted Memo message
        :return: Decrypted message
        :rtype: str
        :raise ValueError: if message cannot be decoded as valid UTF-8
               string
    """
    # decode structure
    raw = base58decode(message[1:])
    from_key = PublicKey(raw[:66])
    raw = raw[66:]
    to_key = PublicKey(raw[:66])
    raw = raw[66:]
    nonce = str(struct.unpack_from("<Q", unhexlify(raw[:16]))[0])
    raw = raw[16:]
    check = struct.unpack_from("<I", unhexlify(raw[:8]))[0]
    raw = raw[8:]
    cipher = raw

    if repr(to_key) == repr(priv.pubkey):
        shared_secret = get_shared_secret(priv, from_key)
    elif repr(from_key) == repr(priv.pubkey):
        shared_secret = get_shared_secret(priv, to_key)
    else:
        raise ValueError("Incorrect PrivateKey")

    # Init encryption
    aes, checksum = init_aes(shared_secret, nonce)

    # Check
    if not check == checksum:
        raise AssertionError("Checksum failure")

    # Encryption
    # remove the varint prefix (FIXME, long messages!)
    message = cipher[2:]
    message = aes.decrypt(unhexlify(py23_bytes(message, 'ascii')))
    try:
        return _unpad(message.decode('utf8'), 16)
    except:  # noqa FIXME(sneak)
        raise ValueError(message)
Exemple #15
0
    def upload(self, image, account, image_name=None):
        """ Uploads an image

            :param str/bytes image: path to the image or image in bytes representation which should be uploaded
            :param str account: Account which is used to upload. A posting key must be provided.
            :param str image_name: optional

            .. code-block:: python

                from dpaygo import DPay
                from dpaygo.imageuploader import ImageUploader
                stm = DPay(keys=["5xxx"]) # private posting key
                iu = ImageUploader(dpay_instance=stm)
                iu.upload("path/to/image.png", "account_name") # "private posting key belongs to account_name

        """
        account = Account(account, dpay_instance=self.dpay)
        if "posting" not in account:
            account.refresh()
        if "posting" not in account:
            raise AssertionError("Could not access posting permission")
        for authority in account["posting"]["key_auths"]:
            posting_wif = self.dpay.wallet.getPrivateKeyForPublicKey(authority[0])

        if isinstance(image, string_types):
            image_data = open(image, 'rb').read()
        elif isinstance(image, io.BytesIO):
            image_data = image.read()
        else:
            image_data = image

        message = py23_bytes(self.challenge, "ascii") + image_data
        signature = sign_message(message, posting_wif)
        signature_in_hex = hexlify(signature).decode("ascii")

        files = {image_name or 'image': image_data}
        url = "%s/%s/%s" % (
            self.base_url,
            account["name"],
            signature_in_hex
        )
        r = requests.post(url, files=files)
        return r.json()
Exemple #16
0
def init_aes_bts(shared_secret, nonce):
    """ Initialize AES instance

        :param hex shared_secret: Shared Secret to use as encryption key
        :param int nonce: Random nonce
        :return: AES instance
        :rtype: AES

    """
    # Shared Secret
    ss = hashlib.sha512(unhexlify(shared_secret)).digest()
    # Seed
    seed = py23_bytes(str(nonce), 'ascii') + hexlify(ss)
    seed_digest = hexlify(hashlib.sha512(seed).digest()).decode('ascii')
    # Check'sum'
    check = hashlib.sha256(unhexlify(seed_digest)).digest()
    check = struct.unpack_from("<I", check[:4])[0]
    # AES
    key = unhexlify(seed_digest[0:64])
    iv = unhexlify(seed_digest[64:96])
    return AES.new(key, AES.MODE_CBC, iv)
Exemple #17
0
    def _request(self, account, method, params, key):
        """Assemble the request, hash it, sign it and send it to the Conveyor
            instance. Returns the server response as JSON.

            :param str account: account name
            :param str method: dSite API method name to be called
            :param dict params: request parameters as `dict`
            :param str key: dPay posting key for signing

        """
        params_bytes = py23_bytes(json.dumps(params), self.ENCODING)
        params_enc = base64.b64encode(params_bytes).decode(self.ENCODING)
        timestamp = datetime.utcnow().strftime(self.TIMEFORMAT)[:-3] + "Z"
        nonce_int = random.getrandbits(64)
        nonce_bytes = struct.pack('>Q', nonce_int)  # 64bit ULL, big endian
        nonce_str = "%016x" % (nonce_int)

        message = self.prehash_message(timestamp, account, method, params_enc,
                                       nonce_bytes)
        signature = sign_message(message, key)
        signature_hex = hexlify(signature).decode(self.ENCODING)

        request = {
            "jsonrpc": "2.0",
            "id": self.id,
            "method": method,
            "params": {
                "__signed": {
                    "account": account,
                    "nonce": nonce_str,
                    "params": params_enc,
                    "signatures": [signature_hex],
                    "timestamp": timestamp
                }
            }
        }
        r = requests.post(self.url, data=json.dumps(request))
        self.id += 1
        return r.json()
Exemple #18
0
def encode_memo_bts(priv, pub, nonce, message):
    """ Encode a message with a shared secret between Alice and Bob

        :param PrivateKey priv: Private Key (of Alice)
        :param PublicKey pub: Public Key (of Bob)
        :param int nonce: Random nonce
        :param str message: Memo message
        :return: Encrypted message
        :rtype: hex

    """
    shared_secret = get_shared_secret(priv, pub)
    aes = init_aes_bts(shared_secret, nonce)
    # Checksum
    raw = py23_bytes(message, 'utf8')
    checksum = hashlib.sha256(raw).digest()
    raw = (checksum[0:4] + raw)
    # Padding
    BS = 16
    # FIXME: this adds 16 bytes even if not required
    if len(raw) % BS:
        raw = _pad(raw, BS)
    # Encryption
    return hexlify(aes.encrypt(raw)).decode('ascii')
Exemple #19
0
def decode_memo_bts(priv, pub, nonce, message):
    """ Decode a message with a shared secret between Alice and Bob

        :param PrivateKey priv: Private Key (of Bob)
        :param PublicKey pub: Public Key (of Alice)
        :param int nonce: Nonce used for Encryption
        :param bytes message: Encrypted Memo message
        :return: Decrypted message
        :rtype: str
        :raise ValueError: if message cannot be decoded as valid UTF-8
               string

    """
    shared_secret = get_shared_secret(priv, pub)
    aes = init_aes_bts(shared_secret, nonce)
    # Encryption
    raw = py23_bytes(message, 'ascii')
    cleartext = aes.decrypt(unhexlify(raw))
    # TODO, verify checksum
    message = cleartext[4:]
    try:
        return _unpad(message.decode('utf8'), 16)
    except Exception:
        raise ValueError(message)
Exemple #20
0
 def deriveChecksum(self, s):
     """ Derive the checksum
     """
     checksum = hashlib.sha256(py23_bytes(s, "ascii")).hexdigest()
     return checksum[:4]
Exemple #21
0
 def test_bytes_is_bytes(self):
     b = py23_bytes(b'ABC')
     self.assertTrue(py23_bytes(b) is b)
     self.assertEqual(repr(py23_bytes(b)), "b'ABC'")
Exemple #22
0
 def test_chr(self):
     BASE58_ALPHABET = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
     self.assertEqual(BASE58_ALPHABET.find(py23_chr(4)), -1)
     self.assertEqual(BASE58_ALPHABET.find(b"Z"), 32)
     self.assertEqual(BASE58_ALPHABET.find(py23_bytes("Z", "ascii")), 32)
Exemple #23
0
def _unpad(s, BS):
    count = int(struct.unpack('B', py23_bytes(s[-1], 'ascii'))[0])
    if py23_bytes(s[-count::], 'ascii') == count * struct.pack('B', count):
        return s[:-count]
    return s
Exemple #24
0
 def test_bytes_getitem(self):
     b = py23_bytes(b'ABCD')
     self.assertEqual(b[0], 65)
     self.assertEqual(b[-1], 68)
     self.assertEqual(b[0:1], b'A')
     self.assertEqual(b[:], b'ABCD')
Exemple #25
0
 def __bytes__(self):
     # padding
     asset = self.asset + "\x00" * (7 - len(self.asset))
     return (struct.pack("<q", int(self.amount)) +
             struct.pack("<b", self.precision) + py23_bytes(asset, "ascii"))
Exemple #26
0
 def __bytes__(self):
     return py23_bytes(b'abc')
Exemple #27
0
 def test_bytes_iterable_of_ints(self):
     self.assertEqual(py23_bytes([65, 66, 67]), b'ABC')
     self.assertEqual(py23_bytes([int(120), int(121), int(122)]), b'xyz')
Exemple #28
0
 def test_isinstance_bytes(self):
     self.assertTrue(isinstance(py23_bytes(b'blah'), bytes_types))
Exemple #29
0
 def test_empty_bytes(self):
     b = py23_bytes()
     self.assertEqual(b, b'')
Exemple #30
0
 def test_bytes_bytes(self):
     self.assertEqual(py23_bytes(b'ABC'), b'ABC')