e10bd81d0ffa3af508b9c80a96600c821d250461
[sdc.git] /
1 package org.openecomp.sdc.securityutil;/*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 import java.math.BigInteger;
25 import java.security.MessageDigest;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.SecureRandom;
28 import java.util.Arrays;
29 import java.util.Random;
30
31
32 public class Passwords {
33
34         private static Logger log = LoggerFactory.getLogger( Passwords.class.getName());
35         private static final Random RANDOM = new SecureRandom();
36         private static final int SALT = 0;
37         private static final int HASH = 1;
38         private static final String HASH_ALGORITHM = "SHA-256";
39
40         /**
41          * static utility class
42          */
43         private Passwords() {
44         }
45
46         /**
47          * the method calculates a hash with a generated salt for the given password
48          * 
49          * @param password
50          * @return a "salt:hash" value
51          */
52         public static String hashPassword(String password) {
53                 if (password!=null){
54                         byte[] salt = getNextSalt();
55                         byte byteData[] = hash(salt, password.getBytes());
56                         if (byteData != null) {
57                                 return toHex(salt) + ":" + toHex(byteData);
58                         }
59                 }
60                 return null;
61         }
62
63         /**
64          * the method checks if the given password matches the calculated hash
65          * 
66          * @param password
67          * @param expectedHash
68          * @return
69          */
70         public static boolean isExpectedPassword(String password, String expectedHash) {
71                 if (password==null && expectedHash==null)
72                         return true;
73                 if (password==null || expectedHash==null)       //iff exactly 1 is null
74                         return false;
75                 if (!expectedHash.contains(":")){
76                         log.error("invalid password expecting hash at the prefix of the password (ex. e0277df331f4ff8f74752ac4a8fbe03b:6dfbad308cdf53c9ff2ee2dca811ee92f1b359586b33027580e2ff92578edbd0)\n" +
77                                         "\t\t\t");
78                         return false;
79                 }
80                 String[] params = expectedHash.split(":");
81                 return isExpectedPassword(password, params[SALT], params[HASH]);
82         }
83
84         /**
85          * the method checks if the given password matches the calculated hash
86          * 
87          * @param password
88          * @param salt
89          * @param hash
90          *            the hash generated using the salt
91          * @return true if the password matched the hash
92          */
93         public static boolean isExpectedPassword(String password, String salt, String hash) {
94                 if ( password == null &&  hash == null )
95                         return true;
96                 if ( salt == null ){
97                         log.error("salt must be initialized");
98                         return false;
99                 }
100                 //unintialized params
101                 if ( password == null ||  hash == null )
102                         return false;
103                 byte[] saltBytes = fromHex(salt);
104                 byte[] hashBytes = fromHex(hash);
105
106                 byte byteData[] = hash(saltBytes, password.getBytes());
107                 if (byteData != null) {
108                         return Arrays.equals(byteData, hashBytes);
109                 }
110                 return false;
111         }
112
113         public static void main(String[] args) {
114                 if (args.length > 1 || args.length > 0) {
115                         System.out.println("[" + hashPassword(args[0]) + "]");
116                 } else {
117                         System.out.println("no passward passed.");
118                 }
119
120         }
121
122         /**
123          * Returns a random salt to be used to hash a password.
124          * 
125          * @return a 16 bytes random salt
126          */
127         private static byte[] getNextSalt() {
128                 byte[] salt = new byte[16];
129                 RANDOM.nextBytes(salt);
130                 return salt;
131         }
132
133         /**
134          * hase's the salt and value using the chosen algorithm
135          * 
136          * @param salt
137          * @param password
138          * @return an array of bytes resulting from the hash
139          */
140         private static byte[] hash(byte[] salt, byte[] password) {
141                 MessageDigest md;
142                 byte[] byteData = null;
143                 try {
144                         md = MessageDigest.getInstance(HASH_ALGORITHM);
145                         md.update(salt);
146                         md.update(password);
147                         byteData = md.digest();
148                 } catch (NoSuchAlgorithmException e) {
149                         System.out.println("invalid algorithm name");
150                 }
151                 return byteData;
152         }
153
154         /**
155          * Converts a string of hexadecimal characters into a byte array.
156          *
157          * @param hex
158          *            the hex string
159          * @return the hex string decoded into a byte array
160          */
161         private static byte[] fromHex(String hex) {
162                 if ( hex == null )
163                         return null;
164                 byte[] binary = new byte[hex.length() / 2];
165                 for (int i = 0; i < binary.length; i++) {
166                         binary[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
167                 }
168                 return binary;
169         }
170
171         /**
172          * Converts a byte array into a hexadecimal string.
173          *
174          * @param array
175          *            the byte array to convert
176          * @return a length*2 character string encoding the byte array
177          */
178         private static String toHex(byte[] array) {
179                 BigInteger bi = new BigInteger(1, array);
180                 String hex = bi.toString(16);
181                 int paddingLength = (array.length * 2) - hex.length();
182                 if (paddingLength > 0)
183                         return String.format("%0" + paddingLength + "d", 0) + hex;
184                 else
185                         return hex;
186         }
187 }