Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add encoding, update for Python 3, add result-only output #2

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Empty file removed README
Empty file.
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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
```
109 changes: 92 additions & 17 deletions junosdecode.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -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 <[email protected]>, who also knows
## very little perl
##
from __future__ import print_function

import sys
from optparse import OptionParser, OptionGroup
import argparse
import random



#################################################################
## globals
Expand Down Expand Up @@ -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

Expand All @@ -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]
Expand All @@ -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()