2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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 * ===================================================================
24 package org.onap.clamp.clds.util;
26 import com.att.eelf.configuration.EELFLogger;
27 import com.att.eelf.configuration.EELFManager;
28 import com.google.common.base.Charsets;
29 import java.io.IOException;
30 import java.io.UnsupportedEncodingException;
31 import java.security.GeneralSecurityException;
32 import java.security.SecureRandom;
33 import java.util.Properties;
34 import javax.crypto.Cipher;
35 import javax.crypto.spec.IvParameterSpec;
36 import javax.crypto.spec.SecretKeySpec;
37 import org.apache.commons.codec.DecoderException;
38 import org.apache.commons.codec.binary.Hex;
39 import org.apache.commons.lang3.ArrayUtils;
42 * CryptoUtils for encrypting/decrypting string based on a Key defined in
43 * application.properties (Spring config file).
45 public final class CryptoUtils {
48 * Used to log CryptoUtils class.
50 private static final EELFLogger logger = EELFManager.getInstance().getLogger(CryptoUtils.class);
52 // Encrypt: echo -n "123456" | openssl aes-128-cbc -e -K <Private Hex key>
53 // -iv <16 Bytes iv (HEX), be careful it's 32 Hex Chars> | xxd -u -g100
54 // Final result is to put in properties file is: IV + Outcome of openssl
56 // ************************************************************
57 // Decrypt: echo -n 'Encrypted string' | xxd -r -ps | openssl aes-128-cbc -d
59 // <Private Hex Key> -iv <16 Bytes IV extracted from Encrypted String, be
60 // careful it's 32 Hex Chars>
62 * Definition of encryption algorithm.
64 private static final String ALGORITHM = "AES";
67 * AES Encryption Key environment variable for external configuration.
69 private static final String AES_ENCRYPTION_KEY = "AES_ENCRYPTION_KEY";
72 * Detailed definition of encryption algorithm.
74 private static final String ALGORITHM_DETAILS = ALGORITHM + "/CBC/PKCS5PADDING";
75 private static final int IV_BLOCK_SIZE_IN_BITS = 128;
77 * An Initial Vector of 16 Bytes, so 32 Hexadecimal Chars.
79 private static final int IV_BLOCK_SIZE_IN_BYTES = IV_BLOCK_SIZE_IN_BITS / 8;
81 * Key to read in the key.properties file.
83 private static final String KEY_PARAM = "org.onap.clamp.encryption.aes.key";
84 private static final String PROPERTIES_FILE_NAME = "clds/key.properties";
86 * The SecretKeySpec created from the Base 64 String key.
88 private static final SecretKeySpec SECRET_KEY_SPEC = readSecretKeySpec(PROPERTIES_FILE_NAME);
91 * Private constructor to avoid creating instances of util class.
93 private CryptoUtils() {
97 * Encrypt a value based on the Clamp Encryption Key.
99 * @param value The value to encrypt
100 * @return The encrypted string
101 * @throws GeneralSecurityException In case of issue with the encryption
102 * @throws UnsupportedEncodingException In case of issue with the charset
105 public static String encrypt(String value) throws GeneralSecurityException {
106 Cipher cipher = Cipher.getInstance(ALGORITHM_DETAILS, "SunJCE");
107 byte[] iv = new byte[IV_BLOCK_SIZE_IN_BYTES];
108 SecureRandom.getInstance("SHA1PRNG").nextBytes(iv);
109 IvParameterSpec ivspec = new IvParameterSpec(iv);
110 cipher.init(Cipher.ENCRYPT_MODE, SECRET_KEY_SPEC, ivspec);
111 return Hex.encodeHexString(ArrayUtils.addAll(iv, cipher.doFinal(value.getBytes(Charsets.UTF_8))));
115 * Decrypt a value based on the Clamp Encryption Key.
117 * @param message The encrypted string that must be decrypted using the Clamp
119 * @return The String decrypted
120 * @throws GeneralSecurityException In case of issue with the encryption
121 * @throws DecoderException In case of issue to decode the HexString
123 public static String decrypt(String message) throws GeneralSecurityException, DecoderException {
124 byte[] encryptedMessage = Hex.decodeHex(message.toCharArray());
125 Cipher cipher = Cipher.getInstance(ALGORITHM_DETAILS, "SunJCE");
126 IvParameterSpec ivspec = new IvParameterSpec(ArrayUtils.subarray(encryptedMessage, 0, IV_BLOCK_SIZE_IN_BYTES));
127 byte[] realData = ArrayUtils.subarray(encryptedMessage, IV_BLOCK_SIZE_IN_BYTES, encryptedMessage.length);
128 cipher.init(Cipher.DECRYPT_MODE, SECRET_KEY_SPEC, ivspec);
129 byte[] decrypted = cipher.doFinal(realData);
130 return new String(decrypted);
134 * Method used to generate the SecretKeySpec from a Base64 String.
136 * @param keyString The key as a string in Base 64
137 * @return The SecretKeySpec created
138 * @throws DecoderException In case of issues with the decoding of Base64
140 private static SecretKeySpec getSecretKeySpec(String keyString) throws DecoderException {
141 byte[] key = Hex.decodeHex(keyString.toCharArray());
142 return new SecretKeySpec(key, ALGORITHM);
146 * Reads SecretKeySpec from file specified by propertiesFileName.
148 * @param propertiesFileName File name with properties
149 * @return SecretKeySpec secret key spec read from propertiesFileName
151 private static SecretKeySpec readSecretKeySpec(String propertiesFileName) {
152 Properties props = new Properties();
154 // Workaround fix to make encryption key configurable
155 // System environment variable takes precedence for over clds/key.properties
156 String encryptionKey = System.getenv(AES_ENCRYPTION_KEY);
157 if (encryptionKey != null && encryptionKey.trim().length() > 0) {
158 return getSecretKeySpec(encryptionKey);
160 props.load(ResourceFileUtils.getResourceAsStream(propertiesFileName));
161 return getSecretKeySpec(props.getProperty(KEY_PARAM));
163 } catch (IOException | DecoderException e) {
164 logger.error("Exception occurred during the key reading", e);