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