Open Kilda Java Documentation
TwoFactorUtility.java
Go to the documentation of this file.
1 package org.openkilda.security;
2 
3 import java.lang.reflect.UndeclaredThrowableException;
4 import java.math.BigInteger;
5 import java.nio.charset.StandardCharsets;
6 import java.security.GeneralSecurityException;
7 import java.security.SecureRandom;
8 import java.text.DateFormat;
9 import java.text.SimpleDateFormat;
10 import java.util.TimeZone;
11 
12 import javax.crypto.Mac;
13 import javax.crypto.spec.SecretKeySpec;
14 
15 import org.apache.commons.codec.binary.Base32;
16 import org.apache.commons.codec.binary.Base64;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 
20 public class TwoFactorUtility {
21 
22  private static Log logger = LogFactory.getLog(TwoFactorUtility.class);
23  private static final int[] DIGITS_POWER
24  // 0 1 2 3 4 5 6 7 8
25  = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
26 
27  public static String getBase32EncryptedKey() {
28  SecureRandom random = new SecureRandom();
29  byte bytes[] = new byte[20];
30  random.nextBytes(bytes);
31  Base32 base32 = new Base32();
32  String base32String = base32.encodeAsString(bytes);
33 
34  logger.debug(" getBase32EncryptedKey method response " + base32String);
35 
36  return base32String;
37  }
38 
39  public static String generateEncryptedKey(final String base32String) {
40  logger.debug("[generateEncryptedKey] param : base32String " + base32String);
41  String generatedKey = null;
42  try {
43  String rsaString = RSAEncryptionDescription.rsaEncrypt(base32String.getBytes(), "");
44  byte[] key = Base64.encodeBase64(rsaString.getBytes());
45  generatedKey = new String(key);
46  } catch (Exception e) {
47  logger.error("[generateEncryptedKey] Exception :" + e);
48 
49  }
50 
51  logger.debug("[generateEncryptedKey] response " + generatedKey);
52 
53  return generatedKey;
54  }
55 
56  public static String decryptKey(final String secretKey) throws Exception {
57  logger.debug("[decryptKey] param : secretKey " + secretKey);
58  byte[] decodedArray = Base64.decodeBase64(secretKey.getBytes());
59  String decodeValue = new String(decodedArray, StandardCharsets.UTF_8);
60  String decryptKey = RSAEncryptionDescription.rsaDecrypt(decodeValue, "");
61 
62  logger.debug("[decryptKey] response " + decryptKey);
63  return decryptKey;
64  }
65 
66  public static boolean validateOtp(final String otp, final String decryptKey) {
67  logger.debug("[validateOtp] param : ,decryptKey : " + decryptKey);
68  boolean otpValid = false;
69  Base32 base32 = new Base32();
70  byte decoded[] = base32.decode(decryptKey);
71  String byteToHex = bytesToHex(decoded);
72  String seed = byteToHex;
73  long T0 = 0;
74  long X = 30;
75  String codelength = "6";
76  long z = System.currentTimeMillis() / 1000;
77 
78  long testTime[] = {z};
79  String steps = "0";
80  DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
81  df.setTimeZone(TimeZone.getTimeZone("UTC"));
82  String otpVal = "";
83  try {
84  for (int i = 0; i < testTime.length; i++) {
85  long T = (testTime[i] - T0) / X;
86  steps = Long.toHexString(T).toUpperCase();
87  while (steps.length() < 16) {
88  steps = "0" + steps;
89  }
90  otpVal = generateTOTP(seed, steps, codelength, "HmacSHA1");
91  }
92  } catch (Exception e) {
93  logger.error("[validateOtp] Exception :" + e);
94  }
95 
96  if (otp.equals(otpVal)) {
97  otpValid = true;
98  }
99 
100  logger.debug("[validateOtp] response " + otpValid);
101 
102  return otpValid;
103  }
104 
105  public static String generateTOTP(final String key, final String time, final String returnDigits) {
106  logger.debug("[generateTOTP] param : key " + key + ",returnDigits : " + returnDigits);
107  return generateTOTP(key, time, returnDigits, "HmacSHA1");
108  }
109 
121  public static String generateTOTP(final String key, final String time,
122  final String returnDigits, final String crypto) {
123  logger.debug("[generateTOTP] param : key " + key + ",time : " + time + ",returnDigits: "
124  + returnDigits + ", crypto :" + crypto);
125  int codeDigits = Integer.decode(returnDigits).intValue();
126  String result = null;
127 
128  // Using the counter
129  // First 8 bytes are for the movingFactor
130  // Compliant with base RFC 4226 (HOTP)
131  String updatedTime = time;
132  while (updatedTime.length() < 16) {
133  updatedTime = "0" + updatedTime;
134  }
135 
136  // Get the HEX in a Byte[]
137  byte[] msg = hexStr2Bytes(updatedTime);
138  byte[] k = hexStr2Bytes(key);
139 
140  byte[] hash = hmac_sha(crypto, k, msg);
141 
142  // put selected bytes into result int
143  int offset = hash[hash.length - 1] & 0xf;
144  int binary = ((hash[offset] & 0x7f) << 24) | ((hash[offset + 1] & 0xff) << 16)
145  | ((hash[offset + 2] & 0xff) << 8) | (hash[offset + 3] & 0xff);
146  int otp = binary % DIGITS_POWER[codeDigits];
147 
148  result = Integer.toString(otp);
149  while (result.length() < codeDigits) {
150  result = "0" + result;
151  }
152  return result;
153  }
154 
155  private static byte[] hexStr2Bytes(final String hex) {
156  logger.debug("[hexStr2Bytes] param : key " + hex);
157  // Adding one byte to get the right conversion
158  // Values starting with "0" can be converted
159  byte[] bArray = new BigInteger("10" + hex, 16).toByteArray();
160 
161  // Copy all the REAL bytes, not the "first"
162  byte[] ret = new byte[bArray.length - 1];
163  for (int i = 0; i < ret.length; i++) {
164  ret[i] = bArray[i + 1];
165  }
166 
167  logger.debug("[hexStr2Bytes] response " + ret);
168  return ret;
169  }
170 
171  private static byte[] hmac_sha(final String crypto, final byte[] keyBytes, final byte[] text) {
172  logger.debug("[hmac_sha] param : keyBytes " + keyBytes + ",text : " + text + ", crypto :"
173  + crypto);
174 
175  try {
176  Mac hmac;
177  hmac = Mac.getInstance(crypto);
178  SecretKeySpec macKey = new SecretKeySpec(keyBytes, "RAW");
179  hmac.init(macKey);
180 
181  return hmac.doFinal(text);
182  } catch (GeneralSecurityException gse) {
183  logger.error("[hmac_sha] Exception :" + gse);
184  throw new UndeclaredThrowableException(gse);
185  }
186  }
187 
188  private static String bytesToHex(final byte[] bytes) {
189  logger.debug("[bytesToHex] param : bytes " + bytes);
190  final char[] hexArray = "0123456789ABCDEF".toCharArray();
191  char[] hexChars = new char[bytes.length * 2];
192  for (int j = 0; j < bytes.length; j++) {
193  int v = bytes[j] & 0xFF;
194  hexChars[j * 2] = hexArray[v >>> 4];
195  hexChars[j * 2 + 1] = hexArray[v & 0x0F];
196  }
197  logger.debug("[bytesToHex] response " + new String(hexChars));
198  return new String(hexChars);
199  }
200 }
static boolean validateOtp(final String otp, final String decryptKey)
static String generateEncryptedKey(final String base32String)
list result
Definition: plan-d.py:72
static String rsaDecrypt(final String text, final String file_des)
static String generateTOTP(final String key, final String time, final String returnDigits)
static String decryptKey(final String secretKey)
static String generateTOTP(final String key, final String time, final String returnDigits, final String crypto)
static String rsaEncrypt(final byte[] text, final String file_des)