📄 scar.java
字号:
byte[] iv = new byte[ivLen]; // IV all zeroes. Not important since we'll start encryption // with a random block. ((FeedbackCipher) cipher).setInitializationVector(iv); SecretKey key = s2k(); if (encrypting) { notify("\nZipping"); // compressing ZipOutputStream zipo = new ZipOutputStream(new FileOutputStream(temp)); zipo.setComment("Made with scar"); zipo.setMethod(ZipOutputStream.DEFLATED); zipo.setLevel(9); zip(inFile, zipo, 0); // if considering the selection criteria (as per our filter) // no files were found and processed we have to stop here // otherwise we'll get a ZipException thrown in our face if // we try to close it. if (count == 0) halt( "No files were found that satisfy the selection criteria"); zipo.flush(); zipo.finish(); zipo.close(); notify("\nEncrypting"); // encrypting temp2 = getTempFile(); fos = new FileOutputStream(temp2); cipher.initEncrypt(key); CipherInputStream cis = new CipherInputStream(new FileInputStream(temp), cipher); // generate a random block as long as the iv, encrypt it // and write it as the first block. Doing so, and since // we run our cipher in CBC mode, ensures that the same // text with the same key will not generate the same // output. random.nextBytes(iv); fos.write(iv); // write a magic word to test when decrypting in order // to ensure that it was encrypted by us or we used the // correct properties fos.write(MAGIC); // process user file(s) while ((n = cis.read(buffer)) != -1) fos.write(buffer, 0, n); cis.close(); fos.close(); if (asciify) { // asciify temp2 to out notify("\nAsciifying"); fis = new FileInputStream(temp2); ScarOutputStream cros = new ScarOutputStream(new FileOutputStream(outFile)); while ((n = fis.read(buffer)) != -1) cros.write(buffer, 0, n); fis.close(); cros.flush(); cros.close(); } else { // rename temp2 to out outFile.delete(); temp2.renameTo(outFile); } temp.delete(); temp2.delete(); } else { // decrypt notify("\nDe-asciifying"); // de-asciify (if applicable) fos = new FileOutputStream(temp); ScarInputStream cris = null; try { cris = new ScarInputStream(new FileInputStream(inFile)); while ((n = cris.read(buffer)) != -1) fos.write(buffer, 0, n); cris.close(); fos.flush(); fos.close(); fis = new FileInputStream(temp); } catch (IOException e1) { // most likely not a scar debug("Warning: " + e1.getMessage()); notify("Warning: " + e1.getMessage()); fis = new FileInputStream(inFile); } notify("\nDecrypting"); // decrypting temp2 = getTempFile(); fos = new FileOutputStream(temp2); cipher.initDecrypt(key); CipherOutputStream cos = new CipherOutputStream(fos, cipher); // read a block as long as the iv and discard it. n = fis.read(buffer, 0, iv.length); debug("length of alleged iv: " + n); if (n != iv.length) throw new CryptixException("File too short to be a scar (1)."); // next check if there is a magic word put there by us during // encryption phase. if not then this file is not ours or was // produced by a different set of properties. n = fis.read(buffer, 0, MAGIC.length); if (n == -1 || n != MAGIC.length) throw new CryptixException("File too short to be a scar (2)."); else { debug("Magic word: " + new String(buffer, 0, MAGIC.length)); if (! (new String(buffer, 0, MAGIC.length)). equals(MAGIC_STRING)) throw new CryptixException( "File doesn't look to be a scar. If it is, it was " + "produced using a different set of properties."); } // read the rest while ((n = fis.read(buffer)) != -1) cos.write(buffer, 0, n); cos.flush(); cos.close(); fis.close(); fos.close(); notify("\nUnzipping"); // unzipping ZipInputStream zipi = new ZipInputStream(new FileInputStream(temp2)); unzip(zipi, outFile); zipi.close(); temp.delete(); temp2.delete(); } if (wipeSource) { // wipe source notify("\nDeleting input"); wipe(inFile, 0); } } catch (CryptixException ex1) { debug(ex1.getMessage()); notify("\n--- Exception: " + ex1.getMessage()); } catch (Exception ex2) { ex2.printStackTrace(); } finally { if (temp != null) try { temp.delete(); } catch (Exception e1) {} if (temp2 != null) try { temp2.delete(); } catch (Exception e2) {} } trace(OUT, "run()"); } /** * S2K algorithm. When used with Cryptix security provider it will not * throw any exception. */ private SecretKey s2k () throws CloneNotSupportedException, InvalidKeyException { trace(IN, "s2k()"); MessageDigest md = null; try { md = MessageDigest.getInstance(mdAlgorithm); } catch (NoSuchAlgorithmException ex1) { throw new CryptixException( "Unable to instantiate a " + mdAlgorithm + " message digest object"); } // // one instance of the md algorithm may not be enough. the // total number depends on (a) the output size of the md // and (b) the default key length of the cipher we will use. // // (a) can be obtained by calling the digest() method and // measuring the output length while (b), and thanks to the // IJCE (is anybody from SUN reading this? ;-), can be // obtained by a call to the getDefaultKeyLength() IJCE // method from a RawKeyGenerator instance. // // do (a) and follow it by (b) // int mdLength = md.digest().length; RawKeyGenerator rkg = null; try { rkg = (RawKeyGenerator) KeyGenerator.getInstance(cipherAlgorithm); } catch (NoSuchAlgorithmException ex1) { throw new CryptixException( "Unable to instantiate a " + cipherAlgorithm + " key-generator object"); } int keyLength = rkg.getDefaultKeyLength(); // // let's have a look at the ietf-draft. here what it says: // // If the hash size is greater than or equal to the session key // size, the leftmost octets of the hash are used as the key. // // If the hash size is less than the key size, multiple instances // of the hash context are created -- enough to produce the required // key data. These instances are preloaded with 0, 1, 2, ... octets // of zeroes (that is to say, the first instance has no preloading, // the second gets preloaded with 1 octet of zero, the third is // preloaded with two octets of zeros, and so forth). // Vector mds = new Vector(); int lensofar = 0; do { mds.addElement(md.clone()); // always add a clone md.update((byte) 0x00); lensofar += mdLength; } while (lensofar < keyLength); // // build a salted byte[] consisting of the salt bytes prepended to // the pass-phrase ones to process through the previous md(s) // int s = salt.length(); int p = passPhrase.length(); byte[] salted = new byte[s + p]; if (s != 0) System.arraycopy(salt.getBytes(), 0, salted, 0, s); System.arraycopy(passPhrase.getBytes(), 0, salted, s, p); int countsofar = 0; int mdCount = mds.size(); do { for (int i = 0; i < mdCount; i++) ((MessageDigest) mds.elementAt(i)).update(salted); countsofar++; } while (countsofar < iterations); // does it at least once // // that's it. time now to assemble the lot and hand it over to // the key-generator object. // byte[] keyData = new byte[keyLength]; byte[] mdBytes; int length; lensofar = 0; for (int i = 0; i < mdCount; i++) { mdBytes = ((MessageDigest) mds.elementAt(i)).digest(); length = (lensofar + mdLength > keyLength) ? keyLength - lensofar : mdLength; System.arraycopy(mdBytes, 0, keyData, lensofar, length); lensofar += length; } rkg.setWeakAllowed(true); // we don't care about key strength here SecretKey key = null; try { key = rkg.generateKey(keyData); } catch (WeakKeyException ex2) { /* will never happen */ } trace(OUT, "s2k()"); return key; } /** * Write notification message to System.out. * * @param s string to output to System.out. */ private void notify (String s) { trace(IN, "notify()"); if (verbose) System.out.println(s + "..."); trace(OUT, "notify()"); } /** * Zip files and/or directories to a ZipOutputStream. * * @param source source file or directory. * @param zip destination zip output stream. * @param level depth level in the recursion tree of this method. * Used to distinguish top level directory from sub- * directories (whether to apply recursion or not). * @exception IOException if operation fails */ public void zip (File source, ZipOutputStream zip, int level) throws FileNotFoundException, IOException { trace(IN, "zip("+level+")"); FileInputStream fis = null; // input stream to read input data if (source.isFile()) { try { count += 1; fis = new FileInputStream(source); String sf = source.getCanonicalPath(); int n = sf.indexOf(fs); // get rid of home drive reference if (n != -1) sf = sf.substring(n + 1); // PKZIP (if you want to check at this stage) wants // '/' as file separator sf = sf.replace(fs.charAt(0), '/'); notify("\t " + sf); zip.putNextEntry(new ZipEntry(sf)); while ((n = fis.read(buffer)) != -1) zip.write(buffer, 0, n); } finally { if (fis != null) try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } else if (source.isDirectory()) { if (level == 0 || (level != 0 && recursion)) { // top level or lower level but recursion required String[] entries = source.list(filter); for (int i = 0; i < entries.length; i++) zip(new File(source, entries[i]), zip, level + 1); } } trace(OUT, "zip("+level+")"); } /** * unzip files and/or directories to a destination. * * @param src source zip stream. * @param dest destination File object. * @exception IOException if operation fails */ public void unzip (ZipInputStream zip, File dest) throws FileNotFoundException, IOException { trace(IN, "unzip()"); ZipEntry ze; FileOutputStream fos = null; while ((ze = zip.getNextEntry()) != null) { if (ze.isDirectory()) continue; try { int n; String sf = ze.getName(); if (! useDirInfo) { // PKZIP uses '/' as file separator n = sf.lastIndexOf("/"); if (n != -1) sf = sf.substring(n + 1); } else sf = sf.replace('/', fs.charAt(0)); String destPath = dest.getPath(); sf = destPath.endsWith(fs) ? destPath + sf : destPath + fs + sf; notify("\t " + sf); File f = new File(sf); if (useDirInfo) new File(f.getParent()).mkdirs(); fos = new FileOutputStream(f); while ((n = zip.read(buffer)) != -1) fos.write(buffer, 0, n); } finally { if (fos != null) try { fos.flush(); fos.close(); } catch (IOException e) { e.printStackTrace(); } } } trace(OUT, "unzip()"); } /** * Wipe source input. If input is a directory than wipe all files * inside and, depending on the value set in the 'recursion' switch, * repeat same for sub-directories. Finally try to delete top level * directory. If this latter is not empty (recursion is inhibited and * at leat one sub-directory is still alive) no deletion occurs.<p> *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -