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