diff --git a/pbincli/cli.py b/pbincli/cli.py index 7b7057b..f604989 100755 --- a/pbincli/cli.py +++ b/pbincli/cli.py @@ -58,6 +58,8 @@ def main(): get_parser = subparsers.add_parser("get", description="Get data from PrivateBin instance") get_parser.add_argument("pasteinfo", help="example: aabb#cccddd") get_parser.add_argument("-p", "--password", help="password for decrypting paste") + get_parser.add_argument("-s", "--server", default=argparse.SUPPRESS, help="PrivateBin service URL (default: https://paste.i2pd.xyz/)") + get_parser.add_argument("-x", "--proxy", default=argparse.SUPPRESS, help="Proxy server address (default: None)") get_parser.add_argument("--no-check-certificate", default=False, action="store_true", help="disable certificate validation") get_parser.add_argument("--no-insecure-warning", default=False, action="store_true", help="suppress InsecureRequestWarning (only with --no-check-certificate)") get_parser.add_argument("-d", "--debug", default=False, action="store_true", help="enable debug") @@ -67,6 +69,8 @@ def main(): delete_parser = subparsers.add_parser("delete", description="Delete paste from PrivateBin instance using token") delete_parser.add_argument("-p", "--paste", required=True, help="paste id") delete_parser.add_argument("-t", "--token", required=True, help="paste deletion token") + delete_parser.add_argument("-s", "--server", default=argparse.SUPPRESS, help="PrivateBin service URL (default: https://paste.i2pd.xyz/)") + delete_parser.add_argument("-x", "--proxy", default=argparse.SUPPRESS, help="Proxy server address (default: None)") delete_parser.add_argument("--no-check-certificate", default=False, action="store_true", help="disable certificate validation") delete_parser.add_argument("--no-insecure-warning", default=False, action="store_true", help="suppress InsecureRequestWarning (only with --no-check-certificate)") delete_parser.add_argument("-d", "--debug", default=False, action="store_true", help="enable debug") diff --git a/pbincli/format.py b/pbincli/format.py index 8187cd3..3ed854b 100644 --- a/pbincli/format.py +++ b/pbincli/format.py @@ -1,9 +1,28 @@ -from Crypto.Random import get_random_bytes -from Crypto.Cipher import AES from base64 import b64encode, b64decode from pbincli.utils import PBinCLIError import zlib +# try import AES cipher and check if it has GCM mode (prevent usage of pycrypto) +try: + from Crypto.Cipher import AES + from Crypto.Random import get_random_bytes + + if not hasattr(AES, 'MODE_GCM'): + try: + from Cryptodome.Cipher import AES + from Cryptodome.Random import get_random_bytes + except ImportError: + PBinCLIError("AES GCM mode is not found in imported crypto module.\n" + + "That can happen if you have installed pycrypto.\n\n" + + "We tried to import pycryptodomex but it is not available.\n" + + "Please install it via pip, if you still need pycrypto, by running:\n" + + "\tpip install pycryptodomex\n" + + "... otherwise use separate python environment or uninstall pycrypto:\n" + + "\tpip uninstall pycrypto") +except ImportError: + PBinCLIError("Unable import pycryptodome") + + CIPHER_ITERATION_COUNT = 100000 CIPHER_SALT_BYTES = 8 CIPHER_BLOCK_BITS = 256 @@ -11,6 +30,7 @@ CIPHER_BLOCK_BYTES = int(CIPHER_BLOCK_BITS/8) CIPHER_TAG_BITS = int(CIPHER_BLOCK_BITS/2) CIPHER_TAG_BYTES = int(CIPHER_TAG_BITS/8) + class Paste: def __init__(self, debug=False): self._version = 2 @@ -233,8 +253,8 @@ class Paste: def _encryptV2(self): from pbincli.utils import json_encode - iv = get_random_bytes(CIPHER_TAG_BYTES) - salt = get_random_bytes(CIPHER_SALT_BYTES) + iv = get_random_bytes(CIPHER_TAG_BYTES) # 16 bytes + salt = get_random_bytes(CIPHER_SALT_BYTES) # 8 bytes key = self.__deriveKey(salt) # prepare encryption authenticated data and message @@ -261,6 +281,8 @@ class Paste: cipher = self.__initializeCipher(key, iv, adata) ciphertext, tag = cipher.encrypt_and_digest(self.__compress(json_encode(cipher_message))) + if self._debug: print("PBKDF2 Key:\t{}\nCipherText:\t{}\nCipherTag:\t{}".format(b64encode(key), b64encode(ciphertext), b64encode(tag))) + self._data = {'v':2,'adata':adata,'ct':b64encode(ciphertext + tag).decode(),'meta':{'expire':self._expiration}}