2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.openecomp.sdc.security;
23 import fj.data.Either;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
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;
40 public class SecurityUtil {
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();
48 private static Key secKey = null ;
50 private SecurityUtil(){ super(); }
54 * cmd commands >$PROGRAM_NAME decrypt "$ENCRYPTED_MSG"
55 * >$PROGRAM_NAME encrypt "message"
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();
64 res = INSTANCE.decrypt(Base64.getDecoder().decode(args[1]), true);
67 res = INSTANCE.encrypt(args[1]);
70 LOG.warn("Unfamiliar command please use: \n>aes <encrypt/decrypt> 'message to encrypt/decrypt' ");
73 LOG.warn("Exception while message encryption or decryption");
76 LOG.debug( "output: {}", res!=null && res.isLeft() ? res.left().value() : "ERROR" );
82 Formatter formatter = new Formatter();
84 secKey = generateKey( KEY, ALGORITHM );
87 if(LOG.isWarnEnabled())
89 LOG.warn(formatter.format("cannot generate key for %s", ALGORITHM).toString(), e);
98 public static Key generateKey(final byte[] key, String algorithm){
99 return new SecretKeySpec(key, algorithm);
102 //obfuscates key prefix -> **********
103 public String obfuscateKey(String sensitiveData){
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, '*');
111 return builder.toString();
113 return sensitiveData;
117 * @param strDataToEncrypt - plain string to encrypt
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
123 public Either<String,String> encrypt(String strDataToEncrypt){
125 if (strDataToEncrypt != null ){
126 Formatter formatter = new Formatter();
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())
139 LOG.warn(formatter.format("cannot encrypt data unknown algorithm or missing encoding for %s",secKey.getAlgorithm()).toString(), e);
141 } catch( InvalidKeyException e){
142 if(LOG.isWarnEnabled())
144 LOG.warn(formatter.format("invalid key recieved - > %s", java.util.Base64.getDecoder().decode(secKey.getEncoded())).toString(), e);
146 } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e){
147 if(LOG.isWarnEnabled())
149 LOG.warn("bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding", e);
156 return Either.right("Cannot encrypt "+strDataToEncrypt);
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
166 public Either<String,String> decrypt(byte[] byteCipherText , boolean isBase64Decoded){
167 if (byteCipherText != null){
168 byte[] alignedCipherText = byteCipherText;
169 Formatter formatter = new Formatter();
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())
184 LOG.warn(formatter.format("cannot encrypt data unknown algorithm or missing encoding for %s", secKey.getAlgorithm()).toString(), e);
186 } catch( InvalidKeyException e){
187 if(LOG.isWarnEnabled())
189 LOG.warn(formatter.format("invalid key recieved - > %s", java.util.Base64.getDecoder().decode(secKey.getEncoded())).toString(), e);
191 } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e){
192 if(LOG.isWarnEnabled())
194 LOG.warn( "bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding", e);
200 return Either.right("Decrypt FAILED");
203 public Either<String,String> decrypt(String byteCipherText){
204 Formatter formatter = new Formatter();
206 return decrypt(byteCipherText.getBytes(CHARSET),true);
207 } catch( UnsupportedEncodingException e ){
208 if(LOG.isWarnEnabled())
210 LOG.warn(formatter.format("Missing encoding for %s",secKey.getAlgorithm()).toString(), e);
215 return Either.right("Decrypt FAILED");