85b5dfb3f88119b7beeaf5d7afe0e25cbd967712
[aaf/cadi.git] / aaf / src / main / java / com / att / cadi / cm / Factory.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package com.att.cadi.cm;\r
24 \r
25 import java.io.BufferedReader;\r
26 import java.io.ByteArrayInputStream;\r
27 import java.io.ByteArrayOutputStream;\r
28 import java.io.DataInputStream;\r
29 import java.io.File;\r
30 import java.io.FileInputStream;\r
31 import java.io.FileNotFoundException;\r
32 import java.io.FileReader;\r
33 import java.io.IOException;\r
34 import java.io.InputStream;\r
35 import java.io.InputStreamReader;\r
36 import java.io.Reader;\r
37 import java.io.StringReader;\r
38 import java.security.InvalidKeyException;\r
39 import java.security.Key;\r
40 import java.security.KeyFactory;\r
41 import java.security.KeyPair;\r
42 import java.security.KeyPairGenerator;\r
43 import java.security.NoSuchAlgorithmException;\r
44 import java.security.PrivateKey;\r
45 import java.security.PublicKey;\r
46 import java.security.SecureRandom;\r
47 import java.security.Signature;\r
48 import java.security.SignatureException;\r
49 import java.security.cert.Certificate;\r
50 import java.security.cert.CertificateEncodingException;\r
51 import java.security.cert.CertificateException;\r
52 import java.security.cert.CertificateFactory;\r
53 import java.security.cert.X509Certificate;\r
54 import java.security.spec.InvalidKeySpecException;\r
55 import java.security.spec.PKCS8EncodedKeySpec;\r
56 import java.security.spec.X509EncodedKeySpec;\r
57 import java.util.Collection;\r
58 import java.util.List;\r
59 \r
60 import javax.crypto.Cipher;\r
61 import javax.crypto.NoSuchPaddingException;\r
62 \r
63 import com.att.cadi.Symm;\r
64 import com.att.inno.env.Env;\r
65 import com.att.inno.env.TimeTaken;\r
66 import com.att.inno.env.Trans;\r
67 \r
68 public class Factory {\r
69         private static final String PRIVATE_KEY_HEADER = "PRIVATE KEY";\r
70         public static final String KEY_ALGO = "RSA";\r
71         public static final String SIG_ALGO = "SHA256withRSA";\r
72 \r
73         public  static final int KEY_LENGTH = 2048;\r
74         private static final KeyPairGenerator keygen;\r
75         private static final KeyFactory keyFactory;\r
76         private static final CertificateFactory certificateFactory;\r
77         private static final SecureRandom random;\r
78         \r
79         \r
80         private static final Symm base64 = Symm.base64.copy(64);\r
81 \r
82         static {\r
83                         random = new SecureRandom();\r
84                         KeyPairGenerator tempKeygen;\r
85                         try {\r
86                                 tempKeygen = KeyPairGenerator.getInstance(KEY_ALGO);//,"BC");\r
87                                 tempKeygen.initialize(KEY_LENGTH, random);\r
88                         } catch (NoSuchAlgorithmException e) {\r
89                                 tempKeygen = null;\r
90                                 e.printStackTrace(System.err);\r
91                         }\r
92                         keygen = tempKeygen;\r
93 \r
94                         KeyFactory tempKeyFactory;\r
95                         try {\r
96                                 tempKeyFactory=KeyFactory.getInstance(KEY_ALGO);//,"BC"\r
97                         } catch (NoSuchAlgorithmException e) {\r
98                                 tempKeyFactory = null;\r
99                                 e.printStackTrace(System.err);\r
100                         };\r
101                         keyFactory = tempKeyFactory;\r
102                          \r
103                         CertificateFactory tempCertificateFactory;\r
104                         try {\r
105                                 tempCertificateFactory = CertificateFactory.getInstance("X.509");\r
106                         } catch (CertificateException e) {\r
107                                 tempCertificateFactory = null;\r
108                                 e.printStackTrace(System.err);\r
109                         }\r
110                         certificateFactory = tempCertificateFactory;\r
111 \r
112                  \r
113         }\r
114 \r
115 \r
116         public static KeyPair generateKeyPair(Trans trans) {\r
117                 TimeTaken tt;\r
118                 if(trans!=null) {\r
119                         tt = trans.start("Generate KeyPair", Env.SUB);\r
120                 } else {\r
121                         tt = null;\r
122                 }\r
123                 try {\r
124                         return keygen.generateKeyPair();\r
125                 } finally {\r
126                         if(tt!=null) {\r
127                                 tt.done();\r
128                         }\r
129                 }\r
130         }  \r
131 \r
132         private static final String LINE_END = "-----\n";\r
133 \r
134         protected static String textBuilder(String kind, byte[] bytes) throws IOException {\r
135                 StringBuilder sb = new StringBuilder();\r
136                 sb.append("-----BEGIN ");\r
137                 sb.append(kind);\r
138                 sb.append(LINE_END);\r
139 \r
140                 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
141                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
142                 base64.encode(bais, baos);\r
143                 sb.append(new String(baos.toByteArray()));\r
144                 \r
145                 if(sb.charAt(sb.length()-1)!='\n') {\r
146                         sb.append('\n');\r
147                 }\r
148                 sb.append("-----END ");\r
149                 sb.append(kind);\r
150                 sb.append(LINE_END);\r
151                 return sb.toString();\r
152         }\r
153         \r
154         public static PrivateKey toPrivateKey(Trans trans, String pk) throws IOException, CertException {\r
155                 byte[] bytes = decode(new StringReader(pk));\r
156                 return toPrivateKey(trans, bytes);\r
157         }\r
158         \r
159         public static PrivateKey toPrivateKey(Trans trans, byte[] bytes) throws IOException, CertException {\r
160                 TimeTaken tt=trans.start("Reconstitute Private Key", Env.SUB);\r
161                 try {\r
162                         return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(bytes));\r
163                 } catch (InvalidKeySpecException e) {\r
164                         throw new CertException("Translating Private Key from PKCS8 KeySpec",e);\r
165                 } finally {\r
166                         tt.done();\r
167                 }\r
168         }\r
169         \r
170         public static PrivateKey toPrivateKey(Trans trans, File file) throws IOException, CertException {\r
171                 TimeTaken tt = trans.start("Decode Private Key File", Env.SUB);\r
172                 try {\r
173                         return toPrivateKey(trans,decode(file));\r
174                 }finally {\r
175                         tt.done();\r
176                 }\r
177         }\r
178 \r
179         public static String toString(Trans trans, PrivateKey pk) throws IOException {\r
180 //              PKCS8EncodedKeySpec pemContents = new PKCS8EncodedKeySpec(pk.getEncoded());\r
181                 trans.debug().log("Private Key to String");\r
182                 return textBuilder(PRIVATE_KEY_HEADER,pk.getEncoded());\r
183         }\r
184 \r
185         public static PublicKey toPublicKey(Trans trans, String pk) throws IOException {\r
186                 TimeTaken tt = trans.start("Reconstitute Public Key", Env.SUB);\r
187                 try {\r
188                         ByteArrayInputStream bais = new ByteArrayInputStream(pk.getBytes());\r
189                         ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
190                         Symm.base64noSplit.decode(bais, baos);\r
191 \r
192                         return keyFactory.generatePublic(new X509EncodedKeySpec(baos.toByteArray()));\r
193                 } catch (InvalidKeySpecException e) {\r
194                         trans.error().log(e,"Translating Public Key from X509 KeySpec");\r
195                         return null;\r
196                 } finally {\r
197                         tt.done();\r
198                 }\r
199         }\r
200         \r
201         public static String toString(Trans trans, PublicKey pk) throws IOException {\r
202                 trans.debug().log("Public Key to String");\r
203                 return textBuilder("PUBLIC KEY",pk.getEncoded());\r
204         }\r
205 \r
206         public static Collection<? extends Certificate> toX509Certificate(String x509) throws CertificateException {\r
207                 return toX509Certificate(x509.getBytes());\r
208         }\r
209         \r
210         public static Collection<? extends Certificate> toX509Certificate(List<String> x509s) throws CertificateException {\r
211                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
212                 try {\r
213                         for(String x509 : x509s) {\r
214                                 baos.write(x509.getBytes());\r
215                         }\r
216                 } catch (IOException e) {\r
217                         throw new CertificateException(e);\r
218                 }\r
219                 return toX509Certificate(new ByteArrayInputStream(baos.toByteArray()));\r
220         }\r
221 \r
222         public static Collection<? extends Certificate> toX509Certificate(byte[] x509) throws CertificateException {\r
223                 return certificateFactory.generateCertificates(new ByteArrayInputStream(x509));\r
224         }\r
225 \r
226         public static Collection<? extends Certificate> toX509Certificate(Trans trans, File file) throws CertificateException, FileNotFoundException {\r
227                 FileInputStream fis = new FileInputStream(file);\r
228                 try {\r
229                         return toX509Certificate(fis);\r
230                 } finally {\r
231                         try {\r
232                                 fis.close();\r
233                         } catch (IOException e) {\r
234                                 throw new CertificateException(e);\r
235                         }\r
236                 }\r
237         }\r
238 \r
239         public static Collection<? extends Certificate> toX509Certificate(InputStream is) throws CertificateException {\r
240                 return certificateFactory.generateCertificates(is);\r
241         }\r
242 \r
243         public static String toString(Trans trans, Certificate cert) throws IOException, CertException {\r
244                 if(trans.debug().isLoggable()) {\r
245                         StringBuilder sb = new StringBuilder("Certificate to String");\r
246                         if(cert instanceof X509Certificate) {\r
247                                 sb.append(" - ");\r
248                                 sb.append(((X509Certificate)cert).getSubjectDN());\r
249                         }\r
250                         trans.debug().log(sb);\r
251                 }\r
252                 try {\r
253                         if(cert==null) {\r
254                                 throw new CertException("Certificate not built");\r
255                         }\r
256                         return textBuilder("CERTIFICATE",cert.getEncoded());\r
257                 } catch (CertificateEncodingException e) {\r
258                         throw new CertException(e);\r
259                 }\r
260         }\r
261 \r
262         public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {\r
263                 return Cipher.getInstance(KEY_ALGO); \r
264         }\r
265 \r
266         public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {\r
267                 Cipher cipher = Cipher.getInstance(KEY_ALGO);\r
268                 cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);\r
269                 return cipher;\r
270         }\r
271 \r
272         public static byte[] strip(Reader rdr) throws IOException {\r
273                 BufferedReader br = new BufferedReader(rdr);\r
274                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
275                 String line;\r
276                 while((line=br.readLine())!=null) {\r
277                         if(line.length()>0 &&\r
278                            !line.startsWith("-----") &&\r
279                            line.indexOf(':')<0) {  // Header elements\r
280                                 baos.write(line.getBytes());\r
281                         }\r
282                 }\r
283                 return baos.toByteArray();\r
284         }\r
285         \r
286         public static class StripperInputStream extends InputStream {\r
287                 private Reader created;\r
288                 private BufferedReader br;\r
289                 private int idx;\r
290                 private String line;\r
291 \r
292                 public StripperInputStream(Reader rdr) {\r
293                         if(rdr instanceof BufferedReader) {\r
294                                 br = (BufferedReader)rdr;\r
295                         } else {\r
296                                 br = new BufferedReader(rdr);\r
297                         }\r
298                         created = null;\r
299                 }\r
300                 \r
301                 public StripperInputStream(File file) throws FileNotFoundException {\r
302                         this(new FileReader(file));\r
303                         created = br;\r
304                 }\r
305 \r
306                 public StripperInputStream(InputStream is) throws FileNotFoundException {\r
307                         this(new InputStreamReader(is));\r
308                         created = br;\r
309                 }\r
310 \r
311                 @Override\r
312                 public int read() throws IOException {\r
313                         if(line==null || idx>=line.length()) {\r
314                                 while((line=br.readLine())!=null) {\r
315                                         if(line.length()>0 &&\r
316                                            !line.startsWith("-----") &&\r
317                                            line.indexOf(':')<0) {  // Header elements\r
318                                                 break;\r
319                                         }\r
320                                 }\r
321 \r
322                                 if(line==null) {\r
323                                         return -1;\r
324                                 }\r
325                                 idx = 0;\r
326                         }\r
327                         return line.charAt(idx++);\r
328                 }\r
329 \r
330                 /* (non-Javadoc)\r
331                  * @see java.io.InputStream#close()\r
332                  */\r
333                 @Override\r
334                 public void close() throws IOException {\r
335                         if(created!=null) {\r
336                                 created.close();\r
337                         }\r
338                 }\r
339         }\r
340 \r
341         public static class Base64InputStream extends InputStream {\r
342                 private InputStream created;\r
343                 private InputStream is;\r
344                 private byte trio[];\r
345                 private byte duo[];\r
346                 private int idx;\r
347 \r
348                 \r
349                 public Base64InputStream(File file) throws FileNotFoundException {\r
350                         this(new FileInputStream(file));\r
351                         created = is;\r
352                 }\r
353 \r
354                 public Base64InputStream(InputStream is) throws FileNotFoundException {\r
355                         this.is = is;\r
356                         trio = new byte[3];\r
357                         idx = 4;\r
358                 }\r
359 \r
360                 @Override\r
361                 public int read() throws IOException {\r
362                         if(duo==null || idx>=duo.length) {\r
363                                 int read = is.read(trio);\r
364                                 if(read==-1) {\r
365                                         return -1;\r
366                                 }\r
367                                 duo = Symm.base64.decode(trio);\r
368                                 if(duo==null || duo.length==0) {\r
369                                         return -1;\r
370                                 }\r
371                                 idx=0;\r
372                         }\r
373                         \r
374                         return duo[idx++];\r
375                 }\r
376 \r
377                 /* (non-Javadoc)\r
378                  * @see java.io.InputStream#close()\r
379                  */\r
380                 @Override\r
381                 public void close() throws IOException {\r
382                         if(created!=null) {\r
383                                 created.close();\r
384                         }\r
385                 }\r
386         }\r
387 \r
388         public static byte[] decode(byte[] bytes) throws IOException {\r
389                 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
390                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
391                 Symm.base64.decode(bais, baos);\r
392                 return baos.toByteArray();\r
393         }\r
394         \r
395         public static byte[] decode(File f) throws IOException {\r
396                 FileReader fr = new FileReader(f);\r
397                 try {\r
398                         return Factory.decode(fr);\r
399                 } finally {\r
400                         fr.close();\r
401                 }\r
402 \r
403         }\r
404         public static byte[] decode(Reader rdr) throws IOException {\r
405                 return decode(strip(rdr));\r
406         }\r
407 \r
408 \r
409         public static byte[] binary(File file) throws IOException {\r
410                 DataInputStream dis = new DataInputStream(new FileInputStream(file));\r
411                 try {\r
412                         byte[] bytes = new byte[(int)file.length()];\r
413                         dis.readFully(bytes);\r
414                         return bytes;\r
415                 } finally {\r
416                         dis.close();\r
417                 }\r
418         }\r
419 \r
420 \r
421         public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {\r
422                 TimeTaken tt = trans.start("Sign Data", Env.SUB);\r
423                 try {\r
424                         Signature sig = Signature.getInstance(SIG_ALGO);\r
425                         sig.initSign(pk, random);\r
426                         sig.update(bytes);\r
427                         return sig.sign();\r
428                 } finally {\r
429                         tt.done();\r
430                 }\r
431         }\r
432 \r
433         public static String toSignatureString(byte[] signed) throws IOException {\r
434                 return textBuilder("SIGNATURE", signed);\r
435         }\r
436 \r
437         public static boolean verify(Trans trans, byte[] bytes, byte[] signature, PublicKey pk) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {\r
438                 TimeTaken tt = trans.start("Verify Data", Env.SUB);\r
439                 try {\r
440                         Signature sig = Signature.getInstance(SIG_ALGO);\r
441                         sig.initVerify(pk);\r
442                         sig.update(bytes);\r
443                         return sig.verify(signature);\r
444                 } finally {\r
445                         tt.done();\r
446                 }       \r
447         }\r
448 }\r