Junos OS

Expand all | Collapse all

Password encryption algorithm in Junos?

Jump to Best Answer
  • 1.  Password encryption algorithm in Junos?

     
    Posted 06-27-2011 04:33

    Hi All,

     

    Does anyone know what password encryption algorithm is used in Junos configuration?

     

    root-authentication {
        encrypted-password "$1$y7ArHxKU$zUbdeLfBirgkCsKiOJ5Qa0"; ## SECRET-DATA
    }



  • 2.  RE: Password encryption algorithm in Junos?

    Posted 06-27-2011 05:20

    Hello,

     

    What you actually see in configuration file is a hash, not an encripted password. 



  • 3.  RE: Password encryption algorithm in Junos?

     
    Posted 06-28-2011 01:21

    Hi Dumitru,

    I'm not sure this can be hash, because in this case

        archival {
            configuration {                
                transfer-on-commit;
                archive-sites {
                    "ftp://ftp@192.168.0.225" password "$9$dwVYoJZjkqfoaFnCA0O"; ## SECRET-DATA
                }
            }

    the router will need actual password, not just hash, to send files to ftp.
    So it can't be hashing, as it is impossible to un-hash...



  • 4.  RE: Password encryption algorithm in Junos?

    Posted 06-28-2011 01:41

    Hi,

     

     

     For user login, the user password is not stored anywhere, only password hash is stored in configuration file and at each login the hash from typed password is generated and is compared to the one stored in configuration file.

     



  • 5.  RE: Password encryption algorithm in Junos?
    Best Answer

    Posted 06-28-2011 01:45

    Hello,

    Passwords starting with $1 are in "salted MD5" format as described in Freebsd crypt(3) man page

    http://www.freebsd.org/cgi/man.cgi?query=crypt&apropos=0&sektion=3&manpath=FreeBSD+6.1-RELEASE&format=html

    Also see

    http://www.gnu.org/s/hello/manual/libc/crypt.html

     

    Passwords starting with $9 are resersibly-encrypted, one can decrypt them online or using Perl lib

    http://blog.stoked-security.com/2011/06/juniper-9-equivalent-of-cisco-type-7.html

     

    HTH

    Rgds

    Alex



  • 6.  RE: Password encryption algorithm in Junos?

    Posted 06-28-2011 01:58


  • 7.  RE: Password encryption algorithm in Junos?

     
    Posted 06-28-2011 02:22

    Thanks a lot, Alex,

    It's clear now that they use reversible encryption for $9$ passwords and MD5 hash
    for $1$ ones.

    I also thank Ulf and Dumitru for pointing to the right direction.



  • 8.  RE: Password encryption algorithm in Junos?

    Posted 02-13-2014 16:25

    I know you posted this many moons ago but this has answered some questions in one go and fixed some nice automation aspects for our SRX deployments so thank you!

    g



  • 9.  RE: Password encryption algorithm in Junos?

    Posted 03-04-2016 12:37

    For those that want to do password encryption using Java instead of Perl below find the Java code to encrypt both $1 and $9 passwords.  This will allow you to convert plain text passwords in to their proper encrypted forms in configurations.

     

    import java.security.NoSuchAlgorithmException;
    import java.security.MessageDigest;
    import java.util.Deque;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.Map;
    import java.util.Random;
    import java.util.regex.Pattern;  
    
    /**
     * Class to encrypt passwords used in Junos configurations.
     * 
     * @author dkasten
     */
    public final class JuniperPassword
    {
      private static final String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
      private static Random rnd = new Random();
      
      // Constants for encrypt9 method
      private static final String MAGIC = "$9$";
      private static final String[] FAMILY = {"QzF3n6/9CAtpu0O", "B1IREhcSyrleKvMW8LXx", "7N-dVbwsY2g4oaJZGUDj", "iHkq.mPf5T"};
      private static Map<String,Integer> EXTRA = new HashMap<String,Integer> ();
      private static Pattern VALID;
      private static final String[] NUM_ALPHA;
      private static Map<String,Integer> ALPHA_NUM = new HashMap<String,Integer> ();
      private static final int[][] ENCODING = {
          {1,  4, 32},
          {1, 16, 32},
          {1,  8, 32},
          {1, 64    },
          {1, 32    },
          {1,  4, 16, 128},
          {1, 32, 64}
      };
      
      static {
        // Prepare EXTRA constant for use with encrypt9 method
        for (int fam = 0; fam < FAMILY.length; fam++) {
          for (char c : FAMILY[fam].toCharArray()) {
            EXTRA.put(String.valueOf(c), 3 - fam);
          }
        }
        
        // Prepare VALID RegEx pattern constant for use with decrypt9 method (VALID currently not used as decrypt9 has not been added to class but letters and end variables are used in next section)
        StringBuilder letters = new StringBuilder("");
        for (String item : FAMILY) {
          letters.append(item);
        }
        String end = letters.toString() + "{4,}$";
        end.replace("-", "\\-");
        VALID = Pattern.compile("^\\Q" + MAGIC + "\\E" + end);
        
        // Prepare NUM_ALPHA and ALPHA_NUM constants for use with encrypt9 method
        NUM_ALPHA = new String[letters.length()];
        int x = 0;
        for (char item : letters.toString().toCharArray()) {
          NUM_ALPHA[x] = String.valueOf(item);
          x++;
        }
        for (int num = 0; num < NUM_ALPHA.length; num++) {
          ALPHA_NUM.put(NUM_ALPHA[num], num);
        }
      }
      
      /**
       * Creates a non-reversable $1 password used for user logins on Junos configurations.  Wrapper with try/catch block and random salt creations
       * for the {@link #crypt(String, String)} method.
       * 
       * @param pw Password to encrypt.
       * @return String - Encrypted password.  Can be null if encryption fails.
       */
      public static String encrypt1(String pw)
      {
        try
        {
          return crypt(pw, randomSalt(8));
        }
        catch (NoSuchAlgorithmException e)
        {
          e.printStackTrace();
          return null;
        }
      }
      
      /**
       * Creates a reversable $9 password used for most passwords in Junos configurations.
       * 
       * @param pw Password to encrypt.
       * @return String - Encrypted password.  Can be null if encryption fails.
       */
      public static String encrypt9(String pw)
      {
        String salt = randomSalt(1);
        String rand = randomSalt(EXTRA.get(salt));
        int pos = 0;
        String prev = salt;
        String crypt = MAGIC + salt + rand;
        
        for (char item : pw.toCharArray()) {
          int[] encode = ENCODING[pos % ENCODING.length];
          crypt += gapEncode(item, prev, encode);
          prev = crypt.substring(crypt.length() - 1);
          pos++;
        }
        
        return crypt;
      }
      
      /**
       * Helper function to generate random salt strings.
       * 
       * @param len Length of the random salt to create.
       * @return String - Generated salt string.
       */
      private static String randomSalt(int len)
      {
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++)
        {
          sb.append(itoa64.charAt(rnd.nextInt(itoa64.length())));
        }
        return sb.toString();
      }
    
      /**
       * Conversion method that is part of the FreeBSD crypt algorithm.  Not designed to be called except by {@link #crypt(String, String)}.
       */
      private static String to64(long v, int n)
      {
        String output = "";
    
        while (--n >= 0)
        {
          output += itoa64.charAt((int) (v & 0x3f));
          v >>=6;
        }
    
        return (output);
      }
    
      /**
       * FreeBSD crypt algorithm converted from C to Java.
       * 
       * @param pw Password to encrypt.
       * @param salt Salt to use during encryption.  If salt is longer than 8 characters it will be truncated to 8 characters.
       *             Also will only take characters up to a $ character.
       * @return String - FreeBSD encrypted password.
       * @throws java.security.NoSuchAlgorithmException System doesn't support MD5 algorithm.
       */
      private static String crypt(String pw, String salt) throws java.security.NoSuchAlgorithmException
      {
        final String magic = "$1$";
        String passwd, sp;
        byte[] finalVar;
        int pl, i, j;
        MessageDigest ctx, ctx1;
        long l;
    
        // Refine the Salt first
        sp = salt;
        
        // If it starts with the magic string, then skip that
        if (sp.startsWith(magic))
        {
          sp = sp.substring(magic.length(), sp.length());
        }
        
        // It stops at the first '$', max 8 chars
        if (sp.contains("$"))
        {
          sp = sp.substring(0, sp.indexOf("$"));
        }
        if (sp.length() > 8)
        {
          sp = sp.substring(0,8);
        }
    
        ctx = MessageDigest.getInstance("MD5");
    
        // The password first, since that is what is most unknown
        ctx.update(pw.getBytes());
        
        // Then our magic string
        ctx.update(magic.getBytes());
        
        // Then the raw salt
        ctx.update(salt.getBytes());
    
        ctx1 = MessageDigest.getInstance("MD5");
    
        // Then just as many characters of the MD5(pw,salt,pw)
        ctx1.update(pw.getBytes());
        ctx1.update(sp.getBytes());
        ctx1.update(pw.getBytes());
        finalVar = ctx1.digest();
        for (pl = pw.length(); pl > 0; pl -= 16)
        {
          ctx.update(finalVar, 0, pl>16 ? 16 : pl);
        }
    
        // Don't leave anything around in vm they could use.
        for (@SuppressWarnings("unused") byte item : finalVar)
        {
          item = (byte)0;
        }
        
        // Then something really weird...
        for (j = 0, i = pw.length(); i != 0; i >>= 1)
        {
          if ((i & 1) != 0)
          {
            ctx.update(finalVar[j]);
          }
          else
          {
            ctx.update(pw.getBytes()[j]);
          }
        }
        
        // Now make the output string
        passwd = magic;
        passwd += sp;
        passwd += "$";
        
        finalVar = ctx.digest();
        
        // and now, just to make sure things don't run too fast 
        // On a 60 Mhz Pentium this takes 34 msec, so you would
        // need 30 seconds to build a 1000 entry dictionary...
        for (i = 0; i < 1000; i++)
        {
          ctx1.reset();
          if ((i & 1) != 0)
          {
            ctx1.update(pw.getBytes());
          }
          else
          {
            ctx1.update(finalVar);
          }
          
          if ((i % 3) != 0)
          {
            ctx1.update(sp.getBytes());
          }
          if ((i % 7) != 0)
          {
            ctx1.update(pw.getBytes());
          }
          if ((i & 1) != 0)
          {
            ctx1.update(finalVar);
          }
          else
          {
            ctx1.update(pw.getBytes());
          }
          finalVar = ctx1.digest();
        }
        
        l = (finalVar[ 0]<<16) | (finalVar[ 6]<<8) | finalVar[12]; passwd += to64(l,4);
        l = (finalVar[ 1]<<16) | (finalVar[ 7]<<8) | finalVar[13]; passwd += to64(l,4);
        l = (finalVar[ 2]<<16) | (finalVar[ 8]<<8) | finalVar[14]; passwd += to64(l,4);
        l = (finalVar[ 3]<<16) | (finalVar[ 9]<<8) | finalVar[15]; passwd += to64(l,4);
        l = (finalVar[ 4]<<16) | (finalVar[10]<<8) | finalVar[ 5]; passwd += to64(l,4);
        l =                       finalVar[11]                   ; passwd += to64(l,2);
        
        
        // Don't leave anything around in VM they could use.
        for (@SuppressWarnings("unused") byte item : finalVar)
        {
          item = (byte)0;
        }        
        
        return passwd;
      }
      
      /**
       * Helper function for {@link #encrypt9(String)} method.  Generates part of the encrypted string and returns it back to the {@link #encrypt9(String)} method.
       *
       * @param pc Character to encrypt.
       * @param prev Previous series of encrypted characters or salt.
       * @param enc Current encoder values.
       * @return String - Encrypted version of the character (can be 2 to 4 characters).
       */
      private static String gapEncode(char pc, String prev, int[] enc) {
        String crypt = "";
        int ord = (int) pc;
        Deque<Integer> gaps = new LinkedList<Integer>();
        
        for (int x = enc.length - 1; x >= 0; x--) {
          gaps.addFirst(ord / enc[x]);
          ord %= enc[x];
        }
        
        for (Integer item : gaps) {
          item += ALPHA_NUM.get(prev) + 1;
          String c = prev = NUM_ALPHA[item % NUM_ALPHA.length];
          crypt += c;
        }
        
        return crypt;
      }
    }

    If anyone is interested I can look in to converting the decrypt for $9 passwords in to Java also and adding it to this class.

     



  • 10.  RE: Password encryption algorithm in Junos?

     
    Posted 03-06-2016 02:39

    Thanks dkasten!

     

    I would be interested to have decryption in Java.



  • 11.  RE: Password encryption algorithm in Junos?

    Posted 03-29-2016 01:11

    Junos put normal pre-share key in $9$ format by default, like OSPF and Radius share secret. Is there a command that forces all password/share secret to store in $1$ format? something like Cisco IOS “service password-encryption”



  • 12.  RE: Password encryption algorithm in Junos?

     
    Posted 04-06-2016 14:58

    Hi Ricky,

     

    Junos actually does this by default - all passwords are stored in either encrypted or hashed format depending on their usage.  

     

    You have to remember that some of these protocols use symmetric encryption and the router actually NEEDS to be able to decrypt the key in the config in order to operate the protocol.

     

    User authentication uses completely asymmetric encryption - eg: we don't care what the password is as long as the hash matches, so these can be one-way $1$ encrypted - the local box has a salt which it feeds into it's encryption algorithm of choice to generate and compare the hash of the user's password, thus never having to actually store it.

     

    Protocols like OSPF however need to transmit information across the network, which means both ends need a common way of decrypting the information, and one that isn't particularly processor intensive - thus the need for reversible/symmetric encryption (and storing keys in a reversible format).

     

    I hope this makes sense!

     



  • 13.  RE: Password encryption algorithm in Junos?

     
    Posted 06-27-2011 05:23

    Hi,

     

    not an answer but: Appearently JUNOS uses the underlying FreeBSD mechanisms as you'll find the same hash which you get from "show configuration | display set | match encr" in the /etc/master.passwd. And I strongly assume that then also a native version of crypt is used (see FreeBSD crypt man-page). You'd propably need an original BSD-machine, copy the hash and check if it works to verify. Hope this helps a little.

     

    Best Regards

     

    Ulf



  • 14.  RE: Password encryption algorithm in Junos?

    Posted 04-30-2018 03:16