diff --git a/README.md b/README.md index 842d140..23beaea 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ Unusual options: -rcc N {For passphrases - impose random camel-case; randomly uppercase the first N letters (default: 0)} +-rrcc N {For passphrases - impose random camel-case; randomly uppercase the last N letters (default: 0)} + At least one of the options -pw, -pp, or -k must be supplied. The keys, passwords, or passphrases produced by RandPassGenerator will be written to the standard output (stdout), so they can easily be redirected to a file. The -out option can also be used to write the output to a file. All messages are written to the standard error (stderr). Detailed log messages are appended to the specified log file - if the log file cannot be opened, then the tool will not run. diff --git a/RandPassGenerator/README.txt b/RandPassGenerator/README.txt index 3a1d6a4..ba8a92d 100644 --- a/RandPassGenerator/README.txt +++ b/RandPassGenerator/README.txt @@ -50,6 +50,8 @@ Unusual options: -sep S For chunk formatting, use S as the separator (default: -) -rcc N For passphrases, randomly upcase first N letters of each word (default: 0) + +-rrcc n For passphrases, randomly upcase last N letters of each word (default: 0) At least one of the options -pw, -pp, or -k must be supplied. The keys, passwords, or passphrases produced by RandPassGenerator will be written to the standard output (stdout), so they can easily be redirected to a file. The -out option can also be used to write the output to a file. All messages are written to the standard error (stderr). diff --git a/RandPassGenerator/src/gov/nsa/ia/gen/WordSet.java b/RandPassGenerator/src/gov/nsa/ia/gen/WordSet.java index 1791f35..3cfdbaa 100644 --- a/RandPassGenerator/src/gov/nsa/ia/gen/WordSet.java +++ b/RandPassGenerator/src/gov/nsa/ia/gen/WordSet.java @@ -367,6 +367,43 @@ public String randomUpcase(String wrd, int n, AbstractDRBG drbg) { return wb.toString(); } + /** + * Randomly upcase the last N letters of a provided word, + * drawing random from the given AbstractDRBG. If N is greater + * than or equal to the length of the input string, then all the + * letters are potentially subject to uppercase. + * + * @param wrd A string composed of letters + * @param n How many of the letters to possibly upcase at probability 1/2 + * @param drbg random source + * + * @return a new string of same length with some letters possibly converted to uppercase + */ + public String reverseRandomUpcase(String wrd, int n, AbstractDRBG drbg) { + if (n <= 0) return wrd; + + int len = wrd.length(); + int y = len-n; // Measuring from the end of the word, go back n letters, start Random Upcase at letters equal to y + Integer ri; + StringBuilder wb = new StringBuilder(len); + + for(int i = 0; i < len; i++) { + char c = wrd.charAt(i); + if (i >= y) { + ri = drbg.generateByte(); + if (ri == null) { + logger.warning("WordSet - generateByte returned null, drbg problem, cannot upcase."); + return null; + } + if (ri.intValue() > 127) { + c = Character.toUpperCase(c); + } + } + wb.append(c); + } + + return wb.toString(); + } // TESTING diff --git a/RandPassGenerator/src/gov/nsa/ia/pass/RandPassGenerator.java b/RandPassGenerator/src/gov/nsa/ia/pass/RandPassGenerator.java index a7edde4..3aa4e22 100644 --- a/RandPassGenerator/src/gov/nsa/ia/pass/RandPassGenerator.java +++ b/RandPassGenerator/src/gov/nsa/ia/pass/RandPassGenerator.java @@ -418,9 +418,10 @@ else if (!(Character.isLetterOrDigit(charsets.charAt(ix)))) { * @param wordlist URL to the wordlist to use, or null for default * @param maxWordLen maximum length of a word to use in the passphrase, <3 means use default * @param ruc random upcase the first ruc letters, 0 or positive + * @param rruc random upcase the last rruc letters, 0 or positive * @return number of passphrases generated, or -1 on error. */ - public int generatePassphrases(int count, int strength, URL wordlist, int maxWordLen, int ruc) { + public int generatePassphrases(int count, int strength, URL wordlist, int maxWordLen, int ruc, int rruc) { WordSet ws; AbstractDRBG drbg; @@ -430,6 +431,7 @@ public int generatePassphrases(int count, int strength, URL wordlist, int maxWor return -1; } if (ruc < 0) ruc = 0; + if (rruc < 0) rruc = 0; drbg = randman.getDRBG(); if (!(drbg.isOkay())) { @@ -474,6 +476,16 @@ public int generatePassphrases(int count, int strength, URL wordlist, int maxWor if (wrd == null) { logger.warning("RandPassGen - fatal error in trying to randomly upcase a word"); return -1; + } + // if rruc <= 0 then this has no effect, we can randomly upcase both from the front and the back + // Debug - Original Below + // wrd = ws.reverseRandomUpcase(s, rruc, drbg); + // Debug - New below + wrd = ws.reverseRandomUpcase(wrd, rruc, drbg); + + if (wrd == null) { + logger.warning("RandPassGen - fatal error in trying to randomly reverse upcase a word"); + return -1; } // add word to the passphrase sj.add(wrd); @@ -706,6 +718,7 @@ private static OptionManager makeOptions() { ret.addOption("decrypt", "Decrypt an encrypted key file using password", true, "-decrypt", null); ret.addOption("enc", "Encrypt each key to a file using password (only for -k)", false, "-enc", null); ret.addOption("randUpcase", "For passphrases, apply uppercase randomly to first N letters of each word", true, "-rcc", null); + ret.addOption("reverseRandUpcase", "For passphrases, apply uppercase randomly to last N letters of each word", true, "-rrcc", null); return ret; } @@ -763,6 +776,7 @@ public static void main(String [] args) { String decryptFilePath = opt.getValue("decrypt"); boolean enc = opt.getValueAsBoolean("enc"); int randUpcase = opt.getValueAsInt("randUpcase"); + int reverseRandUpcase = opt.getValueAsInt("reverseRandUpcase"); // check for something to do if (decryptFilePath != null) { @@ -855,6 +869,16 @@ public static void main(String [] args) { rpg.getLogger().info("Random upcase enabled for first " + randUpcase + " letters of passphrases"); } + // figure out if we are doing reverse random upcasing + if (reverseRandUpcase <= 0) { + reverseRandUpcase = 0; + } else { + if (verbose) { + System.err.println("Using reverse random upcase on last " + reverseRandUpcase + " letters."); + } + rpg.getLogger().info("Random upcase enabled for last " + reverseRandUpcase + " letters of passphrases"); + } + // get the URL for the wordlist URL ppURL = null; if (ppurl != null && ppurl.length() > 0) { @@ -864,7 +888,7 @@ public static void main(String [] args) { rpg.getLogger().warning("RandPassGen - bad word list URL, exception: " + ue); } } - cnt = rpg.generatePassphrases(numPassphrases, strength, ppURL, maxWordLen, randUpcase); + cnt = rpg.generatePassphrases(numPassphrases, strength, ppURL, maxWordLen, randUpcase, reverseRandUpcase); if (cnt <= 0) { rpg.message("Failed to generate passphrases"); rpg.getLogger().warning("Tried to generate " + numPassphrases + " passphrases, but failed.");