Editing Find Hive Users Memo Key and Send Encrypted Message
Please Select a Licence from the LICENCE_HEADERS page |
And place at top of your page |
If no Licence is Selected/Appended, Default will be CC0 Default Licence IF there is no Licence placed below this notice!
When you edit this page, you agree to release your contribution under the CC0 Licence LICENCE:
More information about the cc0 licence can be found here: You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. Licence: Statement of Purpose The laws of most jurisdictions throughout the world automatically confer exclusive Copyright and Related Rights (defined below) upon the creator and subsequent owner(s) (each and all, an "owner") of an original work of authorship and/or a database (each, a "Work"). Certain owners wish to permanently relinquish those rights to a Work for the purpose of contributing to a commons of creative, cultural and scientific works ("Commons") that the public can reliably and without fear of later claims of infringement build upon, modify, incorporate in other works, reuse and redistribute as freely as possible in any form whatsoever and for any purposes, including without limitation commercial purposes. These owners may contribute to the Commons to promote the ideal of a free culture and the further production of creative, cultural and scientific works, or to gain reputation or greater distribution for their Work in part through the use and efforts of others. For these and/or other purposes and motivations, and without any expectation of additional consideration or compensation, the person associating CC0 with a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and publicly distribute the Work under its terms, with knowledge of his or her Copyright and Related Rights in the Work and the meaning and intended legal effect of CC0 on those rights. 1. Copyright and Related Rights. A Work made available under CC0 may be protected by copyright and related or neighboring rights ("Copyright and Related Rights"). Copyright and Related Rights include, but are not limited to, the following: the right to reproduce, adapt, distribute, perform, display, communicate, and translate a Work; moral rights retained by the original author(s) and/or performer(s); publicity and privacy rights pertaining to a person's image or likeness depicted in a Work; rights protecting against unfair competition in regards to a Work, subject to the limitations in paragraph 4(a), below; rights protecting the extraction, dissemination, use and reuse of data in a Work; database rights (such as those arising under Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, and under any national implementation thereof, including any amended or successor version of such directive); and other similar, equivalent or corresponding rights throughout the world based on applicable law or treaty, and any national implementations thereof. 2. Waiver. To the greatest extent permitted by, but not in contravention of, applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and unconditionally waives, abandons, and surrenders all of Affirmer's Copyright and Related Rights and associated claims and causes of action, whether now known or unknown (including existing as well as future claims and causes of action), in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each member of the public at large and to the detriment of Affirmer's heirs and successors, fully intending that such Waiver shall not be subject to revocation, rescission, cancellation, termination, or any other legal or equitable action to disrupt the quiet enjoyment of the Work by the public as contemplated by Affirmer's express Statement of Purpose. 3. Public License Fallback. Should any part of the Waiver for any reason be judged legally invalid or ineffective under applicable law, then the Waiver shall be preserved to the maximum extent permitted taking into account Affirmer's express Statement of Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby grants to each affected person a royalty-free, non transferable, non sublicensable, non exclusive, irrevocable and unconditional license to exercise Affirmer's Copyright and Related Rights in the Work (i) in all territories worldwide, (ii) for the maximum duration provided by applicable law or treaty (including future time extensions), (iii) in any current or future medium and for any number of copies, and (iv) for any purpose whatsoever, including without limitation commercial, advertising or promotional purposes (the "License"). The License shall be deemed effective as of the date CC0 was applied by Affirmer to the Work. Should any part of the License for any reason be judged legally invalid or ineffective under applicable law, such partial invalidity or ineffectiveness shall not invalidate the remainder of the License, and in such case Affirmer hereby affirms that he or she will not (i) exercise any of his or her remaining Copyright and Related Rights in the Work or (ii) assert any associated claims and causes of action with respect to the Work, in either case contrary to Affirmer's express Statement of Purpose. 4. Limitations and Disclaimers. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, licensed or otherwise affected by this document. Affirmer offers the Work as-is and makes no representations or warranties of any kind concerning the Work, express, implied, statutory or otherwise, including without limitation warranties of title, merchantability, fitness for a particular purpose, non infringement, or the absence of latent or other defects, accuracy, or the present or absence of errors, whether or not discoverable, all to the greatest extent permissible under applicable law. Affirmer disclaims responsibility for clearing rights of other persons that may apply to the Work or any use thereof, including without limitation any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims responsibility for obtaining any necessary consents, permissions or other rights required for any use of the Work. Affirmer understands and acknowledges that Creative Commons is not a party to this document and has no duty or obligation with respect to this CC0 or use of the Work. |
- https://hive.blog/hive-138301/@completenoobs/find-hive-users-memo-key-and-send-encrypted-message-l7a
Intro
Learning about hive by tinkering
- Find The Memo Public Key from username
- Encrypt a Message so only the private key holder of that public key can decrypt
Creating Container
- Creating a Container so we know reproducable (depends installed ... etc)
- create container
lxc launch ubuntu:24.04 keys
- Login to container
lxc exec keys bash
- switch to user ubuntu
su - ubuntu
Update Container and Install Dependencies
- Update package lists
sudo apt update && sudo apt upgrade -y
- Install essential packages
sudo apt install -y python3 python3-pip python3-venv git build-essential
- Install development libraries needed for compilation
sudo apt install -y libssl-dev libffi-dev python3-dev
- Verify Python installation
python3 --version
pip3 --version
Create Virtual Environment (Recommended)
- Create a virtual environment
python3 -m venv hive_beem_env
- Activate the virtual environment
source hive_beem_env/bin/activate
- Verify you're in the virtual environment (should show the path)
(hive_beem_env) ubuntu@hive:~$
Install Beem
- NOTE: Beem is installed in Virtual Environment to avoid
error: externally-managed-environment
- Install beem from PyPI
pip install beem
- Verify installation
python -c "import beem; print(beem.__version__)"
Find a Hive Users Public Keys
- Create Script
$EDITOR find-user-keys.py
#!/usr/bin/env python3 import argparse import logging from beem import Hive from beem.account import Account from beem.exceptions import AccountDoesNotExistsException # Set up logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) def get_public_keys(username, nodes=None): """Fetch public keys for a Hive account.""" if nodes is None: nodes = [ "https://api.hive.blog", "https://rpc.ecency.com", "https://api.deathwing.me", "https://fin.hive.3speak.co" ] try: # Initialize Hive instance hive = Hive(node=nodes) logger.info(f"Using node: {hive.rpc.url}") # Get account logger.info(f"Fetching account: {username}") account = Account(username, blockchain_instance=hive) # Get public keys keys = { "posting": account["posting"]["key_auths"][0][0] if account["posting"]["key_auths"] else "None", "active": account["active"]["key_auths"][0][0] if account["active"]["key_auths"] else "None", "owner": account["owner"]["key_auths"][0][0] if account["owner"]["key_auths"] else "None", "memo": account["memo_key"] if account["memo_key"] else "None" } # Print keys print(f"\nPublic Keys for @{username}:") for key_type, key_value in keys.items(): print(f"{key_type.capitalize()}: {key_value}") # Save to file with open(f"{username}_public_keys.txt", "w", encoding="utf-8") as f: f.write(f"Public Keys for @{username}:\n") for key_type, key_value in keys.items(): f.write(f"{key_type.capitalize()}: {key_value}\n") print(f"Saved keys to {username}_public_keys.txt") return keys except AccountDoesNotExistsException: logger.error(f"Account does not exist: {username}") print(f"Error: The account '{username}' does not exist on the Hive blockchain.") except Exception as e: logger.error(f"Error fetching keys for {username}: {str(e)}", exc_info=True) print(f"Error fetching keys: {str(e)}") print("Possible issues: node connectivity or API limits.") def main(): # Set up argument parser parser = argparse.ArgumentParser(description="Fetch public keys for a Hive account.") parser.add_argument("--username", required=True, help="Hive username (e.g., completenoobs)") args = parser.parse_args() # Fetch keys get_public_keys(args.username) if __name__ == "__main__": main()
- To use script
python3 find-user-keys.py --username completenoobs
- OutPut:
(hive_beem_env) ubuntu@keys:~$ python3 find-user-keys.py --user completenoobs 2025-06-16 02:55:48,890 - INFO - Using node: https://api.hive.blog 2025-06-16 02:55:48,890 - INFO - Fetching account: completenoobs Public Keys for @completenoobs: Posting: STM52HfmA7gmnAjq8eQbAPgTxijsoVwm3T439dgeVqjC4baXUyJSV Active: STM4zGfF1K9TbMoCcE2eLtTwrBwVybEhgu5yfBv99nhR6kjf5Hv97 Owner: STM8jjM8CowxH6ttosaUXCK5NufZQMga18KRD6vq1LrmTH4u4poQW Memo: STM5u4bQRcCFfbGgg29TabvAmYsMdM6eGK8sj7sJDWPPpz6SwAums Saved keys to completenoobs_public_keys.txt
- Will also create a text file container user keys in same directory script run:
Encrypting and Decrypting
- Install Missing Depends
pip install cryptography
- Create Script
$EDITOR crypt.py
#!/usr/bin/env python3 """ Offline Hive Memo Encryption/Decryption Encrypts to public key and decrypts with private key without network access Compatible with Hive memo format """ import hashlib import hmac import struct import base64 import os from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, PublicFormat, NoEncryption # Base58 alphabet used by Bitcoin/Hive BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' def base58_encode(data): """Encode bytes to base58""" count = 0 for byte in data: if byte == 0: count += 1 else: break encoded = '' num = int.from_bytes(data, 'big') while num > 0: num, remainder = divmod(num, 58) encoded = BASE58_ALPHABET[remainder] + encoded return '1' * count + encoded def base58_decode(s): """Decode base58 to bytes""" count = 0 for char in s: if char == '1': count += 1 else: break num = 0 for char in s: num = num * 58 + BASE58_ALPHABET.index(char) decoded = num.to_bytes((num.bit_length() + 7) // 8, 'big') return b'\x00' * count + decoded def wif_to_private_key(wif): """Convert WIF format to private key bytes""" decoded = base58_decode(wif) # Remove version byte (0x80) and checksum (last 4 bytes) private_key_bytes = decoded[1:-4] return private_key_bytes def private_key_from_wif(wif): """Generate private key object from WIF""" private_key_bytes = wif_to_private_key(wif) private_key = ec.derive_private_key( int.from_bytes(private_key_bytes, 'big'), ec.SECP256K1(), default_backend() ) return private_key def stm_to_public_key(stm_key): """Convert STM format public key to cryptography public key object""" # Remove STM prefix and decode key_data = base58_decode(stm_key[3:]) # Remove checksum (last 4 bytes) point_data = key_data[:-4] # Parse compressed public key (33 bytes: 0x02/0x03 + 32 bytes) if len(point_data) == 33: x = int.from_bytes(point_data[1:], 'big') y_is_even = point_data[0] == 0x02 # Calculate y coordinate p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F y_squared = (pow(x, 3, p) + 7) % p y = pow(y_squared, (p + 1) // 4, p) if y % 2 != (0 if y_is_even else 1): y = p - y public_key = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256K1(), b'\x04' + x.to_bytes(32, 'big') + y.to_bytes(32, 'big') ) return public_key raise ValueError("Invalid public key format") def generate_shared_secret(private_key, public_key): """Generate shared secret using ECDH""" if isinstance(private_key, str): private_key = public_key_from_wif(private_key).private_key() shared_point = private_key.exchange(ec.ECDH(), public_key) return shared_point def encrypt_message(message, recipient_public_key, sender_private_key): """Encrypt message using Hive memo format""" # Generate shared secret if isinstance(sender_private_key, str): sender_private_key_obj = private_key_from_wif(sender_private_key) else: sender_private_key_obj = sender_private_key if isinstance(recipient_public_key, str): recipient_public_key_obj = stm_to_public_key(recipient_public_key) else: recipient_public_key_obj = recipient_public_key shared_secret = generate_shared_secret(sender_private_key_obj, recipient_public_key_obj) # Generate nonce nonce = os.urandom(8) # Derive encryption key key_material = shared_secret + nonce encryption_key = hashlib.sha512(key_material).digest()[:32] # Encrypt message iv = os.urandom(16) cipher = Cipher(algorithms.AES(encryption_key), modes.CBC(iv), backend=default_backend()) encryptor = cipher.encryptor() # Pad message to 16-byte boundary padded_message = message.encode('utf-8') padding_length = 16 - (len(padded_message) % 16) padded_message += bytes([padding_length] * padding_length) ciphertext = encryptor.update(padded_message) + encryptor.finalize() # Get sender's public key for the memo sender_public_key = sender_private_key_obj.public_key() sender_public_key_bytes = sender_public_key.public_numbers().x.to_bytes(32, 'big') # Create memo format: nonce + sender_pubkey + iv + ciphertext memo_data = nonce + sender_public_key_bytes + iv + ciphertext # Encode as base64 and add # prefix encoded_memo = '#' + base64.b64encode(memo_data).decode('utf-8') return encoded_memo def decrypt_message(encrypted_memo, recipient_private_key): """Decrypt message using Hive memo format""" # Remove # prefix and decode base64 if not encrypted_memo.startswith('#'): raise ValueError("Invalid memo format - should start with #") memo_data = base64.b64decode(encrypted_memo[1:]) # Parse memo components nonce = memo_data[:8] sender_pubkey_x = memo_data[8:40] iv = memo_data[40:56] ciphertext = memo_data[56:] # Reconstruct sender's public key (assuming even y coordinate) sender_x = int.from_bytes(sender_pubkey_x, 'big') p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F y_squared = (pow(sender_x, 3, p) + 7) % p y = pow(y_squared, (p + 1) // 4, p) # Try even y coordinate first try: if y % 2 != 0: y = p - y sender_public_key = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256K1(), b'\x04' + sender_x.to_bytes(32, 'big') + y.to_bytes(32, 'big') ) except: # Try odd y coordinate y = p - y sender_public_key = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256K1(), b'\x04' + sender_x.to_bytes(32, 'big') + y.to_bytes(32, 'big') ) # Convert sender's public key to STM format for display sender_public_numbers = sender_public_key.public_numbers() x = sender_public_numbers.x.to_bytes(32, 'big') y_is_even = sender_public_numbers.y % 2 == 0 compressed_pubkey = (b'\x02' if y_is_even else b'\x03') + x checksum = hashlib.sha256(compressed_pubkey).digest()[:4] sender_stm_pubkey = 'STM' + base58_encode(compressed_pubkey + checksum) # Generate shared secret if isinstance(recipient_private_key, str): recipient_private_key_obj = private_key_from_wif(recipient_private_key) else: recipient_private_key_obj = recipient_private_key shared_secret = generate_shared_secret(recipient_private_key_obj, sender_public_key) # Derive decryption key key_material = shared_secret + nonce decryption_key = hashlib.sha512(key_material).digest()[:32] # Decrypt message cipher = Cipher(algorithms.AES(decryption_key), modes.CBC(iv), backend=default_backend()) decryptor = cipher.decryptor() padded_message = decryptor.update(ciphertext) + decryptor.finalize() # Remove padding padding_length = padded_message[-1] message = padded_message[:-padding_length].decode('utf-8') return message, sender_stm_pubkey def generate_hive_keys(): """Generate a new Hive-compatible key pair""" private_key = ec.generate_private_key(ec.SECP256K1(), default_backend()) private_key_bytes = private_key.private_numbers().private_value.to_bytes(32, 'big') # Create WIF format extended_key = b'\x80' + private_key_bytes checksum = hashlib.sha256(hashlib.sha256(extended_key).digest()).digest()[:4] wif = base58_encode(extended_key + checksum) # Create STM format public key public_key = private_key.public_key() public_key_point = public_key.public_numbers() # Compress public key x = public_key_point.x.to_bytes(32, 'big') y_is_even = public_key_point.y % 2 == 0 compressed_pubkey = (b'\x02' if y_is_even else b'\x03') + x # Add checksum for STM format checksum = hashlib.sha256(compressed_pubkey).digest()[:4] stm_pubkey = 'STM' + base58_encode(compressed_pubkey + checksum) return wif, stm_pubkey def main(): print("=== Offline Hive Memo Tool ===") while True: print("\nOptions:") print("1. Generate new key pair") print("2. Encrypt message") print("3. Decrypt message") print("4. Exit") choice = input("\nEnter choice (1-4): ").strip() if choice == '1': print("\nGenerating new Hive key pair...") private_key, public_key = generate_hive_keys() print(f"Private Key (WIF): {private_key}") print(f"Public Key (STM): {public_key}") elif choice == '2': try: message = input("\nEnter message to encrypt: ") recipient_pubkey = input("Enter recipient's public key (STM...): ").strip() sender_privkey = input("Enter your private key (5...): ").strip() filename = input("Enter output filename: ").strip() encrypted = encrypt_message(message, recipient_pubkey, sender_privkey) with open(filename, 'w') as f: f.write(encrypted) print(f"\nMessage encrypted and saved to {filename}") print(f"Encrypted memo: {encrypted}") except Exception as e: print(f"Encryption error: {e}") elif choice == '3': try: filename = input("\nEnter encrypted file path: ").strip() private_key = input("Enter your private key (5...): ").strip() with open(filename, 'r') as f: encrypted_memo = f.read().strip() decrypted_message, sender_pubkey = decrypt_message(encrypted_memo, private_key) print(f"\nDecrypted message: {decrypted_message}") print(f"Sender's public key: {sender_pubkey}") print(f"\n(You can reply by encrypting a message to: {sender_pubkey})") except Exception as e: print(f"Decryption error: {e}") elif choice == '4': print("Goodbye!") break else: print("Invalid choice. Please try again.") if __name__ == "__main__": main()
- OutPut:
=== Offline Hive Memo Tool === Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4):
Example Use
- In this example 2 key pairs where created, to send and receive
(hive_beem_env) ubuntu@keys:~$ python3 crypt.py === Offline Hive Memo Tool === Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 1 Generating new Hive key pair... Private Key (WIF): 5KR1behsskwnusyUMGZMNVdemVFUvoJTLkj4M7UhN3jpv7G5yK8 Public Key (STM): STM6VsVfhBdhs5pcX7CoTeoyWtxin2SPPFyMPcenbRQjRJLcjwaBK Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 1 Generating new Hive key pair... Private Key (WIF): 5JZqP9VBVL5tTqHCuAjPd4WuJDv84e56fA48wc6CnKtMq6Z4cVe Public Key (STM): STM5aV2anXQonjiBtjSiF8K8g336aDviXQq9j2441hTgVdm3qD3BU Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 4 Goodbye! (hive_beem_env) ubuntu@keys:~$ python3 crypt.py === Offline Hive Memo Tool === Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 2 Enter message to encrypt: test message Enter recipient's public key (STM...): STM5aV2anXQonjiBtjSiF8K8g336aDviXQq9j2441hTgVdm3qD3BU Enter your private key (5...): 5KR1behsskwnusyUMGZMNVdemVFUvoJTLkj4M7UhN3jpv7G5yK8 Enter output filename: test.msg Message encrypted and saved to test.msg Encrypted memo: #ha05gnlySH/UCOEW78Gx6FFlqYSvylks99XfTfyzp7Pq1Zx/o0YDrvCBZIM9v6wiccjyNOkcwT45rzI5MXBIyGsoHDN6lC4D Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 3 Enter encrypted file path: test.msg Enter your private key (5...): 5JZqP9VBVL5tTqHCuAjPd4WuJDv84e56fA48wc6CnKtMq6Z4cVe Decrypted message: test message Sender's public key: STM6VsVfhBdhs5pcX7CoTeoyWtxin2SPPFyMPcenbRQjRJLcjwaBK (You can reply by encrypting a message to: STM6VsVfhBdhs5pcX7CoTeoyWtxin2SPPFyMPcenbRQjRJLcjwaBK) Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 2 Enter message to encrypt: so not doing much then? Enter recipient's public key (STM...): STM6VsVfhBdhs5pcX7CoTeoyWtxin2SPPFyMPcenbRQjRJLcjwaBK Enter your private key (5...): 5JZqP9VBVL5tTqHCuAjPd4WuJDv84e56fA48wc6CnKtMq6Z4cVe Enter output filename: test2.msg Message encrypted and saved to test2.msg Encrypted memo: #f0SOHdMtUA5az+j9s3iwVbThCKvHCy1j3mLZTS45ymAYtAAhVv+6g9Bll1V0unDOIksVC2mdTduPor9IKM4DygfrQz1KSxsf3uC/za+Jxd6BIv4N5l5L1g== Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 3 Enter encrypted file path: test2.msg Enter your private key (5...): 5KR1behsskwnusyUMGZMNVdemVFUvoJTLkj4M7UhN3jpv7G5yK8 Decrypted message: so not doing much then? Sender's public key: STM5aV2anXQonjiBtjSiF8K8g336aDviXQq9j2441hTgVdm3qD3BU (You can reply by encrypting a message to: STM5aV2anXQonjiBtjSiF8K8g336aDviXQq9j2441hTgVdm3qD3BU) Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4):
Example of Script use 2
- Below is some test keys generated for this demo
- This time it did not give same public key from signing private key - but still worked.
RECEIVING Key Pair 1: Generating new Hive key pair... Private Key (WIF): 5JxAbGJ7XFcpAY3rW3pmzGapEkyrSf9wz14Lar3ZMvxUpA14uaR Public Key (STM): STM5KtMabHkqWdwBJavkFRpHd4UkYSMQJiofW3vicw68t6y53YYpF SENDING Key Pair 2: Generating new Hive key pair... Private Key (WIF): 5HvNXDZYh5QFFikGnwv8cs7u2nF6eiUTKPScBfdy4QzvJWqKCLo Public Key (STM): STM6a9JCL7LXKpKDYjaYiwFtdqydkh9aha5YrH7NoKm3wdkw4eUFg
Encryption and Decryption Example 2
(hive_beem_env) ubuntu@keys:~$ python3 crypt.py === Offline Hive Memo Tool === Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 2 Enter message to encrypt: yo whats up :) does this make sense to you. Enter recipient's public key (STM...): STM5KtMabHkqWdwBJavkFRpHd4UkYSMQJiofW3vicw68t6y53YYpF Enter your private key (5...): 5HvNXDZYh5QFFikGnwv8cs7u2nF6eiUTKPScBfdy4QzvJWqKCLo Enter output filename: newtest.msg Message encrypted and saved to newtest.msg Encrypted memo: #syhpjq7Bae/dvF3/yeUdtk9leWooSemGYGSgFlxTXmDl9t4rnDoT1/YHo7HMnf+ZM3FPmMZmNZFeSUUAeWcP+m3g9L/7wvdWP0XXtTqEgoZZOl1BAqJTHIdHxQKDQ1++jLx2YZEkxKo= Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 3 Enter encrypted file path: newtest.msg Enter your private key (5...): 5JxAbGJ7XFcpAY3rW3pmzGapEkyrSf9wz14Lar3ZMvxUpA14uaR Decrypted message: yo whats up :) does this make sense to you. Sender's public key: STM6a9JCL7LXKpKDYjaYiwFtdqydkh9aha5YrH7NoKm3wdkuxXxXg (You can reply by encrypting a message to: STM6a9JCL7LXKpKDYjaYiwFtdqydkh9aha5YrH7NoKm3wdkuxXxXg) Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 2 Enter message to encrypt: reply to sender Enter recipient's public key (STM...): STM6a9JCL7LXKpKDYjaYiwFtdqydkh9aha5YrH7NoKm3wdkuxXxXg Enter your private key (5...): 5JxAbGJ7XFcpAY3rW3pmzGapEkyrSf9wz14Lar3ZMvxUpA14uaR Enter output filename: reply.msg Message encrypted and saved to reply.msg Encrypted memo: #x06sC2YmlHQ5qoKbtCsiibPc7YGejYH1mqxsX01cMQ0UhSo6gKLCWM65AjL8dl80Jdhb6iuJlrlCrlZgdZkO8at0vBGTtLin Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4): 3 Enter encrypted file path: reply.msg Enter your private key (5...): 5HvNXDZYh5QFFikGnwv8cs7u2nF6eiUTKPScBfdy4QzvJWqKCLo Decrypted message: reply to sender Sender's public key: STM5KtMabHkqWdwBJavkFRpHd4UkYSMQJiofW3vicw68t6y7eTR76 (You can reply by encrypting a message to: STM5KtMabHkqWdwBJavkFRpHd4UkYSMQJiofW3vicw68t6y7eTR76) Options: 1. Generate new key pair 2. Encrypt message 3. Decrypt message 4. Exit Enter choice (1-4):