diff --git a/README b/README deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md new file mode 100644 index 0000000..76d8ed1 --- /dev/null +++ b/README.md @@ -0,0 +1,44 @@ +# Junos $9$ secrets encrypt/decrypt script + +## Usage +``` +$ python junosdecode.py +usage: junosdecode.py [-h] [-v] [-r] [-e PLAINTEXT | -d SECRET] + +Junos $9$ password en/decrypt script + +optional arguments: + -h, --help show this help message and exit + -v, --version show program's version number and exit + -r, --result-only Output resulting string only + -e PLAINTEXT, --encrypt PLAINTEXT + encrypt plaintext + -d SECRET, --decrypt SECRET + decrypt secret + +``` + +## Examples +``` +$ python junosdecode.py -e 'hello' +Junos $9$ secrets en/decrypter +python version by matt hite/min song +original perl version by kevin brintnall + +plaintext version: hello +encrypted version: $9$lateMXVb2JGi7-Dk + +$ python junosdecode.py -d '$9$lateMXVb2JGi7-Dk' +Junos $9$ secrets en/decrypter +python version by matt hite/min song +original perl version by kevin brintnall + +encrypted version: $9$lateMXVb2JGi7-Dk +decrypted version: hello + +$ python junosdecode.py -r -e 'hello' +$9$BrKEcyLX-Y2avWYoGif5/CA + +$ python junosdecode.py -r -d '$9$BrKEcyLX-Y2avWYoGif5/CA' +hello +``` diff --git a/junosdecode.py b/junosdecode.py old mode 100755 new mode 100644 index 5c6b3ee..4c6c42f --- a/junosdecode.py +++ b/junosdecode.py @@ -8,11 +8,22 @@ ## original: http://search.cpan.org/dist/Crypt-Juniper/lib/Crypt/Juniper.pm ## requires python 2.7 due to use of dict comprehension ## -## version 1.0 +## version 1.01 - works with python 3 +## ## +############################################################################# +## added juniper_encrypt and the necessary functions +## by Minsuk Song , who also knows +## very little perl +## +from __future__ import print_function + import sys -from optparse import OptionParser, OptionGroup +import argparse +import random + + ################################################################# ## globals @@ -44,7 +55,7 @@ def _nibble(cref, length): nib = cref[0:length] rest = cref[length:] if len(nib) != length: - print "Ran out of characters: hit '%s', expecting %s chars" % (nib, length) + print("Ran out of characters: hit '%s', expecting %s chars" % (nib, length)) sys.exit(1) return nib, rest @@ -56,7 +67,7 @@ def _gap(c1, c2): def _gap_decode(gaps, dec): num = 0 if len(gaps) != len(dec): - print "Nibble and decode size not the same!" + print("Nibble and decode size not the same!") sys.exit(1) for x in range(0, len(gaps)): num += gaps[x] * dec[x] @@ -80,23 +91,87 @@ def juniper_decrypt(crypt): decrypt += _gap_decode(gaps, decode) return decrypt +def _reverse(my_list): + new_list = list(my_list) + new_list.reverse() + return new_list -def main(): - parser = OptionParser(usage="usage: %prog [options] encrypted_string", - version="1.0") +def _gap_encode(pc, prev, encode): + _ord = ord(pc) + + crypt = '' + gaps = [] + for mod in _reverse(encode): + gaps.insert(0, int(_ord/mod)) + _ord %= mod - (options, args) = parser.parse_args() + for gap in gaps: + gap += ALPHA_NUM[prev] + 1 + prev = NUM_ALPHA[gap % len(NUM_ALPHA)] + crypt += prev - # right number of arguments? - if len(args) < 1: - parser.error("wrong number of arguments") + return crypt - encrypted_string = args[0] - print "junos password decrypter" - print "python version by matt hite" - print "original perl version by kevin brintnall\n" - print "encrypted version: %s" % encrypted_string - print "decrypted version: %s" % juniper_decrypt(encrypted_string) +def _randc(cnt = 0): + ret = "" + for _ in range(cnt): + ret += NUM_ALPHA[random.randrange(len(NUM_ALPHA))] + return ret + +def juniper_encrypt(plaintext, salt = None): + if salt is None: + salt = _randc(1) + rand = _randc(EXTRA[salt]) + + pos = 0 + prev = salt + crypt = MAGIC + salt + rand + + for x in plaintext: + encode = ENCODING[pos % len(ENCODING)] + crypt += _gap_encode(x, prev, encode) + prev = crypt[-1] + pos += 1 + + return crypt + + +def main(): + parser = argparse.ArgumentParser(description="Junos $9$ password en/decrypt script") + parser.add_argument('-v','--version', action='version', version='%(prog)s 1.01') + parser.add_argument("-r","--result-only", action="store_true", dest="resultOnly", help="Output resulting string only") + + group = parser.add_mutually_exclusive_group() + group.add_argument("-e", "--encrypt", dest="plaintext", help="encrypt plaintext") + group.add_argument("-d", "--decrypt", dest="secret", help="decrypt secret") + + if len(sys.argv) == 1: + parser.print_help() + sys.exit(1) + args = parser.parse_args() + + if not args.resultOnly: + print("Junos $9$ secrets en/decrypter") + print("python version by matt hite/min song") + print("original perl version by kevin brintnall\n") + + if args.secret: + encrypted_string = args.secret + + if args.resultOnly: + print(juniper_decrypt(encrypted_string), end='') + else: + print("encrypted version: %s" % encrypted_string) + print("decrypted version: %s" % juniper_decrypt(encrypted_string)) + elif args.plaintext: + plaintext_string = args.plaintext + + if args.resultOnly: + print(juniper_encrypt(plaintext_string), end='') + else: + print("plaintext version: %s" % plaintext_string) + print("encrypted version: %s" % juniper_encrypt(plaintext_string)) if __name__ == "__main__": main() +