Java tutorial
/** * @file Utils.java * @brief misc collection of static utilities * @author Doug Anson * @version 1.0 * @see * * Copyright 2015. ARM Ltd. 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. * */ package com.arm.connector.bridge.core; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.nio.ByteBuffer; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.TimeZone; import javax.servlet.ServletContext; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; /** * Static support utilities * @author Doug Anson */ public class Utils { // static variables private static char[] hexArray = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; private static String __cache_hash = null; private static String _externalIPAddress = null; // get local timezone offset from UTC in milliseconds public static int getUTCOffset() { TimeZone tz = TimeZone.getDefault(); Calendar cal = GregorianCalendar.getInstance(tz); return tz.getOffset(cal.getTimeInMillis()); } // get the local time in seconds since Jan 1 1970 public static int getLocalTime() { int utc = (int) (System.currentTimeMillis() / 1000); int localtime = utc; return localtime; } // get UTC time in seconds since Jan 1 1970 public static long getUTCTime() { return Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTimeInMillis() - Utils.getUTCOffset(); } // get our base URL public static String getBaseURL(String endpoint, HttpServletRequest request) { String url = ""; try { url = request.getRequestURL().toString().replace(request.getRequestURI().substring(1), request.getContextPath()); url += "//" + endpoint; url = url.replace("://", "_TEMP_"); url = url.replace("//", "/"); url = url.replace("_TEMP_", "://"); } catch (Exception ex) { url = request.getRequestURL().toString(); } return url; } // convert boolean to string public static String booleanToString(boolean val) { if (val) { return "true"; } return "false"; } // convert string to boolean public static boolean stringToBoolean(String val) { boolean bval = false; if (val != null && val.equalsIgnoreCase("true")) { bval = true; } return bval; } // START DATE FUNCTIONS // get the current date and time public static java.util.Date now() { java.util.Date rightnow = new java.util.Date(System.currentTimeMillis()); return rightnow; } // convert a JAVA Date to a SQL Timestamp and back public static java.sql.Timestamp convertDate(java.util.Date date) { java.sql.Timestamp sql_date = new java.sql.Timestamp(date.getTime()); sql_date.setTime(date.getTime()); return sql_date; } // convert SQL Date to Java Date public static java.util.Date convertDate(java.sql.Timestamp date) { java.util.Date java_date = new java.util.Date(date.getTime()); return java_date; } // convert a Date to a String (java) public static String dateToString(java.util.Date date) { return Utils.dateToString(date, "MM/dd/yyyy HH:mm:ss"); } // Date to Date String public static String dateToString(java.util.Date date, String format) { if (date != null) { DateFormat df = new SimpleDateFormat(format); return df.format(date); } else { return "[no date]"; } } // convert a SQL Timestamp to a String (SQL) public static String dateToString(java.sql.Timestamp timestamp) { if (timestamp != null) { return Utils.dateToString(new java.util.Date(timestamp.getTime())); } else { return "[no date]"; } } // convert a Date to a String (SQL) public static String dateToString(java.sql.Date date) { if (date != null) { return Utils.dateToString(new java.util.Date(date.getTime())); } else { return "[no date]"; } } // convert a String (Java) to a java.util.Date object public static java.util.Date stringToDate(ErrorLogger err, String str_date) { try { SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); String stripped = str_date.replace('"', ' ').trim(); return dateFormat.parse(stripped); } catch (ParseException ex) { err.warning("Unable to parse string date: " + str_date + " to format: \"MM/dd/yyyy HH:mm:ss\"", ex); } return null; } // END DATE FUNCTIONS // Hex String to ByteBuffer or byte[] public static ByteBuffer hexStringToByteBuffer(String str) { return ByteBuffer.wrap(Utils.hexStringToByteArray(str)); } // hex String to ByteArray public static byte[] hexStringToByteArray(String str) { int len = str.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(str.charAt(i), 16) << 4) + Character.digit(str.charAt(i + 1), 16)); } return data; } // convert a hex byte array to a string public static String bytesToHexString(ByteBuffer bytes) { return Utils.bytesToHexString(bytes.array()); } // ByteArray to hex string public static String bytesToHexString(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; for (int j = 0; j < bytes.length; ++j) { int v = bytes[j] & 0xFF; hexChars[j * 2] = hexArray[v >>> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } return new String(hexChars); } // read in a HTML file public static String readHTMLFileIntoString(HttpServlet svc, ErrorLogger err, String filename) { try { String text = null; String file = ""; ServletContext context = svc.getServletContext(); try (InputStream is = context.getResourceAsStream("/" + filename); InputStreamReader isr = new InputStreamReader(is); BufferedReader reader = new BufferedReader(isr)) { while ((text = reader.readLine()) != null) { file += text; } } return file; } catch (IOException ex) { err.critical("error while trying to read HTML template: " + filename, ex); } return null; } // decode CoAP payload Base64 public static String decodeCoAPPayload(String payload) { String decoded = null; try { String b64_payload = payload.replace("\\u003d", "="); Base64 decoder = new Base64(); byte[] data = decoder.decode(b64_payload); decoded = new String(data); } catch (Exception ex) { decoded = "<unk>"; } return decoded; } // create a URL-safe Token public static String createURLSafeToken(String seed) { try { byte[] b64 = Base64.encodeBase64(seed.getBytes()); return new String(b64); } catch (Exception ex) { return "exception"; } } // create Authentication Hash public static String createHash(String data) { try { if (data == null) { return "none"; } MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] digest = md.digest(data.getBytes()); String hex = Hex.encodeHexString(digest); return Base64.encodeBase64URLSafeString(hex.getBytes()); } catch (NoSuchAlgorithmException ex) { return "none"; } } // validate the Authentication Hash public static boolean validateHash(String header_hash, String calc_hash) { boolean validated = false; try { if (Utils.__cache_hash == null) { validated = (header_hash != null && calc_hash != null && calc_hash.equalsIgnoreCase(header_hash) == true); if (validated && Utils.__cache_hash == null) { Utils.__cache_hash = header_hash; } } else { validated = (header_hash != null && Utils.__cache_hash != null && Utils.__cache_hash.equalsIgnoreCase(header_hash) == true); } return validated; } catch (Exception ex) { return false; } } // get our external IP Address public static String getExternalIPAddress() { if (Utils._externalIPAddress == null) { BufferedReader in = null; try { URL whatismyip = new URL("http://checkip.amazonaws.com"); in = new BufferedReader(new InputStreamReader(whatismyip.openStream())); Utils._externalIPAddress = in.readLine(); in.close(); } catch (Exception ex) { try { if (in != null) in.close(); } catch (Exception ex2) { // silent } } } return Utils._externalIPAddress; } // convert a InputStream to a String public static String convertStreamToString(java.io.InputStream is) { java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } /** * Execute the AWS CLI * @param logger - ErrorLogger instance * @param args - arguments for the AWS CLI * @return response from CLI action */ public static String awsCLI(ErrorLogger logger, String args) { // construct the arguments String cmd = "./aws " + args; String response = null; String error = null; try { // invoke the AWS CLI Process proc = Runtime.getRuntime().exec(cmd); response = Utils.convertStreamToString(proc.getInputStream()); error = Utils.convertStreamToString(proc.getErrorStream()); // wait to completion proc.waitFor(); int status = proc.exitValue(); // DEBUG if (status != 0) { // non-zero exit status logger.warning("AWS CLI: Invoked: " + cmd); logger.warning("AWS CLI: Response: " + response); logger.warning("AWS CLI: Errors: " + error); logger.warning("AWS CLI: Exit Code: " + status); } else { // successful exit status logger.info("AWS CLI: Invoked: " + cmd); logger.info("AWS CLI: Response: " + response); logger.info("AWS CLI: Exit Code: " + status); } } catch (IOException | InterruptedException ex) { logger.warning("AWS CLI: Exception for command: " + cmd, ex); response = null; } // return the resposne return response; } // escape chars utility public static String escapeChars(String str) { return str.replace("\\n", ""); } // Create CA Root certificate public static X509Certificate createCACertificate(ErrorLogger logger) { // Root CA for AWS IoT (5/6/2016) // https://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem String pem = "-----BEGIN CERTIFICATE-----" + "MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB" + "yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL" + "ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp" + "U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW" + "ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0" + "aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL" + "MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW" + "ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln" + "biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp" + "U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y" + "aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1" + "nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex" + "t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz" + "SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG" + "BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+" + "rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/" + "NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E" + "BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH" + "BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy" + "aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv" + "MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE" + "p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y" + "5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK" + "WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ" + "4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N" + "hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq" + "-----END CERTIFICATE-----"; return Utils.createX509CertificateFromPEM(logger, pem, "X509"); } // create a Keystore public static String createKeystore(ErrorLogger logger, String base, String sep, String filename, X509Certificate cert, PrivateKey priv_key, String pw) { String basedir = base + File.separator + sep; String keystore_filename = basedir + File.separator + filename; try { // first create the directory if it does not exist File file = new File(basedir); // make the directories logger.info("createKeystore: Making directories for keystore..."); file.mkdirs(); // create the KeyStore logger.info("createKeystore: Creating keystore: " + keystore_filename); file = new File(keystore_filename); if (file.createNewFile()) { logger.info("createKeystore: keystore created: " + keystore_filename); } else { logger.warning("createKeystore: keystore already exists " + keystore_filename); } // store data into the keystore KeyStore ks = KeyStore.getInstance("JKS"); ks.load(null, pw.toCharArray()); // set the certificate, priv and pub keys if (cert != null) { Certificate[] cert_list = new Certificate[2]; cert_list[0] = cert; cert_list[1] = Utils.createCACertificate(logger); ks.setCertificateEntry("aws", cert_list[0]); ks.setCertificateEntry("verisign", cert_list[1]); if (priv_key != null) { try { ks.setKeyEntry("privkey", priv_key, pw.toCharArray(), cert_list); } catch (Exception ex2) { logger.warning("createKeystore: Exception during priv addition... not added to keystore", ex2); } } else { logger.warning("createKeystore: privkey is NULL... not added to keystore"); } } else { logger.warning("createKeystore: certificate is NULL... not added to keystore"); } try (FileOutputStream fos = new FileOutputStream(keystore_filename)) { // store away the keystore content ks.store(fos, pw.toCharArray()); // close fos.flush(); } } catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException ex) { logger.warning("createKeystore: Unable to create keystore: " + keystore_filename, ex); } // return the keystore filename return keystore_filename; } // generate a keystore password public static String generateKeystorePassword(String base_pw, String salt) { // XXX TO DO return base_pw; } // remove the keystore from the filesystem public static void deleteKeystore(ErrorLogger logger, String filename, String keystore_name) { try { // DEBUG logger.info("deleteKeystore: deleting keystore: " + filename); // Delete the KeyStore File file = new File(filename); if (file.delete()) { // success logger.info(file.getName() + " is deleted!"); } else { // failure logger.warning("Delete operation is failed: " + filename); } // Create the parent directory String basedir = filename.replace("/" + keystore_name, ""); // DEBUG logger.info("deleteKeystore: deleting keystore parent directory: " + basedir); // Delete the Base Directory file = new File(basedir); if (file.isDirectory()) { if (file.delete()) { // success logger.info(basedir + " is deleted!"); } else { // failure logger.warning("Delete operation is failed : " + basedir); } } } catch (Exception ex) { // exception caught logger.warning("deleteKeystore: Exception during deletion of keystore: " + filename, ex); } } // Create X509Certificate from PEM static public X509Certificate createX509CertificateFromPEM(ErrorLogger logger, String pem, String cert_type) { try { String temp = Utils.escapeChars(pem); String certPEM = temp.replace("-----BEGIN CERTIFICATE-----", ""); certPEM = certPEM.replace("-----END CERTIFICATE-----", ""); // DEBUG //logger.info("createX509CertificateFromPEM: " + certPEM); Base64 b64 = new Base64(); byte[] decoded = b64.decode(certPEM); CertificateFactory cf = CertificateFactory.getInstance(cert_type); return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(decoded)); } catch (Exception ex) { // exception caught logger.warning("createX509CertificateFromPEM: Exception during private key gen", ex); } return null; } // Create PrivateKey from PEM static public PrivateKey createPrivateKeyFromPEM(ErrorLogger logger, String pem, String algorithm) { try { String temp = Utils.escapeChars(pem); String privKeyPEM = temp.replace("-----BEGIN RSA PRIVATE KEY-----", ""); privKeyPEM = privKeyPEM.replace("-----END RSA PRIVATE KEY-----", ""); // DEBUG //logger.info("createPrivateKeyFromPEM: " + privKeyPEM); Base64 b64 = new Base64(); byte[] decoded = b64.decode(privKeyPEM); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance(algorithm); return kf.generatePrivate(spec); } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) { // exception caught logger.warning("createPrivateKeyFromPEM: Exception during private key gen", ex); } return null; } // Create PublicKey from PEM static public PublicKey createPublicKeyFromPEM(ErrorLogger logger, String pem, String algorithm) { try { String temp = Utils.escapeChars(pem); String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----", ""); publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", ""); // DEBUG //logger.info("createPublicKeyFromPEM: " + publicKeyPEM); Base64 b64 = new Base64(); byte[] decoded = b64.decode(publicKeyPEM); X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance(algorithm); return kf.generatePublic(spec); } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) { // exception caught logger.warning("createPublicKeyFromPEM: Exception during public key gen", ex); } return null; } }