📄 scar.java
字号:
// Own methods//........................................................................... /** Set default properties. */ void initDefaults () { trace(IN, "initDefaults()"); header = DEFAULT_HEADER; footer = DEFAULT_FOOTER; comment = DEFAULT_COMMENT; cipherAlgorithm = DEFAULT_CIPHER; passPhrase = DEFAULT_PASS_PHRASE; mdAlgorithm = DEFAULT_MD; salt = DEFAULT_SALT; iterations = DEFAULT_ITERATIONS; trace(OUT, "initDefaults()"); } /** Process command line arguments. */ public void processOptions (String[] args) { trace(IN, "processOptions()"); int argc = args.length; debug("Command line arguments [..."); for (int i = 0; i < argc; i++) debug(" args["+(i+1)+"]: " + args[i]); debug("...]"); if (argc == 0) printUsage();// System.out.println(// "(type \"java cryptix.tools.Scar\" with no arguments for help)\n\n"); Vector files = new Vector(); int i = -1; String cmd = ""; boolean next = true; filter.reset(); // we'll use the next counter to count the number of crypto-related // args designated on the command line. If the count at the end of // processing the command line remains 0 then we'll issue a warning // to the user that it's bad practice to have all these arguments // used from values stored in the clear on the hard disk. int cargs = 0; while (true) { if (next) { i += 1; if (i >= argc) break; else cmd = args[i]; } else cmd = "-" + cmd.substring(2); if (cmd.startsWith("-a")) { asciify = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-d")) { decrypting = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-e")) { encrypting = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-r")) { recursion = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-u")) { useDirInfo = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-v")) { verbose = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-w")) { wipeSource = true; next = (cmd.length() == 2); } else if (cmd.startsWith("-c")) { // cipher algorithm cipherAlgorithm = args[i + 1]; i += 1; next = true; cargs++; } else if (cmd.startsWith("-p")) { // pass-phrase passPhrase = args[i + 1]; i += 1; next = true; cargs++; } else if (cmd.startsWith("-m")) { // md algorithm mdAlgorithm = args[i + 1]; i += 1; next = true; cargs++; } else if (cmd.startsWith("-s")) { // md salt salt = args[i + 1]; i += 1; next = true; cargs++; } else if (cmd.startsWith("-i")) { // md iterations iterations = Integer.parseInt(args[i + 1]); i += 1; next = true; cargs++; } // // in some cases java expands the input (if it consist of "*.*") // and sometimes it doesn't // else if (! files.contains(cmd)) files.addElement(cmd); } if (decrypting) { if (encrypting || recursion || asciify) halt("Found at least one conflicting option to Decryption"); } else encrypting = true; if (cipherAlgorithm.length() > 1 && (cipherAlgorithm.startsWith("\"") || cipherAlgorithm.startsWith("'"))) cipherAlgorithm = cipherAlgorithm.substring(2, cipherAlgorithm.length() - 2); if (passPhrase.length() > 1 && (passPhrase.startsWith("\"") || passPhrase.startsWith("'"))) passPhrase = passPhrase.substring(2, passPhrase.length() - 2); if (mdAlgorithm.length() > 1 && (mdAlgorithm.startsWith("\"") || mdAlgorithm.startsWith("'"))) mdAlgorithm = mdAlgorithm.substring(2, mdAlgorithm.length() - 2); if (salt.length() > 1 && (salt.startsWith("\"") || salt.startsWith("'"))) salt = salt.substring(2, salt.length() - 2); // now the filenames files.trimToSize(); if (files.size() == 0) // neither input nor output specified halt("Missing <input> path-name"); else if (files.size() == 1) { // assume input only specified input = (String) files.elementAt(0); output = System.getProperty( "user.dir", new File("." + fs).getAbsolutePath()); } else if (files.size() == 2) { // both input and output specified input = (String) files.elementAt(0); output = (String) files.elementAt(1); } else halt("Too many files"); if (input.startsWith("\"") || input.startsWith("'")) input = input.substring(2, input.length() - 2); // input may be a valid File object reference or a wildcard mask if (input.indexOf("*") != -1 || input.indexOf("?") != -1) { // it's a mask filter.setMask((new File(input)).getName()); input = (new File((new File(input)).getAbsolutePath())).getParent(); } if (output.startsWith("\"") || output.startsWith("'")) output = output.substring(2, output.length() - 2); if (encrypting) if (decrypting || useDirInfo || output == null) halt("Found at least one conflicting option to Encryption"); inFile = new File(input); // Make sure specified source exists if (! inFile.exists()) halt("Input <" + input + "> not found"); if (! inFile.canRead()) // and is readable halt("Input <" + input + "> is unreadable"); // finally shouldn't be a directory if decrypting if (decrypting && inFile.isDirectory()) halt( "Decryption required but input <" + input + "> is a directory"); // output has to be a file when encrypting or // a directory when decrypting outFile = new File(output); if (encrypting && outFile.isDirectory()) halt("Encryption required but output <" + output + "> is a directory"); else if (decrypting && ! outFile.isDirectory()) halt("Decryption required but output <" + output + "> is not a directory"); if (cargs == 0) System.out.println( "WARNING:\n" + " You did not specify at least one of: cipher algorithm, pass-phrase,\n" + " message digest algorithm, message digest salt value or message\n" + " digest iteration count; instead you are relying on default values\n" + " for these arguments. Please note that it is bad practice not to\n" + " vary at least one of those parameters. Failing to do so reduces\n" + " the efforts of an attacker trying to decrypt your scar."); temp = getTempFile(); // create 1 temp file trace(OUT, "processOptions()"); } /** * Print an error message to System.err and halts execution returning * -1 to the JVM. * * @param s a message to output on System.err */ private void halt (String s) { trace("halt()"); debug("halt() --> " + s); System.err.println("\n*** " + s + "..."); System.exit(-1); } /** write help text and quit. */ private void printUsage () { trace(IN, "printUsage()"); System.out.println( "NAME\n" + " Scar: Strong Cryptographic ARchiver using Cryptix IJCE\n" + " (International Java Cryptography Extensions).\n\n" + "SYNTAX\n" + " java cryptix.tools.Scar\n" + " [ -e ]\n" + " [ -a ]\n" + " [ -r ]\n" + " [ -v ]\n" + " [ -w ]\n" + " [ -c cipher]\n" + " [ -p passphrase]\n" + " [ -m s2k_message_digest]\n" + " [ -s s2k_salt]\n" + " [ -i s2k_iterations]\n" + " input\n" + " output\n\n" + " java cryptix.tools.Scar\n" + " -d\n" + " [ -u ]\n" + " [ -v ]\n" + " [ -w ]\n" + " [ -c cipher]\n" + " [ -p passphrase]\n" + " [ -m s2k_message_digest]\n" + " [ -s s2k_salt]\n" + " [ -i s2k_iterations]\n" + " input\n" + " [output]\n\n" + "DESCRIPTION\n" + " Scar reads and compresses input and writes the encrypted\n" + " result to output. It also does the inverse operation: reads\n" + " and decrypts input and decompresses the resulting data into\n" + " output.\n\n" + " By default both encryption and decryption are done using the\n" + " 'Square' cipher algorithm (designed by Joan Daemen & Vincent\n" + " Rijmen) in Cipher Electronic Codebook (CBC) mode padded with\n" + " the method described in PKCS#7.\n\n" + " The cipher's secret session key is derived from a passphrase\n" + " supplied by the user through an S2K algorithm. The types and\n" + " differences of such S2K algorithms are described in Open-PGP\n" + " I.E.T.F document (draft-ietf-openpgp-formats.txt) dated 9/97.\n" + " This scar uses Simple, Salted and Salted-Iterated S2K variants.\n" + " The default message digest used with all S2K variants is\n" + " RIPEMD-160.\n\n" + " As mentioned earlier, the encryption and decryption are not\n" + " done on the data itself but on a ZIP-ped image. ZIPping is\n" + " accomplished using the DEFLATE method at its maximum level\n" + " (best size).\n\n" + " When a command line is entered, scar tries to load a properties\n" + " file named \"scar.properties\" from the user home directory,\n" + " the value of which is returned by Java's property \"user.home\"\n\n" + "OPTIONS\n" + " -a Asciify (Encryption). Encode the output in Base-64 format\n" + " (RFC-1521) making it suitable for Internet transmission.\n\n" + " -d Decryption.\n\n" + " -e Encryption (default).\n\n" + " -r Recurse (Encryption). Apply the process repetitively to\n" + " sub-directories found in input.\n\n" + " -u Use directory information (Decryption). Recreate original\n" + " directory tree structure.\n\n" + " -v Verbose. Print notification messages to System.out.\n\n" + " -w Wipe the source input after processing.\n\n" + " -c <cipher>\n" + " Cipher algorithm name ('Square' by default). Other values\n" + " can be any block cipher algorithm installed and accessible\n" + " on user platform that conforms to Sun(R)'s JCE or Cryptix\n" + " IJCE. With Cryptix security provider installed choices are\n" + " Blowfish, CAST5, RC4, IDEA, SAFER and LOKI91 in addition to\n" + " Square.\n\n" + " -p <passphrase>\n" + " An alphanumeric string with no spaces. If contains spaces\n" + " then include within double quotes. If not supplied use \"\".\n\n" + " -m <s2k_message_digest>\n" + " Message digest algorithm name ('RIPEMD-160' by default).\n" + " Other values can be any message digest algorithm installed\n" + " and accessible on user platform that conforms to Sun (R)'s\n" + " JCE or Cryptix's IJCE. With Cryptix security provider this\n" + " can be, in addition to 'RIPEMD-160', HAVAL, MD2, MD4, MD5,\n" + " SHA-1 and RIPEMD-128.\n\n"+ " -s <s2k_salt>\n" + " S2K salt value. If not supplied a Simple or Iterated S2K\n" + " algorithm will be used, depending on whether an iteration\n" + " count was supplied or not.\n\n" + " -i <s2k_iterations>\n" + " S2K iteration count. If a positive value is not provided,\n" + " a Simple or Salted S2K algorithm will be used, depending\n" + " on whether a salt value is given or not.\n\n" + " <input>\n" + " Input file or directory pathname. If the pathname includes\n" + " spaces, then it should be enclosed within double quotes.\n" + " Wild characters such as '*' (any number of characters) and\n" + " '?' (any one character) are allowed, in such case <input>\n" + " acts as a filter for actual selection of input file(s).\n" + " When a filter is used, it should be enclosed within \"\".\n\n" + " <output>\n" + " Output file or directory. When decrypting this should be\n" + " a directory pathname. If absent, in the case of decryption,\n" + " use the current directory.\n\n" + "COPYRIGHT\n" + " Copyright (c) 1997, 1998 Systemics Ltd. on behalf of\n" + " the Cryptix Development Team. All rights reserved.\n"); trace(OUT, "printUsage()"); System.exit(0); } /** * Method to return a randomly built string to be used as the name of a * temporary file in the current working directory */ private File getTempFile () { trace(IN, "getTempFile()"); int x; File f; do { x = (int)(Math.abs(random.nextDouble()) * 1000000); f = new File("." + fs, 'F' + String.valueOf(x)); } while (f.exists()); debug("getTempFile() --> " + f.getName()); trace(OUT, "getTempFile()"); return f; } /** main action. */ public void run () { trace(IN, "run()"); notify("\nActual parameters"); notify("\tcipher algorithm: \"" + cipherAlgorithm + "\""); notify("\t pass-phrase: \"" + passPhrase + "\""); notify("\t message digest: \"" + mdAlgorithm + "\""); notify("\t md salt: \"" + salt + "\""); notify("\t md iterations: " + iterations); notify("\t input file(s): <" + input + ">"); notify("\t output file/dir: <" + output + ">"); notify("\tselection filter: <" + filter + ">"); int n; FileInputStream fis = null; FileOutputStream fos = null; try { Cipher cipher = null; try { cipher = Cipher.getInstance(cipherAlgorithm + "/CBC/PKCS#7"); } catch (NoSuchAlgorithmException ex1) { throw new CryptixException( "Unable to instantiate a " + cipherAlgorithm + " cipher object in CBC mode with PKCS#7 padding."); } int ivLen = ((FeedbackCipher) cipher).getInitializationVectorLength();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -