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