package org.spongycastle.openpgp.examples; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Security; import java.util.Iterator; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.jce.provider.BouncyCastleProvider; import org.spongycastle.openpgp.PGPCompressedData; import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedDataGenerator; import org.spongycastle.openpgp.PGPEncryptedDataList; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPLiteralData; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPOnePassSignatureList; import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPSecretKeyRingCollection; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; import org.spongycastle.util.io.Streams; /** * A simple utility class that encrypts/decrypts public key based * encryption files. * <p> * To encrypt a file: KeyBasedFileProcessor -e [-a|-ai] fileName publicKeyFile.<br> * If -a is specified the output file will be "ascii-armored". * If -i is specified the output file will be have integrity checking added. * <p> * To decrypt: KeyBasedFileProcessor -d fileName secretKeyFile passPhrase. * <p> * Note 1: this example will silently overwrite files, nor does it pay any attention to * the specification of "_CONSOLE" in the filename. It also expects that a single pass phrase * will have been used. * <p> * Note 2: if an empty file name has been specified in the literal data object contained in the * encrypted packet a file with the name filename.out will be generated in the current working directory. */ public class KeyBasedFileProcessor { private static void decryptFile( String inputFileName, String keyFileName, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException { InputStream in = new BufferedInputStream(new FileInputStream(inputFileName)); InputStream keyIn = new BufferedInputStream(new FileInputStream(keyFileName)); decryptFile(in, keyIn, passwd, defaultFileName); keyIn.close(); in.close(); } /** * decrypt the passed in message stream */ private static void decryptFile( InputStream in, InputStream keyIn, char[] passwd, String defaultFileName) throws IOException, NoSuchProviderException { in = PGPUtil.getDecoderStream(in); try { PGPObjectFactory pgpF = new PGPObjectFactory(in); PGPEncryptedDataList enc; Object o = pgpF.nextObject(); // // the first object might be a PGP marker packet. // if (o instanceof PGPEncryptedDataList) { enc = (PGPEncryptedDataList)o; } else { enc = (PGPEncryptedDataList)pgpF.nextObject(); } // // find the secret key // Iterator it = enc.getEncryptedDataObjects(); PGPPrivateKey sKey = null; PGPPublicKeyEncryptedData pbe = null; PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection( PGPUtil.getDecoderStream(keyIn)); while (sKey == null && it.hasNext()) { pbe = (PGPPublicKeyEncryptedData)it.next(); sKey = PGPExampleUtil.findSecretKey(pgpSec, pbe.getKeyID(), passwd); } if (sKey == null) { throw new IllegalArgumentException("secret key for message not found."); } InputStream clear = pbe.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("SC").build(sKey)); PGPObjectFactory plainFact = new PGPObjectFactory(clear); Object message = plainFact.nextObject(); if (message instanceof PGPCompressedData) { PGPCompressedData cData = (PGPCompressedData)message; PGPObjectFactory pgpFact = new PGPObjectFactory(cData.getDataStream()); message = pgpFact.nextObject(); } if (message instanceof PGPLiteralData) { PGPLiteralData ld = (PGPLiteralData)message; String outFileName = ld.getFileName(); if (outFileName.length() == 0) { outFileName = defaultFileName; } InputStream unc = ld.getInputStream(); OutputStream fOut = new BufferedOutputStream(new FileOutputStream(outFileName)); Streams.pipeAll(unc, fOut); fOut.close(); } else if (message instanceof PGPOnePassSignatureList) { throw new PGPException("encrypted message contains a signed message - not literal data."); } else { throw new PGPException("message is not a simple encrypted file - type unknown."); } if (pbe.isIntegrityProtected()) { if (!pbe.verify()) { System.err.println("message failed integrity check"); } else { System.err.println("message integrity check passed"); } } else { System.err.println("no message integrity check"); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } } private static void encryptFile( String outputFileName, String inputFileName, String encKeyFileName, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException, PGPException { OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFileName)); PGPPublicKey encKey = PGPExampleUtil.readPublicKey(encKeyFileName); encryptFile(out, inputFileName, encKey, armor, withIntegrityCheck); out.close(); } private static void encryptFile( OutputStream out, String fileName, PGPPublicKey encKey, boolean armor, boolean withIntegrityCheck) throws IOException, NoSuchProviderException { if (armor) { out = new ArmoredOutputStream(out); } try { byte[] bytes = PGPExampleUtil.compressFile(fileName, CompressionAlgorithmTags.ZIP); PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( new JcePGPDataEncryptorBuilder(PGPEncryptedData.CAST5).setWithIntegrityPacket(withIntegrityCheck).setSecureRandom(new SecureRandom()).setProvider("SC")); encGen.addMethod(new JcePublicKeyKeyEncryptionMethodGenerator(encKey).setProvider("SC")); OutputStream cOut = encGen.open(out, bytes.length); cOut.write(bytes); cOut.close(); if (armor) { out.close(); } } catch (PGPException e) { System.err.println(e); if (e.getUnderlyingException() != null) { e.getUnderlyingException().printStackTrace(); } } } public static void main( String[] args) throws Exception { Security.addProvider(new BouncyCastleProvider()); if (args.length == 0) { System.err.println("usage: KeyBasedFileProcessor -e|-d [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]"); return; } if (args[0].equals("-e")) { if (args[1].equals("-a") || args[1].equals("-ai") || args[1].equals("-ia")) { encryptFile(args[2] + ".asc", args[2], args[3], true, (args[1].indexOf('i') > 0)); } else if (args[1].equals("-i")) { encryptFile(args[2] + ".bpg", args[2], args[3], false, true); } else { encryptFile(args[1] + ".bpg", args[1], args[2], false, false); } } else if (args[0].equals("-d")) { decryptFile(args[1], args[2], args[3].toCharArray(), new File(args[1]).getName() + ".out"); } else { System.err.println("usage: KeyBasedFileProcessor -d|-e [-a|ai] file [secretKeyFile passPhrase|pubKeyFile]"); } } }