CSIT Fix for SDC-2585
[sdc.git] / security-utils / src / main / java / org / openecomp / sdc / security / SecurityUtil.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 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 package org.openecomp.sdc.security;
22
23 import fj.data.Either;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 import javax.crypto.BadPaddingException;
28 import javax.crypto.Cipher;
29 import javax.crypto.IllegalBlockSizeException;
30 import javax.crypto.NoSuchPaddingException;
31 import javax.crypto.spec.SecretKeySpec;
32 import java.io.UnsupportedEncodingException;
33 import java.nio.charset.StandardCharsets;
34 import java.security.InvalidKeyException;
35 import java.security.Key;
36 import java.security.NoSuchAlgorithmException;
37 import java.util.Base64;
38 import java.util.Formatter;
39
40 public class SecurityUtil {
41
42     private static final Logger LOG = LoggerFactory.getLogger( SecurityUtil.class );
43     private static final byte[] KEY = new byte[]{-64,5,-32 ,-117 ,-44,8,-39, 1, -9, 36,-46,-81, 62,-15,-63,-75};
44     public static final SecurityUtil INSTANCE = new SecurityUtil();
45     public static final String ALGORITHM = "AES" ;
46     public static final String CHARSET = StandardCharsets.UTF_8.name();
47
48     private static Key secKey = null ;
49
50     private SecurityUtil(){ super(); }
51
52     /**
53      *
54      * cmd commands >$PROGRAM_NAME decrypt "$ENCRYPTED_MSG"
55      *              >$PROGRAM_NAME encrypt "message"
56     **/
57     public static void main(String[] args) throws Exception {
58         if ( args!=null && args.length>1){
59             fj.data.Either res = null;
60             final String op = args[0].trim().toLowerCase();
61             try{
62                 switch(op) {
63                     case "decrypt":
64                         res = INSTANCE.decrypt(Base64.getDecoder().decode(args[1]), true);
65                         break;
66                     case "encrypt":
67                         res = INSTANCE.encrypt(args[1]);
68                         break;
69                     default:
70                         LOG.warn("Unfamiliar command please use: \n>aes <encrypt/decrypt> 'message to encrypt/decrypt' ");
71                 }
72             }catch(Exception e){
73                 LOG.warn("Exception while message encryption or decryption");
74                 throw e;
75             }
76             LOG.debug( "output: {}", res!=null && res.isLeft() ? res.left().value() : "ERROR" );
77         }
78     }
79
80
81     static {
82         Formatter formatter = new Formatter();
83         try{
84             secKey = generateKey( KEY, ALGORITHM );
85         }
86         catch(Exception e){
87             if(LOG.isWarnEnabled())
88             {
89                 LOG.warn(formatter.format("cannot generate key for %s", ALGORITHM).toString(), e);
90             }
91         }finally {
92             formatter.close();
93         }
94     }
95
96
97
98     public static Key generateKey(final byte[] key, String algorithm){
99         return new SecretKeySpec(key, algorithm);
100     }
101
102     //obfuscates key prefix -> **********
103     public String obfuscateKey(String sensitiveData){
104
105         if (sensitiveData != null){
106             int len = sensitiveData.length();
107             StringBuilder builder = new StringBuilder(sensitiveData);
108             for (int i=0; i<len/2; i++){
109                 builder.setCharAt(i, '*');
110             }
111             return builder.toString();
112         }
113         return sensitiveData;
114     }
115
116     /**
117      *  @param strDataToEncrypt - plain string to encrypt
118      *  Encrypt the Data
119      *          a. Declare / Initialize the Data. Here the data is of type String
120      *          b. Convert the Input Text to Bytes
121      *          c. Encrypt the bytes using doFinal method
122      */
123     public Either<String,String> encrypt(String strDataToEncrypt){
124
125         if (strDataToEncrypt != null ){
126             Formatter formatter = new Formatter();
127             try{
128                 LOG.debug("Encrypt key -> {}", secKey);
129                 Cipher aesCipherForEncryption = Cipher.getInstance("AES");          // Must specify the mode explicitly as most JCE providers default to ECB mode!!
130                 aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secKey);
131                 byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();
132                 byte[] byteCipherText = aesCipherForEncryption.doFinal(byteDataToEncrypt);
133                 String strCipherText = new String( java.util.Base64.getMimeEncoder().encode(byteCipherText), CHARSET );
134                 LOG.debug("Cipher Text generated using AES is {}", strCipherText);
135                 return Either.left(strCipherText);
136             } catch( NoSuchAlgorithmException | UnsupportedEncodingException e){
137                 if(LOG.isWarnEnabled())
138                 {
139                    LOG.warn(formatter.format("cannot encrypt data unknown algorithm or missing encoding for %s",secKey.getAlgorithm()).toString(), e);
140                 }
141             } catch( InvalidKeyException e){
142                 if(LOG.isWarnEnabled())
143                 {
144                    LOG.warn(formatter.format("invalid key recieved - > %s", java.util.Base64.getDecoder().decode(secKey.getEncoded())).toString(), e);
145                 }
146             } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException  e){
147                 if(LOG.isWarnEnabled())
148                 {
149                    LOG.warn("bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding", e);
150                 }
151             }
152             finally {
153                 formatter.close();
154             }
155         }
156         return Either.right("Cannot encrypt "+strDataToEncrypt);
157     }
158
159     /**
160      * Decrypt the Data
161      * @param byteCipherText - should be valid bae64 input in the length of 16bytes
162      * @param isBase64Decoded - is data already base64 encoded&aligned to 16 bytes
163      *          a. Initialize a new instance of Cipher for Decryption (normally don't reuse the same object)
164      *          b. Decrypt the cipher bytes using doFinal method
165      */
166     public Either<String,String> decrypt(byte[] byteCipherText , boolean isBase64Decoded){
167         if (byteCipherText != null){
168             byte[] alignedCipherText = byteCipherText;
169             Formatter formatter = new Formatter();
170             try{
171                 if (isBase64Decoded)
172                     alignedCipherText = Base64.getDecoder().decode(byteCipherText);
173                 LOG.debug("Decrypt key -> {}", secKey.getEncoded());
174                 Cipher aesCipherForDecryption = Cipher.getInstance("AES"); // Must specify the mode explicitly as most JCE providers default to ECB mode!!
175                 aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secKey);
176                 byte[] byteDecryptedText = aesCipherForDecryption.doFinal(alignedCipherText);
177                 String strDecryptedText = new String(byteDecryptedText);
178                 String obfuscateKey = obfuscateKey( strDecryptedText );
179                 LOG.debug("Decrypted Text message is: {}" , obfuscateKey);
180                 return Either.left(strDecryptedText);
181             } catch( NoSuchAlgorithmException e){
182                 if(LOG.isWarnEnabled())
183                 {
184                     LOG.warn(formatter.format("cannot encrypt data unknown algorithm or missing encoding for %s", secKey.getAlgorithm()).toString(), e);
185                 }
186             } catch( InvalidKeyException e){
187                 if(LOG.isWarnEnabled())
188                 {
189                     LOG.warn(formatter.format("invalid key recieved - > %s", java.util.Base64.getDecoder().decode(secKey.getEncoded())).toString(), e);
190                 }
191             } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException  e){
192                 if(LOG.isWarnEnabled())
193                 {
194                     LOG.warn( "bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding", e);
195                 }
196             }finally {
197                 formatter.close();
198             }
199         }
200         return Either.right("Decrypt FAILED");
201     }
202
203     public Either<String,String> decrypt(String byteCipherText){
204         Formatter formatter = new Formatter();
205         try {
206             return decrypt(byteCipherText.getBytes(CHARSET),true);
207         } catch( UnsupportedEncodingException e ){
208             if(LOG.isWarnEnabled())
209             {
210                 LOG.warn(formatter.format("Missing encoding for %s",secKey.getAlgorithm()).toString(), e);
211             }
212         }finally {
213             formatter.close();
214         }
215         return Either.right("Decrypt FAILED");
216     }
217 }