Update AAF Version 1.0.0
[aaf/cadi.git] / aaf / src / main / java / org / onap / aaf / 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 org.onap.aaf.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 org.onap.aaf.cadi.Symm;\r
64 \r
65 import org.onap.aaf.inno.env.Env;\r
66 import org.onap.aaf.inno.env.TimeTaken;\r
67 import org.onap.aaf.inno.env.Trans;\r
68 \r
69 public class Factory {\r
70         private static final String PRIVATE_KEY_HEADER = "PRIVATE KEY";\r
71         public static final String KEY_ALGO = "RSA";\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         public static String toString(Trans trans, PrivateKey pk) throws IOException {\r
181 //              PKCS8EncodedKeySpec pemContents = new PKCS8EncodedKeySpec(pk.getEncoded());\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(String x509) throws CertificateException {\r
208                 return toX509Certificate(x509.getBytes());\r
209         }\r
210         \r
211         public static Collection<? extends Certificate> toX509Certificate(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(new ByteArrayInputStream(baos.toByteArray()));\r
221         }\r
222 \r
223         public static Collection<? extends Certificate> toX509Certificate(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(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(InputStream is) throws CertificateException {\r
241                 return certificateFactory.generateCertificates(is);\r
242         }\r
243 \r
244         public static String toString(Trans trans, Certificate cert) throws IOException, CertException {\r
245                 if(trans.debug().isLoggable()) {\r
246                         StringBuilder sb = new StringBuilder("Certificate to String");\r
247                         if(cert instanceof X509Certificate) {\r
248                                 sb.append(" - ");\r
249                                 sb.append(((X509Certificate)cert).getSubjectDN());\r
250                         }\r
251                         trans.debug().log(sb);\r
252                 }\r
253                 try {\r
254                         if(cert==null) {\r
255                                 throw new CertException("Certificate not built");\r
256                         }\r
257                         return textBuilder("CERTIFICATE",cert.getEncoded());\r
258                 } catch (CertificateEncodingException e) {\r
259                         throw new CertException(e);\r
260                 }\r
261         }\r
262 \r
263         public static Cipher pkCipher() throws NoSuchAlgorithmException, NoSuchPaddingException {\r
264                 return Cipher.getInstance(KEY_ALGO); \r
265         }\r
266 \r
267         public static Cipher pkCipher(Key key, boolean encrypt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException {\r
268                 Cipher cipher = Cipher.getInstance(KEY_ALGO);\r
269                 cipher.init(encrypt?Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE,key);\r
270                 return cipher;\r
271         }\r
272 \r
273         public static byte[] strip(Reader rdr) throws IOException {\r
274                 BufferedReader br = new BufferedReader(rdr);\r
275                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
276                 String line;\r
277                 while((line=br.readLine())!=null) {\r
278                         if(line.length()>0 &&\r
279                            !line.startsWith("-----") &&\r
280                            line.indexOf(':')<0) {  // Header elements\r
281                                 baos.write(line.getBytes());\r
282                         }\r
283                 }\r
284                 return baos.toByteArray();\r
285         }\r
286         \r
287         public static class StripperInputStream extends InputStream {\r
288                 private Reader created;\r
289                 private BufferedReader br;\r
290                 private int idx;\r
291                 private String line;\r
292 \r
293                 public StripperInputStream(Reader rdr) {\r
294                         if(rdr instanceof BufferedReader) {\r
295                                 br = (BufferedReader)rdr;\r
296                         } else {\r
297                                 br = new BufferedReader(rdr);\r
298                         }\r
299                         created = null;\r
300                 }\r
301                 \r
302                 public StripperInputStream(File file) throws FileNotFoundException {\r
303                         this(new FileReader(file));\r
304                         created = br;\r
305                 }\r
306 \r
307                 public StripperInputStream(InputStream is) throws FileNotFoundException {\r
308                         this(new InputStreamReader(is));\r
309                         created = br;\r
310                 }\r
311 \r
312                 @Override\r
313                 public int read() throws IOException {\r
314                         if(line==null || idx>=line.length()) {\r
315                                 while((line=br.readLine())!=null) {\r
316                                         if(line.length()>0 &&\r
317                                            !line.startsWith("-----") &&\r
318                                            line.indexOf(':')<0) {  // Header elements\r
319                                                 break;\r
320                                         }\r
321                                 }\r
322 \r
323                                 if(line==null) {\r
324                                         return -1;\r
325                                 }\r
326                                 idx = 0;\r
327                         }\r
328                         return line.charAt(idx++);\r
329                 }\r
330 \r
331                 /* (non-Javadoc)\r
332                  * @see java.io.InputStream#close()\r
333                  */\r
334                 @Override\r
335                 public void close() throws IOException {\r
336                         if(created!=null) {\r
337                                 created.close();\r
338                         }\r
339                 }\r
340         }\r
341 \r
342         public static class Base64InputStream extends InputStream {\r
343                 private InputStream created;\r
344                 private InputStream is;\r
345                 private byte trio[];\r
346                 private byte duo[];\r
347                 private int idx;\r
348 \r
349                 \r
350                 public Base64InputStream(File file) throws FileNotFoundException {\r
351                         this(new FileInputStream(file));\r
352                         created = is;\r
353                 }\r
354 \r
355                 public Base64InputStream(InputStream is) throws FileNotFoundException {\r
356                         this.is = is;\r
357                         trio = new byte[3];\r
358                         idx = 4;\r
359                 }\r
360 \r
361                 @Override\r
362                 public int read() throws IOException {\r
363                         if(duo==null || idx>=duo.length) {\r
364                                 int read = is.read(trio);\r
365                                 if(read==-1) {\r
366                                         return -1;\r
367                                 }\r
368                                 duo = Symm.base64.decode(trio);\r
369                                 if(duo==null || duo.length==0) {\r
370                                         return -1;\r
371                                 }\r
372                                 idx=0;\r
373                         }\r
374                         \r
375                         return duo[idx++];\r
376                 }\r
377 \r
378                 /* (non-Javadoc)\r
379                  * @see java.io.InputStream#close()\r
380                  */\r
381                 @Override\r
382                 public void close() throws IOException {\r
383                         if(created!=null) {\r
384                                 created.close();\r
385                         }\r
386                 }\r
387         }\r
388 \r
389         public static byte[] decode(byte[] bytes) throws IOException {\r
390                 ByteArrayInputStream bais = new ByteArrayInputStream(bytes);\r
391                 ByteArrayOutputStream baos = new ByteArrayOutputStream();\r
392                 Symm.base64.decode(bais, baos);\r
393                 return baos.toByteArray();\r
394         }\r
395         \r
396         public static byte[] decode(File f) throws IOException {\r
397                 FileReader fr = new FileReader(f);\r
398                 try {\r
399                         return Factory.decode(fr);\r
400                 } finally {\r
401                         fr.close();\r
402                 }\r
403 \r
404         }\r
405         public static byte[] decode(Reader rdr) throws IOException {\r
406                 return decode(strip(rdr));\r
407         }\r
408 \r
409 \r
410         public static byte[] binary(File file) throws IOException {\r
411                 DataInputStream dis = new DataInputStream(new FileInputStream(file));\r
412                 try {\r
413                         byte[] bytes = new byte[(int)file.length()];\r
414                         dis.readFully(bytes);\r
415                         return bytes;\r
416                 } finally {\r
417                         dis.close();\r
418                 }\r
419         }\r
420 \r
421 \r
422         public static byte[] sign(Trans trans, byte[] bytes, PrivateKey pk) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {\r
423                 TimeTaken tt = trans.start("Sign Data", Env.SUB);\r
424                 try {\r
425                         Signature sig = Signature.getInstance(SIG_ALGO);\r
426                         sig.initSign(pk, random);\r
427                         sig.update(bytes);\r
428                         return sig.sign();\r
429                 } finally {\r
430                         tt.done();\r
431                 }\r
432         }\r
433 \r
434         public static String toSignatureString(byte[] signed) throws IOException {\r
435                 return textBuilder("SIGNATURE", signed);\r
436         }\r
437 \r
438         public static boolean verify(Trans trans, byte[] bytes, byte[] signature, PublicKey pk) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {\r
439                 TimeTaken tt = trans.start("Verify Data", Env.SUB);\r
440                 try {\r
441                         Signature sig = Signature.getInstance(SIG_ALGO);\r
442                         sig.initVerify(pk);\r
443                         sig.update(bytes);\r
444                         return sig.verify(signature);\r
445                 } finally {\r
446                         tt.done();\r
447                 }       \r
448         }\r
449 }\r