re base code
[sdc.git] / security-utils / src / main / java / org / openecomp / sdc / security / SecurityUtil.java
1 package org.openecomp.sdc.security;
2
3 import fj.data.Either;
4 import org.slf4j.Logger;
5 import org.slf4j.LoggerFactory;
6
7 import javax.crypto.BadPaddingException;
8 import javax.crypto.Cipher;
9 import javax.crypto.IllegalBlockSizeException;
10 import javax.crypto.NoSuchPaddingException;
11 import javax.crypto.spec.SecretKeySpec;
12 import java.io.UnsupportedEncodingException;
13 import java.nio.charset.StandardCharsets;
14 import java.security.InvalidKeyException;
15 import java.security.Key;
16 import java.security.NoSuchAlgorithmException;
17 import java.util.Base64;
18
19 public class SecurityUtil {
20
21     private static final Logger LOG = LoggerFactory.getLogger( SecurityUtil.class );
22     private static final byte[] KEY = new byte[]{-64,5,-32 ,-117 ,-44,8,-39, 1, -9, 36,-46,-81, 62,-15,-63,-75};
23     public static final SecurityUtil INSTANCE = new SecurityUtil();
24     public static final String ALGORITHM = "AES" ;
25     public static final String CHARSET = StandardCharsets.UTF_8.name();
26
27     private static Key secKey = null ;
28
29     /**
30      *
31      * cmd commands >$PROGRAM_NAME decrypt "$ENCRYPTED_MSG"
32      *              >$PROGRAM_NAME encrypt "message"
33     **/
34     public static void main(String[] args) throws Exception {
35         if ( args!=null && args.length>1){
36             fj.data.Either res = null;
37             final String op = args[0].trim().toLowerCase();
38             try{
39                 switch(op) {
40                     case "decrypt":
41                         res = INSTANCE.decrypt(Base64.getDecoder().decode(args[1]), true);
42                         break;
43                     case "encrypt":
44                         res = INSTANCE.encrypt(args[1]);
45                         break;
46                     default:
47                         LOG.warn("Unfamiliar command please use: \n>aes <encrypt/decrypt> 'message to encrypt/decrypt' ");
48                 }
49             }catch(Exception e){
50                 LOG.debug( "cannot perform {}:" );
51                 throw e;
52             }
53             LOG.debug( "output: {}", res!=null && res.isLeft() ? res.left().value() : "ERROR" );
54         }
55     }
56
57     private SecurityUtil(){ super(); }
58
59     static {
60         try{
61             secKey = generateKey( KEY, ALGORITHM );
62         }
63         catch(Exception e){
64             LOG.warn("cannot generate key for {}", ALGORITHM);
65         }
66     }
67
68
69
70     public static Key generateKey(final byte[] KEY, String algorithm){
71         return new SecretKeySpec(KEY, algorithm);
72     }
73
74     //obfuscates key prefix -> **********
75     public String obfuscateKey(String sensitiveData){
76
77         if (sensitiveData != null){
78             int len = sensitiveData.length();
79             StringBuilder builder = new StringBuilder(sensitiveData);
80             for (int i=0; i<len/2; i++){
81                 builder.setCharAt(i, '*');
82             }
83             return builder.toString();
84         }
85         return sensitiveData;
86     }
87
88     /**
89      *  @param strDataToEncrypt - plain string to encrypt
90      *  Encrypt the Data
91      *          a. Declare / Initialize the Data. Here the data is of type String
92      *          b. Convert the Input Text to Bytes
93      *          c. Encrypt the bytes using doFinal method
94      */
95     public Either<String,String> encrypt(String strDataToEncrypt){
96         if (strDataToEncrypt != null ){
97             try {
98                 LOG.debug("Encrypt key -> {}", secKey);
99                 Cipher aesCipherForEncryption = Cipher.getInstance("AES");          // Must specify the mode explicitly as most JCE providers default to ECB mode!!
100                 aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secKey);
101                 byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();
102                 byte[] byteCipherText = aesCipherForEncryption.doFinal(byteDataToEncrypt);
103                 String strCipherText = new String( java.util.Base64.getMimeEncoder().encode(byteCipherText), CHARSET );
104                 LOG.debug("Cipher Text generated using AES is {}", strCipherText);
105                 return Either.left(strCipherText);
106             } catch( NoSuchAlgorithmException | UnsupportedEncodingException e){
107                 LOG.warn( "cannot encrypt data unknown algorithm or missing encoding for {}" ,secKey.getAlgorithm());
108             } catch( InvalidKeyException e){
109                 LOG.warn( "invalid key recieved - > {} | {}" , java.util.Base64.getDecoder().decode( secKey.getEncoded() ), e.getMessage() );
110             } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException  e){
111                 LOG.warn( "bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding" , e.getMessage() );
112             }
113         }
114         return Either.right("Cannot encrypt "+strDataToEncrypt);
115     }
116
117     /**
118      * Decrypt the Data
119      * @param byteCipherText - should be valid bae64 input in the length of 16bytes
120      * @param isBase64Decoded - is data already base64 encoded&aligned to 16 bytes
121      *          a. Initialize a new instance of Cipher for Decryption (normally don't reuse the same object)
122      *          b. Decrypt the cipher bytes using doFinal method
123      */
124     public Either<String,String> decrypt(byte[] byteCipherText , boolean isBase64Decoded){
125         if (byteCipherText != null){
126             byte[] alignedCipherText = byteCipherText;
127             try{
128                 if (isBase64Decoded)
129                     alignedCipherText = Base64.getDecoder().decode(byteCipherText);
130                 LOG.debug("Decrypt key -> "+secKey.getEncoded());
131                 Cipher aesCipherForDecryption = Cipher.getInstance("AES"); // Must specify the mode explicitly as most JCE providers default to ECB mode!!
132                 aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secKey);
133                 byte[] byteDecryptedText = aesCipherForDecryption.doFinal(alignedCipherText);
134                 String strDecryptedText = new String(byteDecryptedText);
135                 LOG.debug("Decrypted Text message is: {}" , obfuscateKey( strDecryptedText ));
136                 return Either.left(strDecryptedText);
137             } catch( NoSuchAlgorithmException e){
138                 LOG.warn( "cannot encrypt data unknown algorithm or missing encoding for {}" ,secKey.getAlgorithm());
139             } catch( InvalidKeyException e){
140                 LOG.warn( "invalid key recieved - > {} | {}" , java.util.Base64.getDecoder().decode( secKey.getEncoded() ), e.getMessage() );
141             } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException  e){
142                 LOG.warn( "bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding" , e.getMessage() );
143             }
144         }
145         return Either.right("Decrypt FAILED");
146     }
147
148     public Either<String,String> decrypt(String byteCipherText){
149         try {
150             return decrypt(byteCipherText.getBytes(CHARSET),true);
151         } catch( UnsupportedEncodingException e ){
152             LOG.warn( "Missing encoding for {} | {} " ,secKey.getAlgorithm() , e.getMessage());
153         }
154         return Either.right("Decrypt FAILED");
155     }
156 }