diff --git a/pbincli.py b/pbincli.py index ee0fa27..416318b 100755 --- a/pbincli.py +++ b/pbincli.py @@ -20,9 +20,17 @@ def main(): send_parser.add_argument("-e", "--expire", default="1day", action="store", help="expiration of paste (default: 1day)") send_parser.add_argument("-f", "--format", default="plaintext", action="store", help="format of paste (default: plaintext)") send_parser.add_argument("-p", "--password", help="password for crypting paste") - #send_parser.add_argument("filename", help="filename (example: image.jpg)") + send_parser.add_argument("-D", "--debug", default=False, action="store_true", help="enable debug") + #send_parser.add_argument("filename", help="example: image.jpg") send_parser.set_defaults(func=pbincli.actions.send) + get_parser = subparsers.add_parser("get", description="Get data from PrivateBin instance", usage=""" +%(prog)s pasteid#password""" + ) + get_parser.add_argument("pasteinfo", help="example: aabb#cccddd") + get_parser.add_argument("-D", "--debug", default=False, action="store_true", help="enable debug") + get_parser.set_defaults(func=pbincli.actions.get) + # parse arguments args = parser.parse_args() if hasattr(args, "func"): diff --git a/pbincli/actions.py b/pbincli/actions.py index fbcdb6f..fe4c68d 100644 --- a/pbincli/actions.py +++ b/pbincli/actions.py @@ -4,36 +4,76 @@ import os import pbincli.actions '''from pbincli.sjcl_gcm import SJCL''' import pbincli.sjcl_simple +import pbincli.utils from base64 import b64encode from Crypto.Hash import SHA256 from pbincli.transports import privatebin -from pbincli.utils import PBinCLIException, check_readable, check_writable from zlib import compress + def send(args): """ Sub-command for sending paste """ #check_readable(args.filename) #with open(args.filename, "rb") as f: # contents = f.read() #file = b64encode(compress(contents)) - data = b'Test!' + passphrase = os.urandom(32) - #print("Passphrase: {}".format(passphrase)) + if args.debug: print("Passphrase: {}".format(passphrase)) if args.password: - #print("Password: {}".format(password)) p = SHA256.new() p.update(args.password.encode("UTF-8")) - passphrase = passphrase + p.hexdigest().encode("UTF-8") + passphrase = b64encode(passphrase + p.hexdigest().encode("UTF-8")) + + else: + passphrase = b64encode(passphrase) + if args.degub: print("Password:\t{}".format(passphrase)) #data = SJCL().encrypt(file, password.decode("UTF-8")) - """Sending text from 'data' string""" #cipher = pbincli.sjcl_simple.encrypt(b64encode(passphrase), file) - cipher = pbincli.sjcl_simple.encrypt(b64encode(passphrase), data) - request = {'data':json.dumps(cipher, ensure_ascii=False),'expire':args.expire,'formatter':args.format,'burnafterreading':int(args.burn),'opendiscussion':int(args.discus) + """Sending text from 'data' string""" + cipher = pbincli.sjcl_simple.encrypt(passphrase, data) + request = {'data':json.dumps(cipher, ensure_ascii=False).replace(' ',''),'expire':args.expire,'formatter':args.format,'burnafterreading':int(args.burn),'opendiscussion':int(args.discus) } - print(request) - '''Here we run function post from pbincli.transports''' - privatebin().post(request, b64encode(passphrase)) + if args.debug: print("Request:\t{}".format(request)) + + + result, server = privatebin().post(request) + if args.debug: print("Response:\t{}\n".format(result.decode("UTF-8"))) + result = json.loads(result) + """Standart response: {"status":0,"id":"aaabbb","url":"\/?aaabbb","deletetoken":"aaabbbccc"}""" + if result['status'] == 0: + print("Paste uploaded!\nPasteID:\t{}\nPassword:\t{}\nDelete token:\t{}\n\nLink:\t{}?{}#{}".format(result['id'], passphrase.decode("UTF-8"), result['deletetoken'], server, result['id'], passphrase.decode("UTF-8"))) + + else: + print("Something went wrong...\nError:\t{}".format(result['error'])) + sys.exit(1) + + +def get(args): + paste = args.pasteinfo.split("#") + if paste[0] and paste[1]: + if args.debug: print("PasteID:\t{}\nPassword:\t{}\n".format(paste[0], paste[1])) + result = privatebin().get(args.pasteinfo) + else: + print("PBinCLI error: Incorrect request") + sys.exit(1) + + + if args.debug: print("Response:\t{}\n".format(result.decode("UTF-8"))) + result = json.loads(result) + if result['status'] == 0: + print("Paste received!\n") + text = pbincli.utils.json_loads_byteified(result['data']) + out = pbincli.sjcl_simple.decrypt(paste[1], text) + print(out) + + if 'burnafterreading' in result['meta'] and result['meta']['burnafterreading']: + print("Meow!") + + else: + print("Something went wrong...\nError:\t{}".format(result['error'])) + sys.exit(1) diff --git a/pbincli/sjcl_simple.py b/pbincli/sjcl_simple.py index 8d882c9..c3f4842 100644 --- a/pbincli/sjcl_simple.py +++ b/pbincli/sjcl_simple.py @@ -14,7 +14,7 @@ def decrypt(pwd, json): iv = b64decode(json['iv']) ct = b64decode(json['ct']) salt = b64decode(json['salt']) - ts = data['ts'] / 8 + ts = json['ts'] / 8 tag_start = len(ct) - ts tag = ct[tag_start:] @@ -66,7 +66,7 @@ def encrypt(pwd, plaintext, mode='gcm', algorithm='aes', return json -def _kdf(keysize=256, iters=256000, salt=None, **kwargs): +def _kdf(keysize=256, iters=10000, salt=None, **kwargs): kdf_salt = salt or os.urandom(8) kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=keysize / 8, diff --git a/pbincli/transports.py b/pbincli/transports.py index 962e8bc..8f44b0a 100644 --- a/pbincli/transports.py +++ b/pbincli/transports.py @@ -1,19 +1,26 @@ import requests import json import urllib -from pprint import pprint class privatebin(object): + def __init__(self): - #self.proxies = {'http': 'http://127.0.0.1:4444'} + self.proxies = {'http': 'http://127.0.0.1:4444'} self.server = 'http://paste.r4sas.i2p/' self.headers = {'X-Requested-With': 'JSONHttpRequest'} - def post(self, data, password): - #r = requests.post(url=self.server, headers=self.headers, proxies=self.proxies, data=data) - r = requests.post(url=self.server, headers=self.headers, data=data) - print(r.text) - result = json.loads(r.text) - '''Standart response: {"status":0,"id":"aaabbb","url":"\/?aaabbb","deletetoken":"aaabbbccc"}''' - if result['status'] == 0: - print("Paste uploaded!\nPasteID:\t{}\nPassword:\t{}\nDelete token:\t{}\n".format(result['id'], password.decode("UTF-8"), result['deletetoken'])) + + def post(self, request): + r = requests.post(url=self.server, headers=self.headers, proxies=self.proxies, data=request) + return r.text, self.server + + + def get(self, request): + url = self.server + "?" + request + r = requests.get(url=url, headers=self.headers, proxies=self.proxies) + return r.text + + + def delete(self, request): + r = requests.post(url=self.server, headers=self.headers, proxies=self.proxies, data=request) + return r.text diff --git a/pbincli/utils.py b/pbincli/utils.py index 93e4bf0..1534e07 100644 --- a/pbincli/utils.py +++ b/pbincli/utils.py @@ -1,4 +1,5 @@ """Various code""" +import json import os class PBinCLIException(Exception): @@ -13,3 +14,33 @@ def check_writable(f): """Checks if path is writable""" if not os.access(os.path.dirname(f) or ".", os.W_OK): raise PBinCLIException("Path is not writable: {}".format(f)) + +"""http://stackoverflow.com/a/33571117""" +def json_load_byteified(file_handle): + return _byteify( + json.load(file_handle, object_hook=_byteify), + ignore_dicts=True + ) + +def json_loads_byteified(json_text): + return _byteify( + json.loads(json_text, object_hook=_byteify), + ignore_dicts=True + ) + +def _byteify(data, ignore_dicts = False): + # if this is a unicode string, return its string representation + if isinstance(data, unicode): + return data.encode('utf-8') + # if this is a list of values, return list of byteified values + if isinstance(data, list): + return [ _byteify(item, ignore_dicts=True) for item in data ] + # if this is a dictionary, return dictionary of byteified keys and values + # but only if we haven't already byteified it + if isinstance(data, dict) and not ignore_dicts: + return { + _byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True) + for key, value in data.iteritems() + } + # if it's anything else, return it in its original form + return data