1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.pgp;
12
13 import java.io.BufferedInputStream;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.OutputStream;
17 import java.security.NoSuchProviderException;
18 import java.util.Iterator;
19
20 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicLong;
21
22 import org.bouncycastle.openpgp.PGPCompressedData;
23 import org.bouncycastle.openpgp.PGPEncryptedDataList;
24 import org.bouncycastle.openpgp.PGPException;
25 import org.bouncycastle.openpgp.PGPLiteralData;
26 import org.bouncycastle.openpgp.PGPObjectFactory;
27 import org.bouncycastle.openpgp.PGPOnePassSignature;
28 import org.bouncycastle.openpgp.PGPOnePassSignatureList;
29 import org.bouncycastle.openpgp.PGPPrivateKey;
30 import org.bouncycastle.openpgp.PGPPublicKey;
31 import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData;
32 import org.bouncycastle.openpgp.PGPSecretKey;
33 import org.bouncycastle.openpgp.PGPUtil;
34
35 public class DecryptOutputStreamWriter implements OutputStreamWriter
36 {
37 private static final long offset = 1 << 24;
38
39 private InputStream toBeDecrypted;
40 private PGPPublicKey publicKey;
41 private PGPSecretKey secretKey;
42 private String password;
43
44 private InputStream uncStream;
45 private InputStream compressedStream;
46 private InputStream clearStream;
47 private long bytesWrote;
48
49 public DecryptOutputStreamWriter(InputStream toBeDecrypted,
50 PGPPublicKey publicKey,
51 PGPSecretKey secretKey,
52 String password) throws IOException
53 {
54 this.toBeDecrypted = toBeDecrypted;
55 this.publicKey = publicKey;
56 this.secretKey = secretKey;
57 this.password = password;
58 this.bytesWrote = 0;
59 }
60
61
62
63
64 public void initialize(OutputStream out) throws Exception
65 {
66 InputStream decodedInputStream = PGPUtil.getDecoderStream(this.toBeDecrypted);
67 PGPObjectFactory pgpF = new PGPObjectFactory(decodedInputStream);
68 Object o = pgpF.nextObject();
69
70 if (o == null)
71 {
72 throw new IllegalArgumentException("Invalid PGP message");
73 }
74
75
76 PGPEncryptedDataList enc;
77 if (o instanceof PGPEncryptedDataList)
78 {
79 enc = (PGPEncryptedDataList) o;
80
81 }
82 else
83 {
84 enc = (PGPEncryptedDataList) pgpF.nextObject();
85 }
86
87
88
89 Iterator it = enc.getEncryptedDataObjects();
90 PGPPublicKeyEncryptedData pbe = null;
91 PGPPrivateKey privateKey = null;
92 while (privateKey == null && it.hasNext())
93 {
94 pbe = (PGPPublicKeyEncryptedData) it.next();
95 privateKey = getPrivateKey(pbe.getKeyID(), this.password);
96 if (privateKey == null)
97 {
98 throw new IllegalArgumentException("Failed to find private key with ID " + pbe.getKeyID());
99 }
100 }
101
102 clearStream = pbe.getDataStream(privateKey, "BC");
103 PGPObjectFactory plainFact = new PGPObjectFactory(clearStream);
104
105 o = plainFact.nextObject();
106 PGPOnePassSignature signature = null;
107 if (o instanceof PGPOnePassSignatureList)
108 {
109 PGPOnePassSignatureList list = (PGPOnePassSignatureList) o;
110 signature = list.get(0);
111 signature.initVerify(this.publicKey, "BC");
112
113
114 o = plainFact.nextObject();
115 }
116
117 compressedStream = null;
118 if (o instanceof PGPCompressedData)
119 {
120 PGPCompressedData cData = (PGPCompressedData) o;
121 compressedStream = new BufferedInputStream(cData.getDataStream());
122 PGPObjectFactory pgpFact = new PGPObjectFactory(compressedStream);
123 Object streamData = pgpFact.nextObject();
124 o = streamData;
125 }
126
127 if (o instanceof PGPLiteralData)
128 {
129 PGPLiteralData ld = (PGPLiteralData) o;
130 uncStream = ld.getInputStream();
131 }
132 else
133 {
134 throw new PGPException("input is not PGPLiteralData - type unknown.");
135 }
136 }
137
138
139
140
141 public boolean write(OutputStream out, AtomicLong bytesRequested) throws Exception
142 {
143 int len = 0;
144 byte[] buf = new byte[1 << 16];
145 boolean wroteSomething = false;
146
147 while (bytesRequested.get() + offset > bytesWrote && (len = uncStream.read(buf)) > 0)
148 {
149 out.write(buf, 0, len);
150 bytesWrote = bytesWrote + len;
151 wroteSomething = true;
152 }
153
154 if (wroteSomething && len <= 0)
155 {
156 uncStream.close();
157 if (compressedStream != null)
158 {
159 compressedStream.close();
160 }
161 clearStream.close();
162 return true;
163 }
164
165 return false;
166 }
167
168 private PGPPrivateKey getPrivateKey(long keyID, String pass) throws PGPException, NoSuchProviderException
169 {
170 PGPSecretKey pgpSecKey = this.secretKey;
171 if (pgpSecKey == null)
172 {
173 return null;
174 }
175 else
176 {
177 return pgpSecKey.extractPrivateKey(pass.toCharArray(), "BC");
178 }
179 }
180 }