summaryrefslogtreecommitdiffstats
path: root/security-utils
diff options
context:
space:
mode:
authorMichael Lando <ml636r@att.com>2018-03-04 14:53:33 +0200
committerMichael Lando <ml636r@att.com>2018-03-07 13:19:05 +0000
commita5445100050e49e83f73424198d73cd72d672a4d (patch)
treecacf4df817df31be23e4e790d1dda857bdae061e /security-utils
parent51157f92c21976cba4914c378aaa3cba49826931 (diff)
Sync Integ to Master
Change-Id: I71e3acc26fa612127756ac04073a522b9cc6cd74 Issue-ID: SDC-977 Signed-off-by: Gitelman, Tal (tg851x) <tg851x@intl.att.com>
Diffstat (limited to 'security-utils')
-rw-r--r--security-utils/logback-test.xml13
-rw-r--r--security-utils/pom.xml20
-rw-r--r--security-utils/src/main/java/org/openecomp/sdc/security/Passwords.java36
-rw-r--r--security-utils/src/main/java/org/openecomp/sdc/security/SecurityUtil.java155
-rw-r--r--security-utils/src/test/java/org/openecomp/sdc/security/PasswordTest.java48
-rw-r--r--security-utils/src/test/java/org/openecomp/sdc/security/PasswordsTest.java75
-rw-r--r--security-utils/src/test/java/org/openecomp/sdc/security/SecurityUtilTest.java27
7 files changed, 321 insertions, 53 deletions
diff --git a/security-utils/logback-test.xml b/security-utils/logback-test.xml
new file mode 100644
index 0000000000..4b7eb955c7
--- /dev/null
+++ b/security-utils/logback-test.xml
@@ -0,0 +1,13 @@
+<!-- only one line, shut up logback ! -->
+<configuration >
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <Pattern>
+ %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
+ </Pattern>
+ </encoder>
+ </appender>
+ <root level="OFF">
+ <appender-ref ref="STDOUT" />
+ </root>
+</configuration>
diff --git a/security-utils/pom.xml b/security-utils/pom.xml
index ec707c23e4..a6e9befe5d 100644
--- a/security-utils/pom.xml
+++ b/security-utils/pom.xml
@@ -11,13 +11,33 @@
<version>1.2.0-SNAPSHOT</version>
</parent>
+ <properties>
+ <sonar.skip>true</sonar.skip>
+ </properties>
+
<dependencies>
+
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
+
+ <!-- slf4j + logback -->
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4j-api.version}</version>
+ <scope>compile</scope>
+ </dependency>
+ <!-- functional java -->
+ <dependency>
+ <groupId>org.functionaljava</groupId>
+ <artifactId>functionaljava</artifactId>
+ <version>${functionaljava.version}</version>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/security-utils/src/main/java/org/openecomp/sdc/security/Passwords.java b/security-utils/src/main/java/org/openecomp/sdc/security/Passwords.java
index ef424b95de..5f5e00722e 100644
--- a/security-utils/src/main/java/org/openecomp/sdc/security/Passwords.java
+++ b/security-utils/src/main/java/org/openecomp/sdc/security/Passwords.java
@@ -20,6 +20,9 @@
package org.openecomp.sdc.security;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -27,8 +30,10 @@ import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Random;
+
public class Passwords {
+ private static Logger log = LoggerFactory.getLogger( Passwords.class.getName());
private static final Random RANDOM = new SecureRandom();
private static final int SALT = 0;
private static final int HASH = 1;
@@ -47,13 +52,14 @@ public class Passwords {
* @return a "salt:hash" value
*/
public static String hashPassword(String password) {
- byte[] salt = getNextSalt();
- byte byteData[] = hash(salt, password.getBytes());
- if (byteData != null) {
- return toHex(salt) + ":" + toHex(byteData);
+ if (password!=null){
+ byte[] salt = getNextSalt();
+ byte byteData[] = hash(salt, password.getBytes());
+ if (byteData != null) {
+ return toHex(salt) + ":" + toHex(byteData);
+ }
}
return null;
-
}
/**
@@ -64,6 +70,15 @@ public class Passwords {
* @return
*/
public static boolean isExpectedPassword(String password, String expectedHash) {
+ if (password==null && expectedHash==null)
+ return true;
+ if (password==null || expectedHash==null) //iff exactly 1 is null
+ return false;
+ if (!expectedHash.contains(":")){
+ log.error("invalid password expecting hash at the prefix of the password (ex. e0277df331f4ff8f74752ac4a8fbe03b:6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0)\n" +
+ "\t\t\t");
+ return false;
+ }
String[] params = expectedHash.split(":");
return isExpectedPassword(password, params[SALT], params[HASH]);
}
@@ -78,6 +93,15 @@ public class Passwords {
* @return true if the password matched the hash
*/
public static boolean isExpectedPassword(String password, String salt, String hash) {
+ if ( password == null && hash == null )
+ return true;
+ if ( salt == null ){
+ log.error("salt must be initialized");
+ return false;
+ }
+ //unintialized params
+ if ( password == null || hash == null )
+ return false;
byte[] saltBytes = fromHex(salt);
byte[] hashBytes = fromHex(hash);
@@ -137,6 +161,8 @@ public class Passwords {
* @return the hex string decoded into a byte array
*/
private static byte[] fromHex(String hex) {
+ if ( hex == null )
+ return null;
byte[] binary = new byte[hex.length() / 2];
for (int i = 0; i < binary.length; i++) {
binary[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
diff --git a/security-utils/src/main/java/org/openecomp/sdc/security/SecurityUtil.java b/security-utils/src/main/java/org/openecomp/sdc/security/SecurityUtil.java
new file mode 100644
index 0000000000..892c29b88f
--- /dev/null
+++ b/security-utils/src/main/java/org/openecomp/sdc/security/SecurityUtil.java
@@ -0,0 +1,155 @@
+package org.openecomp.sdc.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import fj.data.*;
+
+public class SecurityUtil {
+
+ private static final Logger LOG = LoggerFactory.getLogger( SecurityUtil.class );
+ private static final byte[] KEY = new byte[]{-64,5,-32 ,-117 ,-44,8,-39, 1, -9, 36,-46,-81, 62,-15,-63,-75};
+ public static final SecurityUtil INSTANCE = new SecurityUtil();
+ public static final String ALGORITHM = "AES" ;
+ public static final String CHARSET = StandardCharsets.UTF_8.name();
+
+ public static Key secKey = null ;
+
+ /**
+ *
+ * cmd commands >$PROGRAM_NAME decrypt "$ENCRYPTED_MSG"
+ * >$PROGRAM_NAME encrypt "message"
+ **/
+ public static void main(String[] args) throws Exception {
+ if ( args!=null && args.length>1){
+ fj.data.Either res = null;
+ final String op = args[0].trim().toLowerCase();
+ try{
+ switch(op) {
+ case "decrypt":
+ res = INSTANCE.decrypt(Base64.getDecoder().decode(args[1]), true);
+ break;
+ case "encrypt":
+ res = INSTANCE.encrypt(args[1]);
+ break;
+ default:
+ LOG.warn("Unfamiliar command please use: \n>aes <encrypt/decrypt> 'message to encrypt/decrypt' ");
+ }
+ }catch(Exception e){
+ LOG.debug( "cannot perform {}:" );
+ throw e;
+ }
+ LOG.debug( "output: {}", res!=null && res.isLeft() ? res.left().value() : "ERROR" );
+ }
+ }
+
+ private SecurityUtil(){ super(); }
+
+ static {
+ try{
+ secKey = generateKey( KEY, ALGORITHM );
+ }
+ catch(Exception e){
+ LOG.warn("cannot generate key for {}", ALGORITHM);
+ }
+ }
+
+
+
+ public static Key generateKey(final byte[] KEY, String algorithm){
+ return new SecretKeySpec(KEY, algorithm);
+ }
+
+ //obfuscates key prefix -> **********
+ public String obfuscateKey(String sensitiveData){
+
+ if (sensitiveData != null){
+ int len = sensitiveData.length();
+ StringBuilder builder = new StringBuilder(sensitiveData);
+ for (int i=0; i<len/2; i++){
+ builder.setCharAt(i, '*');
+ }
+ return builder.toString();
+ }
+ return sensitiveData;
+ }
+
+ /**
+ * @param strDataToEncrypt - plain string to encrypt
+ * Encrypt the Data
+ * a. Declare / Initialize the Data. Here the data is of type String
+ * b. Convert the Input Text to Bytes
+ * c. Encrypt the bytes using doFinal method
+ */
+ public Either<String,String> encrypt(String strDataToEncrypt){
+ if (strDataToEncrypt != null ){
+ try {
+ LOG.debug("Encrypt key -> {}", secKey);
+ Cipher aesCipherForEncryption = Cipher.getInstance("AES"); // Must specify the mode explicitly as most JCE providers default to ECB mode!!
+ aesCipherForEncryption.init(Cipher.ENCRYPT_MODE, secKey);
+ byte[] byteDataToEncrypt = strDataToEncrypt.getBytes();
+ byte[] byteCipherText = aesCipherForEncryption.doFinal(byteDataToEncrypt);
+ String strCipherText = new String( java.util.Base64.getMimeEncoder().encode(byteCipherText), CHARSET );
+ LOG.debug("Cipher Text generated using AES is {}", strCipherText);
+ return Either.left(strCipherText);
+ } catch( NoSuchAlgorithmException | UnsupportedEncodingException e){
+ LOG.warn( "cannot encrypt data unknown algorithm or missing encoding for {}" ,secKey.getAlgorithm());
+ } catch( InvalidKeyException e){
+ LOG.warn( "invalid key recieved - > {} | {}" , java.util.Base64.getDecoder().decode( secKey.getEncoded() ), e.getMessage() );
+ } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e){
+ LOG.warn( "bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding" , e.getMessage() );
+ }
+ }
+ return Either.right("Cannot encrypt "+strDataToEncrypt);
+ }
+
+ /**
+ * Decrypt the Data
+ * @param byteCipherText - should be valid bae64 input in the length of 16bytes
+ * @param isBase64Decoded - is data already base64 encoded&aligned to 16 bytes
+ * a. Initialize a new instance of Cipher for Decryption (normally don't reuse the same object)
+ * b. Decrypt the cipher bytes using doFinal method
+ */
+ public Either<String,String> decrypt(byte[] byteCipherText , boolean isBase64Decoded){
+ if (byteCipherText != null){
+ byte[] alignedCipherText = byteCipherText;
+ try{
+ if (isBase64Decoded)
+ alignedCipherText = Base64.getDecoder().decode(byteCipherText);
+ LOG.debug("Decrypt key -> "+secKey.getEncoded());
+ Cipher aesCipherForDecryption = Cipher.getInstance("AES"); // Must specify the mode explicitly as most JCE providers default to ECB mode!!
+ aesCipherForDecryption.init(Cipher.DECRYPT_MODE, secKey);
+ byte[] byteDecryptedText = aesCipherForDecryption.doFinal(alignedCipherText);
+ String strDecryptedText = new String(byteDecryptedText);
+ LOG.debug("Decrypted Text message is: {}" , obfuscateKey( strDecryptedText ));
+ return Either.left(strDecryptedText);
+ } catch( NoSuchAlgorithmException e){
+ LOG.warn( "cannot encrypt data unknown algorithm or missing encoding for {}" ,secKey.getAlgorithm());
+ } catch( InvalidKeyException e){
+ LOG.warn( "invalid key recieved - > {} | {}" , java.util.Base64.getDecoder().decode( secKey.getEncoded() ), e.getMessage() );
+ } catch( IllegalBlockSizeException | BadPaddingException | NoSuchPaddingException e){
+ LOG.warn( "bad algorithm definition (Illegal Block Size or padding), please review you algorithm block&padding" , e.getMessage() );
+ }
+ }
+ return Either.right("Decrypt FAILED");
+ }
+
+ public Either<String,String> decrypt(String byteCipherText){
+ try {
+ return decrypt(byteCipherText.getBytes(CHARSET),true);
+ } catch( UnsupportedEncodingException e ){
+ LOG.warn( "Missing encoding for {} | {} " ,secKey.getAlgorithm() , e.getMessage());
+ }
+ return Either.right("Decrypt FAILED");
+ }
+}
diff --git a/security-utils/src/test/java/org/openecomp/sdc/security/PasswordTest.java b/security-utils/src/test/java/org/openecomp/sdc/security/PasswordTest.java
deleted file mode 100644
index 895806d1b5..0000000000
--- a/security-utils/src/test/java/org/openecomp/sdc/security/PasswordTest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * SDC
- * ================================================================================
- * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END=========================================================
- */
-
-package org.openecomp.sdc.security;
-
-import static org.junit.Assert.assertTrue;
-
-import org.junit.Test;
-
-public class PasswordTest {
-
- @Test
- public void hashtest() {
- String password = "123456";
- String hash = Passwords.hashPassword(password);
- assertTrue(Passwords.isExpectedPassword(password, hash));
- password = "1sdfgsgd23456";
- hash = Passwords.hashPassword(password);
- assertTrue(Passwords.isExpectedPassword(password, hash));
- password = "1sdfgsgd2345((*&%$%6";
- hash = Passwords.hashPassword(password);
- assertTrue(Passwords.isExpectedPassword(password, hash));
- password = "";
- hash = Passwords.hashPassword(password);
- assertTrue(Passwords.isExpectedPassword(password, hash));
- password = " ";
- hash = Passwords.hashPassword(password);
- assertTrue(Passwords.isExpectedPassword(password, hash));
- }
-
-}
diff --git a/security-utils/src/test/java/org/openecomp/sdc/security/PasswordsTest.java b/security-utils/src/test/java/org/openecomp/sdc/security/PasswordsTest.java
new file mode 100644
index 0000000000..26f04735e5
--- /dev/null
+++ b/security-utils/src/test/java/org/openecomp/sdc/security/PasswordsTest.java
@@ -0,0 +1,75 @@
+package org.openecomp.sdc.security;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class PasswordsTest {
+
+ @Test
+ public void hashPassword() throws Exception {
+ String hash = Passwords.hashPassword("hello1234");
+ assertEquals(true, Passwords.isExpectedPassword("hello1234", hash));
+
+ //test different salt-> result in different hash
+ String hash2 = Passwords.hashPassword("hello1234");
+ assertEquals(false, hash.equals(hash2));
+
+ String hash3 = Passwords.hashPassword("");
+ assertEquals(true, Passwords.isExpectedPassword("", hash3));
+
+ String hash4 = Passwords.hashPassword(null);
+ assertEquals(true, hash4 == null );
+ }
+
+ @Test
+ public void isExpectedPassword() throws Exception {
+ //region isExpectedPassword(String password, String salt, String hash)
+ assertEquals(true, Passwords.isExpectedPassword(null, null , null));
+ //valid hash
+ assertEquals(true, Passwords.isExpectedPassword("hello1234", "e0277df331f4ff8f74752ac4a8fbe03b","6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0"));
+ //invalid salt
+ assertEquals(false, Passwords.isExpectedPassword("hello1234", "c0000df331f4ff8f74752ac4a00be03c","6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0"));
+ assertEquals(false, Passwords.isExpectedPassword("hello1234", null,"6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0"));
+ //exacly 1 param uninitialized
+ assertEquals(false,Passwords.isExpectedPassword("hello1234", "",null));
+ assertEquals(false,Passwords.isExpectedPassword( null, "" , "hello1234"));
+ //no salt & no hash
+ assertEquals(false, Passwords.isExpectedPassword("hello1234", null ,"hello1234"));
+ //endregion
+
+ //region isExpectedPassword(String password, String expectedHash)
+ assertEquals(true, Passwords.isExpectedPassword(null, null));
+ //valid hash
+ assertEquals(true, Passwords.isExpectedPassword("hello1234", "e0277df331f4ff8f74752ac4a8fbe03b:6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0"));
+ //invalid salt
+ assertEquals(false, Passwords.isExpectedPassword("hello1234", "c0000df331f4ff8f74752ac4a00be03c:6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0"));
+ //exacly 1 param uninitialized
+ assertEquals(false,Passwords.isExpectedPassword("hello1234", null));
+ assertEquals(false,Passwords.isExpectedPassword( null,"hello1234"));
+ //no salt & no hash
+ assertEquals(false, Passwords.isExpectedPassword("hello1234", "hello1234"));
+ //endregion
+ }
+
+ @Test
+ public void hashtest() {
+ String password = "123456";
+ String hash = Passwords.hashPassword(password);
+ assertTrue(Passwords.isExpectedPassword(password, hash));
+ password = "1sdfgsgd23456";
+ hash = Passwords.hashPassword(password);
+ assertTrue(Passwords.isExpectedPassword(password, hash));
+ password = "1sdfgsgd2345((*&%$%6";
+ hash = Passwords.hashPassword(password);
+ assertTrue(Passwords.isExpectedPassword(password, hash));
+ password = "";
+ hash = Passwords.hashPassword(password);
+ assertTrue(Passwords.isExpectedPassword(password, hash));
+ password = " ";
+ hash = Passwords.hashPassword(password);
+ assertTrue(Passwords.isExpectedPassword(password, hash));
+ }
+
+
+} \ No newline at end of file
diff --git a/security-utils/src/test/java/org/openecomp/sdc/security/SecurityUtilTest.java b/security-utils/src/test/java/org/openecomp/sdc/security/SecurityUtilTest.java
new file mode 100644
index 0000000000..e23c864b77
--- /dev/null
+++ b/security-utils/src/test/java/org/openecomp/sdc/security/SecurityUtilTest.java
@@ -0,0 +1,27 @@
+package org.openecomp.sdc.security;
+
+import org.junit.Test;
+import java.util.Base64;
+import static org.junit.Assert.*;
+
+public class SecurityUtilTest {
+
+ @Test
+ public void encryptDecryptAES128() throws Exception {
+ String data = "decrypt SUCCESS!!";
+ String encrypted = SecurityUtil.INSTANCE.encrypt(data).left().value();
+ assertNotEquals( data, encrypted );
+ byte[] decryptMsg = Base64.getDecoder().decode(encrypted);
+ assertEquals( SecurityUtil.INSTANCE.decrypt( decryptMsg , false ).left().value() ,data );
+ assertEquals( SecurityUtil.INSTANCE.decrypt( encrypted.getBytes() , true ).left().value() ,data );
+ }
+
+ @Test
+ public void obfuscateKey() throws Exception {
+ String key = "abcdefghij123456";
+ String expectedkey = "********ij123456";
+ String obfuscated = SecurityUtil.INSTANCE.obfuscateKey( key );
+ System.out.println( obfuscated );
+ assertEquals( obfuscated , expectedkey );
+ }
+} \ No newline at end of file