aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java')
-rw-r--r--libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java390
1 files changed, 390 insertions, 0 deletions
diff --git a/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
new file mode 100644
index 000000000..4082e2a66
--- /dev/null
+++ b/libraries/spongycastle/pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
@@ -0,0 +1,390 @@
+package org.spongycastle.openpgp.examples;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.SignatureException;
+import java.util.Iterator;
+
+import org.spongycastle.bcpg.ArmoredInputStream;
+import org.spongycastle.bcpg.ArmoredOutputStream;
+import org.spongycastle.bcpg.BCPGOutputStream;
+import org.spongycastle.jce.provider.BouncyCastleProvider;
+import org.spongycastle.openpgp.PGPException;
+import org.spongycastle.openpgp.PGPObjectFactory;
+import org.spongycastle.openpgp.PGPPrivateKey;
+import org.spongycastle.openpgp.PGPPublicKey;
+import org.spongycastle.openpgp.PGPPublicKeyRingCollection;
+import org.spongycastle.openpgp.PGPSecretKey;
+import org.spongycastle.openpgp.PGPSignature;
+import org.spongycastle.openpgp.PGPSignatureGenerator;
+import org.spongycastle.openpgp.PGPSignatureList;
+import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
+import org.spongycastle.openpgp.PGPUtil;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
+import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
+import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
+
+/**
+ * A simple utility class that creates clear signed files and verifies them.
+ * <p>
+ * To sign a file: ClearSignedFileProcessor -s fileName secretKey passPhrase.<br>
+ * <p>
+ * To decrypt: ClearSignedFileProcessor -v fileName signatureFile publicKeyFile.
+ */
+public class ClearSignedFileProcessor
+{
+ private static int readInputLine(ByteArrayOutputStream bOut, InputStream fIn)
+ throws IOException
+ {
+ bOut.reset();
+
+ int lookAhead = -1;
+ int ch;
+
+ while ((ch = fIn.read()) >= 0)
+ {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n')
+ {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+
+ return lookAhead;
+ }
+
+ private static int readInputLine(ByteArrayOutputStream bOut, int lookAhead, InputStream fIn)
+ throws IOException
+ {
+ bOut.reset();
+
+ int ch = lookAhead;
+
+ do
+ {
+ bOut.write(ch);
+ if (ch == '\r' || ch == '\n')
+ {
+ lookAhead = readPassedEOL(bOut, ch, fIn);
+ break;
+ }
+ }
+ while ((ch = fIn.read()) >= 0);
+
+ if (ch < 0)
+ {
+ lookAhead = -1;
+ }
+
+ return lookAhead;
+ }
+
+ private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn)
+ throws IOException
+ {
+ int lookAhead = fIn.read();
+
+ if (lastCh == '\r' && lookAhead == '\n')
+ {
+ bOut.write(lookAhead);
+ lookAhead = fIn.read();
+ }
+
+ return lookAhead;
+ }
+
+ /*
+ * verify a clear text signed file
+ */
+ private static void verifyFile(
+ InputStream in,
+ InputStream keyIn,
+ String resultName)
+ throws Exception
+ {
+ ArmoredInputStream aIn = new ArmoredInputStream(in);
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(resultName));
+
+
+
+ //
+ // write out signed section using the local line separator.
+ // note: trailing white space needs to be removed from the end of
+ // each line RFC 4880 Section 7.1
+ //
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, aIn);
+ byte[] lineSep = getLineSeparator();
+
+ if (lookAhead != -1 && aIn.isClearText())
+ {
+ byte[] line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line));
+ out.write(lineSep);
+
+ while (lookAhead != -1 && aIn.isClearText())
+ {
+ lookAhead = readInputLine(lineOut, lookAhead, aIn);
+
+ line = lineOut.toByteArray();
+ out.write(line, 0, getLengthWithoutSeparatorOrTrailingWhitespace(line));
+ out.write(lineSep);
+ }
+ }
+
+ out.close();
+
+ PGPPublicKeyRingCollection pgpRings = new PGPPublicKeyRingCollection(keyIn);
+
+ PGPObjectFactory pgpFact = new PGPObjectFactory(aIn);
+ PGPSignatureList p3 = (PGPSignatureList)pgpFact.nextObject();
+ PGPSignature sig = p3.get(0);
+
+ PGPPublicKey publicKey = pgpRings.getPublicKey(sig.getKeyID());
+ sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("SC"), publicKey);
+
+ //
+ // read the input, making sure we ignore the last newline.
+ //
+
+ InputStream sigIn = new BufferedInputStream(new FileInputStream(resultName));
+
+ lookAhead = readInputLine(lineOut, sigIn);
+
+ processLine(sig, lineOut.toByteArray());
+
+ if (lookAhead != -1)
+ {
+ do
+ {
+ lookAhead = readInputLine(lineOut, lookAhead, sigIn);
+
+ sig.update((byte)'\r');
+ sig.update((byte)'\n');
+
+ processLine(sig, lineOut.toByteArray());
+ }
+ while (lookAhead != -1);
+ }
+
+ sigIn.close();
+
+ if (sig.verify())
+ {
+ System.out.println("signature verified.");
+ }
+ else
+ {
+ System.out.println("signature verification failed.");
+ }
+ }
+
+ private static byte[] getLineSeparator()
+ {
+ String nl = System.getProperty("line.separator");
+ byte[] nlBytes = new byte[nl.length()];
+
+ for (int i = 0; i != nlBytes.length; i++)
+ {
+ nlBytes[i] = (byte)nl.charAt(i);
+ }
+
+ return nlBytes;
+ }
+
+ /*
+ * create a clear text signed file.
+ */
+ private static void signFile(
+ String fileName,
+ InputStream keyIn,
+ OutputStream out,
+ char[] pass,
+ String digestName)
+ throws IOException, NoSuchAlgorithmException, NoSuchProviderException, PGPException, SignatureException
+ {
+ int digest;
+
+ if (digestName.equals("SHA256"))
+ {
+ digest = PGPUtil.SHA256;
+ }
+ else if (digestName.equals("SHA384"))
+ {
+ digest = PGPUtil.SHA384;
+ }
+ else if (digestName.equals("SHA512"))
+ {
+ digest = PGPUtil.SHA512;
+ }
+ else if (digestName.equals("MD5"))
+ {
+ digest = PGPUtil.MD5;
+ }
+ else if (digestName.equals("RIPEMD160"))
+ {
+ digest = PGPUtil.RIPEMD160;
+ }
+ else
+ {
+ digest = PGPUtil.SHA1;
+ }
+
+ PGPSecretKey pgpSecKey = PGPExampleUtil.readSecretKey(keyIn);
+ PGPPrivateKey pgpPrivKey = pgpSecKey.extractPrivateKey(new JcePBESecretKeyDecryptorBuilder().setProvider("SC").build(pass));
+ PGPSignatureGenerator sGen = new PGPSignatureGenerator(new JcaPGPContentSignerBuilder(pgpSecKey.getPublicKey().getAlgorithm(), digest).setProvider("SC"));
+ PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
+
+ sGen.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, pgpPrivKey);
+
+ Iterator it = pgpSecKey.getPublicKey().getUserIDs();
+ if (it.hasNext())
+ {
+ spGen.setSignerUserID(false, (String)it.next());
+ sGen.setHashedSubpackets(spGen.generate());
+ }
+
+ InputStream fIn = new BufferedInputStream(new FileInputStream(fileName));
+ ArmoredOutputStream aOut = new ArmoredOutputStream(out);
+
+ aOut.beginClearText(digest);
+
+ //
+ // note the last \n/\r/\r\n in the file is ignored
+ //
+ ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
+ int lookAhead = readInputLine(lineOut, fIn);
+
+ processLine(aOut, sGen, lineOut.toByteArray());
+
+ if (lookAhead != -1)
+ {
+ do
+ {
+ lookAhead = readInputLine(lineOut, lookAhead, fIn);
+
+ sGen.update((byte)'\r');
+ sGen.update((byte)'\n');
+
+ processLine(aOut, sGen, lineOut.toByteArray());
+ }
+ while (lookAhead != -1);
+ }
+
+ fIn.close();
+
+ aOut.endClearText();
+
+ BCPGOutputStream bOut = new BCPGOutputStream(aOut);
+
+ sGen.generate().encode(bOut);
+
+ aOut.close();
+ }
+
+ private static void processLine(PGPSignature sig, byte[] line)
+ throws SignatureException, IOException
+ {
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0)
+ {
+ sig.update(line, 0, length);
+ }
+ }
+
+ private static void processLine(OutputStream aOut, PGPSignatureGenerator sGen, byte[] line)
+ throws SignatureException, IOException
+ {
+ // note: trailing white space needs to be removed from the end of
+ // each line for signature calculation RFC 4880 Section 7.1
+ int length = getLengthWithoutWhiteSpace(line);
+ if (length > 0)
+ {
+ sGen.update(line, 0, length);
+ }
+
+ aOut.write(line, 0, line.length);
+ }
+
+ private static int getLengthWithoutSeparatorOrTrailingWhitespace(byte[] line)
+ {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end]))
+ {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isLineEnding(byte b)
+ {
+ return b == '\r' || b == '\n';
+ }
+
+ private static int getLengthWithoutWhiteSpace(byte[] line)
+ {
+ int end = line.length - 1;
+
+ while (end >= 0 && isWhiteSpace(line[end]))
+ {
+ end--;
+ }
+
+ return end + 1;
+ }
+
+ private static boolean isWhiteSpace(byte b)
+ {
+ return isLineEnding(b) || b == '\t' || b == ' ';
+ }
+
+ public static void main(
+ String[] args)
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ if (args[0].equals("-s"))
+ {
+ InputStream keyIn = PGPUtil.getDecoderStream(new FileInputStream(args[2]));
+ FileOutputStream out = new FileOutputStream(args[1] + ".asc");
+
+ if (args.length == 4)
+ {
+ signFile(args[1], keyIn, out, args[3].toCharArray(), "SHA1");
+ }
+ else
+ {
+ signFile(args[1], keyIn, out, args[3].toCharArray(), args[4]);
+ }
+ }
+ else if (args[0].equals("-v"))
+ {
+ if (args[1].indexOf(".asc") < 0)
+ {
+ System.err.println("file needs to end in \".asc\"");
+ System.exit(1);
+ }
+ FileInputStream in = new FileInputStream(args[1]);
+ InputStream keyIn = PGPUtil.getDecoderStream(new FileInputStream(args[2]));
+
+ verifyFile(in, keyIn, args[1].substring(0, args[1].length() - 4));
+ }
+ else
+ {
+ System.err.println("usage: ClearSignedFileProcessor [-s file keyfile passPhrase]|[-v sigFile keyFile]");
+ }
+ }
+}