1 | /* |
---|
2 | Tibisay Movil |
---|
3 | |
---|
4 | Copyright (C) 2013 Antonio Araujo (aaraujo@cenditel.gob.ve), Jose Ruiz |
---|
5 | (jruiz@cenditel.gob.ve), Fundacion Centro Nacional de Desarrollo e |
---|
6 | Investigacion en Tecnologias Libres - CENDITEL. |
---|
7 | |
---|
8 | La Fundación CENDITEL concede permiso para usar, copiar, distribuir y/o |
---|
9 | modificar este programa, reconociendo el derecho que la humanidad posee al |
---|
10 | libre acceso al conocimiento, bajo los términos de la licencia de software |
---|
11 | GPL versión 2.0 de la Free Software Foundation. |
---|
12 | |
---|
13 | Este programa se distribuye con la esperanza de que sea util, pero SIN |
---|
14 | NINGUNA GARANTIA; tampoco las implicitas garantias de MERCANTILIDAD o |
---|
15 | ADECUACION A UN PROPOSITO PARTICULAR. |
---|
16 | |
---|
17 | Para mayor información sobre los términos de la licencia ver el archivo |
---|
18 | llamado "gpl-2.0.txt" en ingles. |
---|
19 | */ |
---|
20 | |
---|
21 | |
---|
22 | package ve.gob.cenditel.tibisaymovil; |
---|
23 | |
---|
24 | import java.io.BufferedInputStream; |
---|
25 | import java.io.ByteArrayOutputStream; |
---|
26 | import java.io.File; |
---|
27 | import java.io.FileInputStream; |
---|
28 | import java.io.IOException; |
---|
29 | import java.io.InputStream; |
---|
30 | import java.security.InvalidKeyException; |
---|
31 | import java.security.NoSuchAlgorithmException; |
---|
32 | import java.security.PrivateKey; |
---|
33 | import java.security.Signature; |
---|
34 | import java.security.SignatureException; |
---|
35 | import java.security.cert.CertificateEncodingException; |
---|
36 | import java.security.cert.X509Certificate; |
---|
37 | import java.util.ArrayList; |
---|
38 | |
---|
39 | import javax.ws.rs.core.MediaType; |
---|
40 | |
---|
41 | import org.codehaus.jettison.json.JSONException; |
---|
42 | import org.codehaus.jettison.json.JSONObject; |
---|
43 | import org.spongycastle.asn1.ASN1StreamParser; |
---|
44 | import org.spongycastle.asn1.DERSequenceGenerator; |
---|
45 | import org.spongycastle.cert.jcajce.JcaCertStore; |
---|
46 | import org.spongycastle.cms.CMSException; |
---|
47 | import org.spongycastle.cms.CMSProcessableFile; |
---|
48 | import org.spongycastle.cms.CMSSignedData; |
---|
49 | import org.spongycastle.cms.CMSSignedDataGenerator; |
---|
50 | import org.spongycastle.cms.CMSTypedData; |
---|
51 | import org.spongycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; |
---|
52 | import org.spongycastle.jce.provider.BouncyCastleProvider; |
---|
53 | import org.spongycastle.operator.ContentSigner; |
---|
54 | import org.spongycastle.operator.OperatorCreationException; |
---|
55 | import org.spongycastle.operator.jcajce.JcaContentSignerBuilder; |
---|
56 | import org.spongycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; |
---|
57 | import org.spongycastle.util.Store; |
---|
58 | import org.spongycastle.util.encoders.Base64Encoder; |
---|
59 | |
---|
60 | import android.app.Activity; |
---|
61 | import android.content.Context; |
---|
62 | import android.content.SharedPreferences; |
---|
63 | import android.preference.PreferenceManager; |
---|
64 | import android.widget.Toast; |
---|
65 | |
---|
66 | import com.sun.jersey.api.client.Client; |
---|
67 | import com.sun.jersey.api.client.ClientHandlerException; |
---|
68 | import com.sun.jersey.api.client.ClientRequest; |
---|
69 | import com.sun.jersey.api.client.ClientResponse; |
---|
70 | import com.sun.jersey.api.client.WebResource; |
---|
71 | import com.sun.jersey.api.client.filter.ClientFilter; |
---|
72 | import com.sun.jersey.multipart.FormDataMultiPart; |
---|
73 | import com.sun.jersey.multipart.file.DefaultMediaTypePredictor; |
---|
74 | import com.sun.jersey.multipart.file.DefaultMediaTypePredictor.CommonMediaTypes; |
---|
75 | import com.sun.jersey.spi.service.ServiceFinder; |
---|
76 | |
---|
77 | /** |
---|
78 | * Cryptograhic utilities. |
---|
79 | * |
---|
80 | * @author José M. Prieto (jmprieto@emergya.com) |
---|
81 | */ |
---|
82 | public class CryptoUtils { |
---|
83 | |
---|
84 | /** |
---|
85 | * Sign a file. Generates a PKCS#7 signature in DER encoding. |
---|
86 | * |
---|
87 | * @param file the File where the data to be signed is stored |
---|
88 | * @param certificate certificate of the signer. The certificate is included in the resulting signature |
---|
89 | * @param key private key used to sign |
---|
90 | * @return a PKCS#7 signature with the certificate attached encoded in DER format |
---|
91 | * |
---|
92 | * @throws CertificateEncodingException if there is an error related to the certificate |
---|
93 | * @throws CMSException if there is an error signing the data |
---|
94 | * @throws IOException if there is an error encoding the signature |
---|
95 | * @throws OperatorCreationException if there is an error in the cryptographic library |
---|
96 | */ |
---|
97 | public static byte[] signPKCS7(File file, X509Certificate certificate, PrivateKey key) |
---|
98 | throws CertificateEncodingException, CMSException, IOException, OperatorCreationException { |
---|
99 | |
---|
100 | // TODO reuse CertificateUtils provider |
---|
101 | BouncyCastleProvider provider = new BouncyCastleProvider(); |
---|
102 | ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>(); |
---|
103 | CMSTypedData msg = new CMSProcessableFile(file); |
---|
104 | |
---|
105 | certList.add(certificate); |
---|
106 | |
---|
107 | Store certs = new JcaCertStore(certList); |
---|
108 | |
---|
109 | CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); |
---|
110 | ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider(provider).build(key); |
---|
111 | |
---|
112 | gen.addSignerInfoGenerator( |
---|
113 | new JcaSignerInfoGeneratorBuilder( |
---|
114 | new JcaDigestCalculatorProviderBuilder().setProvider(provider).build()) |
---|
115 | .build(sha1Signer, certificate)); |
---|
116 | |
---|
117 | gen.addCertificates(certs); |
---|
118 | |
---|
119 | |
---|
120 | //TODO: Error in Android 4.2 |
---|
121 | CMSSignedData cmsData = gen.generate(msg, false); |
---|
122 | |
---|
123 | byte[] result = cmsData.getEncoded(); |
---|
124 | return result; |
---|
125 | } |
---|
126 | |
---|
127 | // public static InputStream signPDF(File file, X509Certificate[] chain, PrivateKey key, Context context) |
---|
128 | // throws IOException, CertificateEncodingException, JSONException, SignatureException, InvalidKeyException, NoSuchAlgorithmException, DocumentWritingException { |
---|
129 | // |
---|
130 | // ServiceFinder.setIteratorProvider(new AndroidServiceIteratorProvider()); |
---|
131 | // Client client = Client.create(); |
---|
132 | // client.setConnectTimeout(5000); |
---|
133 | // client.setReadTimeout(5000); |
---|
134 | // client.addFilter(new ClientFilter() { |
---|
135 | // private ArrayList<Object> cookies; |
---|
136 | // |
---|
137 | // @Override |
---|
138 | // public ClientResponse handle(ClientRequest request) throws ClientHandlerException { |
---|
139 | // if (cookies != null) { |
---|
140 | // request.getHeaders().put("Cookie", cookies); |
---|
141 | // } |
---|
142 | // ClientResponse response = getNext().handle(request); |
---|
143 | // if (response.getCookies() != null) { |
---|
144 | // if (cookies == null) { |
---|
145 | // cookies = new ArrayList<Object>(); |
---|
146 | // } |
---|
147 | // // simple addAll just for illustration (should probably check for duplicates and expired cookies) |
---|
148 | // cookies.addAll(response.getCookies()); |
---|
149 | // } |
---|
150 | // return response; |
---|
151 | // } |
---|
152 | // }); |
---|
153 | // |
---|
154 | // //TODO: SERVER URL |
---|
155 | // //EXTERNAL |
---|
156 | // //WebResource res = client.resource("http://venezuela-apps.emergya.es:51880/service/pdf"); |
---|
157 | // //INTERNAL |
---|
158 | // WebResource res = client.resource("http://venezuela-apps.emergya.es:8080/service/pdf"); |
---|
159 | // //LOCAL Android |
---|
160 | // //WebResource res = client.resource("http://10.0.2.2:8080/service/pdf"); |
---|
161 | // |
---|
162 | // ByteArrayOutputStream buf = new ByteArrayOutputStream(); |
---|
163 | // DERSequenceGenerator seq = new DERSequenceGenerator(buf); |
---|
164 | // for (X509Certificate cert : chain) { |
---|
165 | // seq.addObject(new ASN1StreamParser(cert.getEncoded()).readObject()); |
---|
166 | // } |
---|
167 | // seq.close(); |
---|
168 | // |
---|
169 | // FormDataMultiPart form = new FormDataMultiPart(); |
---|
170 | // FileInputStream inputStream = new FileInputStream(file); |
---|
171 | // form.field("pdf", inputStream, |
---|
172 | // DefaultMediaTypePredictor.CommonMediaTypes.getMediaTypeFromFile(file)); |
---|
173 | // form.field("chain", buf.toByteArray(), MediaType.APPLICATION_OCTET_STREAM_TYPE); |
---|
174 | // |
---|
175 | // |
---|
176 | // |
---|
177 | // //New code: Obtain configuration parameters. |
---|
178 | //// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); |
---|
179 | //// String position = prefs.getString(ConfigurationActivity.positionKey, "3"); |
---|
180 | //// form.field("position", position); |
---|
181 | //// |
---|
182 | //// |
---|
183 | //// String imagePath = prefs.getString(ConfigurationActivity.imageKey, ""); |
---|
184 | //// File imageFile; |
---|
185 | //// InputStream imageStream; |
---|
186 | //// MediaType mediaType; |
---|
187 | //// if (imagePath.equals("")){ |
---|
188 | //// |
---|
189 | //// imageStream = context.getAssets().open("icono_app.png"); |
---|
190 | //// mediaType = DefaultMediaTypePredictor.CommonMediaTypes.PNG.getMediaType(); |
---|
191 | //// |
---|
192 | //// }else{ |
---|
193 | //// imageFile = new File(imagePath); |
---|
194 | //// imageStream = new FileInputStream(imageFile); |
---|
195 | //// mediaType = DefaultMediaTypePredictor.CommonMediaTypes.getMediaTypeFromFile(imageFile); |
---|
196 | //// } |
---|
197 | //// form.field("image", imageStream, mediaType); |
---|
198 | //// //---- |
---|
199 | // |
---|
200 | // |
---|
201 | // JSONObject json = res.type(MediaType.MULTIPART_FORM_DATA_TYPE).accept(MediaType.APPLICATION_JSON_TYPE).post(JSONObject.class, form); |
---|
202 | // inputStream.close(); |
---|
203 | // |
---|
204 | // |
---|
205 | // //TODO: ERROR CHECKS |
---|
206 | // String ERROR_MESSAGE = "errorMessage"; |
---|
207 | // String ERROR_CODE = "errorCode"; |
---|
208 | // |
---|
209 | // try{ |
---|
210 | // int code = json.getInt(ERROR_CODE); |
---|
211 | // final String message = json.getString(ERROR_MESSAGE); |
---|
212 | // if (message!=null && !message.equals("")){ |
---|
213 | // final Activity act = ((Activity) context); |
---|
214 | // act.runOnUiThread(new Runnable() { |
---|
215 | // public void run() { |
---|
216 | // Toast.makeText(act, message, Toast.LENGTH_SHORT).show(); |
---|
217 | // } |
---|
218 | // }); |
---|
219 | // } |
---|
220 | // throw new DocumentWritingException(); |
---|
221 | // |
---|
222 | // }catch (JSONException e){} |
---|
223 | // |
---|
224 | // //---- |
---|
225 | // |
---|
226 | // |
---|
227 | // |
---|
228 | // byte[] hash = base64Decode(json.getString("hash")); |
---|
229 | // Signature signer = Signature.getInstance("SHA1withRSA"); |
---|
230 | // signer.initSign(key); |
---|
231 | // signer.update(hash); |
---|
232 | // byte[] signature = signer.sign(); |
---|
233 | // String signature64 = base64Encode(signature); |
---|
234 | // |
---|
235 | // return res.queryParam("s", signature64).accept("application/pdf").get(InputStream.class); |
---|
236 | // } |
---|
237 | |
---|
238 | private static String base64Encode(byte[] data) |
---|
239 | throws IOException { |
---|
240 | |
---|
241 | Base64Encoder encoder = new Base64Encoder(); |
---|
242 | ByteArrayOutputStream stream = new ByteArrayOutputStream(); |
---|
243 | encoder.encode(data, 0, data.length, stream); |
---|
244 | return stream.toString(); |
---|
245 | } |
---|
246 | |
---|
247 | private static byte[] base64Decode(String string) |
---|
248 | throws IOException { |
---|
249 | |
---|
250 | Base64Encoder encoder = new Base64Encoder(); |
---|
251 | ByteArrayOutputStream buf = new ByteArrayOutputStream(); |
---|
252 | encoder.decode(string, buf); |
---|
253 | return buf.toByteArray(); |
---|
254 | } |
---|
255 | } |
---|