def decrypt(self, memo): """ Decrypt a memo :param str memo: encrypted memo message :returns: encrypted memo :rtype: str """ if not memo: return None # We first try to decode assuming we received the memo if isinstance(memo, dict) and "to" in memo and "from" in memo and "memo" in memo: memo_to = Account(memo["to"], steem_instance=self.steem) memo_from = Account(memo["from"], steem_instance=self.steem) message = memo["memo"] else: memo_to = self.to_account memo_from = self.from_account message = memo if isinstance(memo, dict) and "nonce" in memo: nonce = memo.get("nonce") else: nonce = "" try: memo_wif = self.steem.wallet.getPrivateKeyForPublicKey( memo_to["memo_key"] ) pubkey = memo_from["memo_key"] except MissingKeyError: try: # if that failed, we assume that we have sent the memo memo_wif = self.steem.wallet.getPrivateKeyForPublicKey( memo_from["memo_key"] ) pubkey = memo_to["memo_key"] except MissingKeyError: # if all fails, raise exception raise MissingKeyError( "Non of the required memo keys are installed!" "Need any of {}".format( [memo_to["name"], memo_from["name"]])) if not hasattr(self, 'chain_prefix'): self.chain_prefix = self.steem.prefix if message[0] == '#': return BtsMemo.decode_memo( PrivateKey(memo_wif), message ) else: return BtsMemo.decode_memo_bts( PrivateKey(memo_wif), PublicKey(pubkey, prefix=self.chain_prefix), nonce, message )
def test_encrypt_decrypt(self): base58 = u'#HU6pdQ4Hh8cFrDVooekRPVZu4BdrhAe9RxrWrei2CwfAApAPdM4PT5mSV9cV3tTuWKotYQF6suyM4JHFBZz4pcwyezPzuZ2na7uwhRcLqFotsqxWRBpaXkNks2QCnYLS8' text = u'#爱' nonce = u'1462976530069648' wif = str(PasswordKey("", "", role="", prefix="STM").get_private_key()) private_key = PrivateKey(wif=wif, prefix="STM") public_key = private_key.pubkey cypertext = encode_memo(private_key, public_key, nonce, text, prefix="STM") self.assertEqual(cypertext, base58) plaintext = decode_memo(private_key, cypertext) self.assertEqual(plaintext, text)
def decrypt_binary(self, infile, outfile, buffer_size=2048): """ Decrypt a binary file :param str infile: encrypted binary file :param str outfile: output file name :param int buffer_size: read buffer size :returns: encrypted memo information :rtype: dict """ if not os.path.exists(infile): raise ValueError("%s does not exists!" % infile) if buffer_size % 16 != 0: raise ValueError("buffer_size must be dividable by 16") with open(infile, 'rb') as fin: memo_size = struct.unpack('<Q', fin.read(struct.calcsize('<Q')))[0] memo = fin.read(memo_size) orig_file_size = struct.unpack('<Q', fin.read(struct.calcsize('<Q')))[0] memo = '#' + base58encode(hexlify(memo).decode("ascii")) memo_to = self.to_account memo_from = self.from_account from_key, to_key, nonce, check, cipher = BtsMemo.extract_memo_data(memo) if memo_to is None and memo_from is None: try: memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( str(to_key) ) pubkey = from_key except MissingKeyError: try: # if that failed, we assume that we have sent the memo memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( str(from_key) ) pubkey = to_key except MissingKeyError: # if all fails, raise exception raise MissingKeyError( "Non of the required memo keys are installed!" "Need any of {}".format( [str(to_key), str(from_key)])) elif memo_to is not None and memo_from is not None and isinstance(memo_from, PrivateKey): memo_wif = memo_from if isinstance(memo_to, Account): pubkey = memo_to["memo_key"] else: pubkey = memo_to elif memo_to is not None and memo_from is not None and isinstance(memo_to, PrivateKey): memo_wif = memo_to if isinstance(memo_from, Account): pubkey = memo_from["memo_key"] else: pubkey = memo_from else: try: memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( memo_to["memo_key"] ) pubkey = memo_from["memo_key"] except MissingKeyError: try: # if that failed, we assume that we have sent the memo memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( memo_from["memo_key"] ) pubkey = memo_to["memo_key"] except MissingKeyError: # if all fails, raise exception raise MissingKeyError( "Non of the required memo keys are installed!" "Need any of {}".format( [memo_to["name"], memo_from["name"]])) if not hasattr(self, 'chain_prefix'): self.chain_prefix = self.blockchain.prefix priv = PrivateKey(memo_wif) pubkey = PublicKey(pubkey, prefix=self.chain_prefix) beem_version = BtsMemo.decode_memo( priv, memo ) shared_secret = BtsMemo.get_shared_secret(priv, pubkey) # Init encryption aes, checksum = BtsMemo.init_aes(shared_secret, nonce) with open(infile, 'rb') as fin: memo_size = struct.unpack('<Q', fin.read(struct.calcsize('<Q')))[0] memo = fin.read(memo_size) file_size = struct.unpack('<Q', fin.read(struct.calcsize('<Q')))[0] with open(outfile, 'wb') as fout: while True: data = fin.read(buffer_size) n = len(data) if n == 0: break decd = aes.decrypt(data) n = len(decd) if file_size > n: fout.write(decd) else: fout.write(decd[:file_size]) # <- remove padding on last block file_size -= n return { "file_size": orig_file_size, "from_key": str(from_key), "to_key": str(to_key), "nonce": nonce, "beem_version": beem_version }
def decrypt(self, memo): """ Decrypt a memo :param str memo: encrypted memo message :returns: encrypted memo :rtype: str """ if not memo: return None memo_wif = None # We first try to decode assuming we received the memo if isinstance(memo, dict) and "to" in memo and "from" in memo and "memo" in memo: memo_to = Account(memo["to"], blockchain_instance=self.blockchain) memo_from = Account(memo["from"], blockchain_instance=self.blockchain) message = memo["memo"] else: memo_to = self.to_account memo_from = self.from_account message = memo if isinstance(memo, dict) and "nonce" in memo: nonce = memo.get("nonce") else: nonce = "" if memo_to is None or memo_from is None: from_key, to_key, nonce, check, cipher = BtsMemo.extract_memo_data(message) try: memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( str(to_key) ) pubkey = from_key except MissingKeyError: try: # if that failed, we assume that we have sent the memo memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( str(from_key) ) pubkey = to_key except MissingKeyError: # if all fails, raise exception raise MissingKeyError( "Non of the required memo keys are installed!" "Need any of {}".format( [str(to_key), str(from_key)])) elif memo_to is not None and memo_from is not None and isinstance(memo_from, PrivateKey): memo_wif = memo_from pubkey = memo_to elif memo_to is not None and memo_from is not None and isinstance(memo_to, PrivateKey): memo_wif = memo_to pubkey = memo_from else: try: memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( memo_to["memo_key"] ) pubkey = memo_from["memo_key"] except MissingKeyError: try: # if that failed, we assume that we have sent the memo memo_wif = self.blockchain.wallet.getPrivateKeyForPublicKey( memo_from["memo_key"] ) pubkey = memo_to["memo_key"] except MissingKeyError: # if all fails, raise exception raise MissingKeyError( "Non of the required memo keys are installed!" "Need any of {}".format( [memo_to["name"], memo_from["name"]])) if not hasattr(self, 'chain_prefix'): self.chain_prefix = self.blockchain.prefix if message[0] == '#' or memo_to is None or memo_from is None: return BtsMemo.decode_memo( PrivateKey(memo_wif), message ) else: return BtsMemo.decode_memo_bts( PrivateKey(memo_wif), PublicKey(pubkey, prefix=self.chain_prefix), nonce, message )
def test_decrypt(self): for memo in test_cases: dec = decode_memo(PrivateKey(memo["wif"]), memo["message"]) self.assertEqual(memo["plain"], dec)
def test_decrypt_bugged_padding(self): for memo in not_enough_padding: dec = decode_memo(PrivateKey(memo["wif"]), memo["message"]) self.assertEqual(memo["plain"], dec[1:])