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