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