a8b302698dab34f265e744caab2bfe0d5aaa87b7
[appc.git] / appc-common / src / main / java / org / openecomp / appc / encryption / EncryptionTool.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : APP-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *                                              reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.appc.encryption;
23
24 import java.security.Provider;
25 import java.security.Provider.Service;
26 import java.security.Security;
27
28 import javax.crypto.Cipher;
29
30 import org.jasypt.contrib.org.apache.commons.codec_1_3.binary.Base64;
31 import org.jasypt.util.text.BasicTextEncryptor;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 /**
36  * This class is used to encapsulate the encryption and decryption support in one place and to provide a utility to
37  * encrypt and decrypt data.
38  */
39 public class EncryptionTool {
40
41     /**
42      * This lock object is used ONLY if the singleton has not been set up.
43      */
44     private static final Object lock = new Object();
45
46     /**
47      * The salt is used to initialize the PBE (password Based Encrpytion) algorithm.
48      */
49     private static final byte[] DEFAULT_SALT = {
50         (byte) 0xc7, (byte) 0x73, (byte) 0x21, (byte) 0x8c, (byte) 0x7e, (byte) 0xc8, (byte) 0xee, (byte) 0x99
51     };
52
53     /**
54      * The prefix we insert onto any data we encrypt so that we can tell if it is encrpyted later and therefore decrypt
55      * it
56      */
57     @SuppressWarnings("nls")
58     public static final String ENCRYPTED_VALUE_PREFIX = "enc:";
59
60     /**
61      * The instance of the encryption utility object
62      */
63     private static EncryptionTool instance = null;
64
65     /**
66      * The iteration count used to initialize the PBE algorithm and to generate the key spec
67      */
68     private static final int ITERATION_COUNT = 20;
69
70     /**
71      * The logger for this class.
72      */
73     private static final Logger LOG = LoggerFactory.getLogger(EncryptionTool.class);
74
75     /**
76      * The secret passphrase (PBE) that we use to perform encryption and decryption. The algorithm we are using is a
77      * symmetrical cipher.
78      */
79     private static char[] secret = {
80         'C', '_', 'z', 'l', '!', 'K', '!', '4', '?', 'O', 'z', 'E', 'K', 'E', '>', 'U', 'R', '/', '%', 'Y', '\\', 'f',
81         'b', '"', 'e', 'n', '{', '"', 'l', 'U', 'F', '+', 'E', '\'', 'R', 'T', 'p', '1', 'V', '4', 'l', 'a', '9', 'w',
82         'v', '5', 'Z', '#', 'i', 'V', '"', 'd', 'l', '!', 'L', 'M', 'g', 'L', 'Q', '{', 'v', 'v', 'K', 'V'
83     };
84
85     /**
86      * The algorithm to encrypt and decrpyt data is "Password (or passphrase) Based Encryption with Message Digest #5
87      * and the Data Encryption Standard", i.e., PBEWithMD5AndDES.
88      */
89     @SuppressWarnings("nls")
90     private static final String SECURITY_ALGORITHM = "PBEWITHMD5AND256BITAES";// "PBEWithMD5AndDES";
91
92     /**
93      * The decryption cipher object
94      */
95     private Cipher decryptCipher = null;
96
97     /**
98      * The encryption cipher object
99      */
100     private Cipher encryptCipher = null;
101
102     private BasicTextEncryptor encryptor;
103
104     /**
105      * Get an instance of the EncryptionTool
106      *
107      * @return The encryption tool to be used
108      */
109     public static final EncryptionTool getInstance() {
110         if (instance == null) {
111             synchronized (lock) {
112                 if (instance == null) {
113                     instance = new EncryptionTool();
114                 }
115             }
116         }
117         return instance;
118     }
119
120     /**
121      * Create the EncryptionTool instance
122      */
123     @SuppressWarnings("nls")
124     private EncryptionTool() {
125         String out = "Found the following security algorithms:";
126         for (Provider p : Security.getProviders()) {
127             for (Service s : p.getServices()) {
128                 String algo = s.getAlgorithm();
129                 out +=
130                     String.format("\n  -Algorithm [ %s ] in provider [ %s ] and service [ %s ]", algo, p.getName(),
131                         s.getClassName());
132             }
133         }
134         LOG.debug(out);
135     }
136
137     /**
138      * Decrypt the provided encrypted text
139      *
140      * @param cipherText
141      *            THe cipher text to be decrypted. If the ciphertext is not encrypted, then it is returned as is.
142      * @return the clear test of the (possibly) encrypted value. The original value if the string is not encrypted.
143      */
144     @SuppressWarnings("nls")
145     public synchronized String decrypt(String cipherText) {
146         if (isEncrypted(cipherText)) {
147             String encValue = cipherText.substring(ENCRYPTED_VALUE_PREFIX.length());
148             byte[] plainByte = Base64.decodeBase64(encValue.getBytes());
149             byte[] decryptByte = xorWithSecret(plainByte);
150             return new String(decryptByte);
151         } else {
152             return cipherText;
153         }
154
155     }
156
157     /**
158      * Encrypt the provided clear text
159      *
160      * @param clearText
161      *            The clear text to be encrypted
162      * @return the encrypted text. If the clear text is empty (null or zero length), then an empty string is returned.
163      *         If the clear text is already encrypted, it is not encrypted again and is returned as is. Otherwise, the
164      *         clear text is encrypted and returned.
165      */
166     @SuppressWarnings("nls")
167     public synchronized String encrypt(String clearText) {
168         if (clearText != null) {
169             byte[] encByte = xorWithSecret(clearText.getBytes());
170             String encryptedValue = new String(Base64.encodeBase64(encByte));
171             return ENCRYPTED_VALUE_PREFIX + encryptedValue;
172         } else {
173             return null;
174         }
175     }
176
177     /**
178      * Is a value encrypted? A value is considered to be encrypted if it begins with the
179      * {@linkplain #ENCRYPTED_VALUE_PREFIX encrypted value prefix}.
180      *
181      * @param value
182      *            the value to check.
183      * @return true/false;
184      */
185     private static boolean isEncrypted(final String value) {
186         return value != null && value.startsWith(ENCRYPTED_VALUE_PREFIX);
187     }
188
189     /**
190      * XORs the input byte array with the secret key, padding 0x0 to the end of the secret key if the input is longer
191      * and returns a byte array the same size as input
192      *
193      * @param inp
194      *            The byte array to be XORed with secret
195      * @return A byte array the same size as inp or null if input is null.
196      */
197     private byte[] xorWithSecret(byte[] inp) {
198         if (inp == null) {
199             return null;
200         }
201
202         byte[] secretBytes = new String(secret).getBytes();
203         int size = inp.length;
204
205         byte[] out = new byte[size];
206         for (int i = 0; i < size; i++) {
207             out[i] = (byte) ((inp[i]) ^ (secretBytes[i % secretBytes.length]));
208         }
209         return out;
210     }
211
212 }