23
23
import org .apache .commons .cli .HelpFormatter ;
24
24
import org .apache .commons .cli .Option ;
25
25
import org .apache .commons .cli .Options ;
26
- import org .apache .commons .cli .PosixParser ;
26
+ import org .apache .commons .cli .DefaultParser ;
27
27
import org .apache .shiro .authc .credential .DefaultPasswordService ;
28
28
import org .apache .shiro .codec .Base64 ;
29
29
import org .apache .shiro .codec .Hex ;
30
30
import org .apache .shiro .crypto .SecureRandomNumberGenerator ;
31
31
import org .apache .shiro .crypto .UnknownAlgorithmException ;
32
- import org .apache .shiro .crypto .hash .SimpleHash ;
32
+ import org .apache .shiro .crypto .hash .DefaultHashService ;
33
+ import org .apache .shiro .crypto .hash .Hash ;
34
+ import org .apache .shiro .crypto .hash .HashRequest ;
35
+ import org .apache .shiro .crypto .hash .SimpleHashRequest ;
33
36
import org .apache .shiro .crypto .hash .format .DefaultHashFormatFactory ;
34
37
import org .apache .shiro .crypto .hash .format .HashFormat ;
35
38
import org .apache .shiro .crypto .hash .format .HashFormatFactory ;
@@ -77,6 +80,8 @@ public final class Hasher {
77
80
private static final Option SALT_GEN = new Option ("gs" , "gensalt" , false , "generate and use a random salt. Defaults to true when password hashing, false otherwise." );
78
81
private static final Option NO_SALT_GEN = new Option ("ngs" , "nogensalt" , false , "do NOT generate and use a random salt (valid during password hashing)." );
79
82
private static final Option SALT_GEN_SIZE = new Option ("gss" , "gensaltsize" , true , "the number of salt bits (not bytes!) to generate. Defaults to 128." );
83
+ private static final Option PRIVATE_SALT = new Option ("ps" , "privatesalt" , true , "use the specified private salt. <arg> is plaintext." );
84
+ private static final Option PRIVATE_SALT_BYTES = new Option ("psb" , "privatesaltbytes" , true , "use the specified private salt bytes. <arg> is hex or base64 encoded text." );
80
85
81
86
private static final String SALT_MUTEX_MSG = createMutexMessage (SALT , SALT_BYTES );
82
87
@@ -92,12 +97,13 @@ public final class Hasher {
92
97
93
98
public static void main (String [] args ) {
94
99
95
- CommandLineParser parser = new PosixParser ();
100
+ CommandLineParser parser = new DefaultParser ();
96
101
97
102
Options options = new Options ();
98
103
options .addOption (HELP ).addOption (DEBUG ).addOption (ALGORITHM ).addOption (ITERATIONS );
99
104
options .addOption (RESOURCE ).addOption (PASSWORD ).addOption (PASSWORD_NC );
100
105
options .addOption (SALT ).addOption (SALT_BYTES ).addOption (SALT_GEN ).addOption (SALT_GEN_SIZE ).addOption (NO_SALT_GEN );
106
+ options .addOption (PRIVATE_SALT ).addOption (PRIVATE_SALT_BYTES );
101
107
options .addOption (FORMAT );
102
108
103
109
boolean debug = false ;
@@ -110,6 +116,8 @@ public static void main(String[] args) {
110
116
String saltBytesString = null ;
111
117
boolean generateSalt = false ;
112
118
int generatedSaltSize = DEFAULT_GENERATED_SALT_SIZE ;
119
+ String privateSaltString = null ;
120
+ String privateSaltBytesString = null ;
113
121
114
122
String formatString = null ;
115
123
@@ -161,6 +169,12 @@ public static void main(String[] args) {
161
169
throw new IllegalArgumentException ("Generated salt size must be a multiple of 8 (e.g. 128, 192, 256, 512, etc)." );
162
170
}
163
171
}
172
+ if (line .hasOption (PRIVATE_SALT .getOpt ())) {
173
+ privateSaltString = line .getOptionValue (PRIVATE_SALT .getOpt ());
174
+ }
175
+ if (line .hasOption (PRIVATE_SALT_BYTES .getOpt ())) {
176
+ privateSaltBytesString = line .getOptionValue (PRIVATE_SALT_BYTES .getOpt ());
177
+ }
164
178
if (line .hasOption (FORMAT .getOpt ())) {
165
179
formatString = line .getOptionValue (FORMAT .getOpt ());
166
180
}
@@ -209,9 +223,13 @@ public static void main(String[] args) {
209
223
}
210
224
}
211
225
212
- ByteSource salt = getSalt (saltString , saltBytesString , generateSalt , generatedSaltSize );
226
+ ByteSource publicSalt = getSalt (saltString , saltBytesString , generateSalt , generatedSaltSize );
227
+ ByteSource privateSalt = getSalt (privateSaltString , privateSaltBytesString , false , generatedSaltSize );
228
+ HashRequest hashRequest = new SimpleHashRequest (algorithm , ByteSource .Util .bytes (source ), publicSalt , iterations );
213
229
214
- SimpleHash hash = new SimpleHash (algorithm , source , salt , iterations );
230
+ DefaultHashService hashService = new DefaultHashService ();
231
+ hashService .setPrivateSalt (privateSalt );
232
+ Hash hash = hashService .computeHash (hashRequest );
215
233
216
234
if (formatString == null ) {
217
235
//Output format was not specified. Default to 'shiro1' when password hashing, and 'hex' for
@@ -375,6 +393,17 @@ private static void printHelp(Options options, Exception e, boolean debug) {
375
393
"encoding. If you prefer to use hex encoding, additionally use the\n " +
376
394
"-sgh/--saltgeneratedhex option." +
377
395
"\n \n " +
396
+ "Specifying a private salt:" +
397
+ "\n \n " +
398
+ "You may specify a private salt using the -ps/--privatesalt option followed\n " +
399
+ "by the private salt value. If the private salt value is a base64 or hex \n " +
400
+ "string representing a byte array, you must specify the -psb/--privatesaltbytes\n " +
401
+ "option to indicate this, otherwise the text value bytes will be used directly." +
402
+ "\n \n " +
403
+ "When using -psb/--privatesaltbytes, the -ps/--privatesalt value is expected to\n " +
404
+ "be a base64-encoded string by default. If the value is a hex-encoded string,\n " +
405
+ "you must prefix the string with 0x (zero x) to indicate a hex value." +
406
+ "\n \n " +
378
407
"Files, URLs and classpath resources:\n " +
379
408
"---------------------------------\n " +
380
409
"If using the -r/--resource option, the <value> represents a resource path.\n " +
0 commit comments