From c428d3657778e060c954d2df63dc2b7584ccec25 Mon Sep 17 00:00:00 2001 From: Brian Clements Date: Thu, 19 Jun 2014 10:28:02 -0500 Subject: [PATCH] Omaha #3226 fixed lightning decrypt validation, added initialization vector Change-Id: I8c72ef66f3f65a5bb1c3fdf8a2dd391c0cb5c554 Former-commit-id: 0f2fde3d29eb6ff3bea79cee87188f5244eb9e55 [formerly 9064c50f017c63d262ba7fe5f3e6a996ec1f8cd7] [formerly da6eea7f57919b94e22bbb609c65f761b54acdb5] [formerly 0f2fde3d29eb6ff3bea79cee87188f5244eb9e55 [formerly 9064c50f017c63d262ba7fe5f3e6a996ec1f8cd7] [formerly da6eea7f57919b94e22bbb609c65f761b54acdb5] [formerly 36f8207246c297e749a9e093463d351f82b43f48 [formerly da6eea7f57919b94e22bbb609c65f761b54acdb5 [formerly 38a729b7d5b42ac60004473a4c875b5171a93569]]]] Former-commit-id: 36f8207246c297e749a9e093463d351f82b43f48 Former-commit-id: a228a4490c3668df16ab07a067f8caaf7f425ec8 [formerly b5bc5cf85b6fccaad9c1509e88bfa54d0ec96104] [formerly 2c3c9a4018b4c62754a3d190903cf70fc8bbdbb8 [formerly bb69af4aef3a7f9fcc5468e4b5aa889e9eeb602d]] Former-commit-id: 874b9a4b5813b66cb67f27f0976d76c3e68f095c [formerly 18fd0db668e8d61412345bdc6115f7b5b77b630d] Former-commit-id: 2ad045e4c7370e62172235c784e8158861f5bf51 --- .../binlightning/BinLightningDecoder.java | 21 ++++++++- .../total/TotalLightningDecoder.java | 11 ++++- .../binlightning/BinLightningAESKey.java | 34 ++++++++++++++ .../DecryptedLightningValidator.java | 46 +++++++++++++++++++ .../EncryptedBinLightningCipher.java | 31 +++++++++---- 5 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/DecryptedLightningValidator.java diff --git a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java index 7785b49f62..ba9cf6ef9a 100644 --- a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java +++ b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/BinLightningDecoder.java @@ -22,6 +22,7 @@ package com.raytheon.edex.plugin.binlightning; import gov.noaa.nws.ost.edex.plugin.binlightning.BinLightningAESKey; import gov.noaa.nws.ost.edex.plugin.binlightning.BinLightningDataDecryptionException; import gov.noaa.nws.ost.edex.plugin.binlightning.BinLightningDecoderUtil; +import gov.noaa.nws.ost.edex.plugin.binlightning.DecryptedLightningValidator; import gov.noaa.nws.ost.edex.plugin.binlightning.EncryptedBinLightningCipher; import java.text.SimpleDateFormat; @@ -88,6 +89,7 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource; * Jun 05, 2014 3226 bclement LightningStikePoint refactor, added extractPData() * Jun 09, 2014 3226 bclement moved data array decrypt prep to EncryptedBinLightingCipher * Jun 10, 2014 3226 bclement added filter support + * Jun 19, 2014 3226 bclement added validator callback * * * @@ -113,6 +115,23 @@ public class BinLightningDecoder extends AbstractDecoder { public LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.CLOUD_TO_GROUND; private String traceId = null; + + /** + * callback for validating decryption results + */ + private static DecryptedLightningValidator validator = new DecryptedLightningValidator() { + @Override + public boolean isValid(byte[] decryptedData) { + return BinLightningDecoderUtil.isKeepAliveRecord(decryptedData) == false + && BinLightningDecoderUtil + .isLightningDataRecords(decryptedData) == false; + /* + * use this if keep-alive record could be mixed with lightning + * records + */ + // return BinLigntningDecoderUtil.isValidMixedRecordData(decryptedData) == false + } + }; /** * Construct a BinLightning decoder. Calling hasNext() after construction @@ -351,7 +370,7 @@ public class BinLightningDecoder extends AbstractDecoder { .prepDataForDecryption(pdata, traceId); byte[] decryptedData = cipher.decryptData(encryptedData, - dataDate, BINLIGHTNING_KEYSTORE_PREFIX); + dataDate, BINLIGHTNING_KEYSTORE_PREFIX, validator); // decrypt ok, then decode, first check if keep-alive record if (BinLightningDecoderUtil.isKeepAliveRecord(decryptedData)) { logger.info(traceId diff --git a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java index 2207fd60aa..b89c47d527 100644 --- a/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java +++ b/edexOsgi/com.raytheon.edex.plugin.binlightning/src/com/raytheon/edex/plugin/binlightning/total/TotalLightningDecoder.java @@ -19,6 +19,7 @@ **/ package com.raytheon.edex.plugin.binlightning.total; +import gov.noaa.nws.ost.edex.plugin.binlightning.DecryptedLightningValidator; import gov.noaa.nws.ost.edex.plugin.binlightning.EncryptedBinLightningCipher; import java.nio.ByteBuffer; @@ -58,6 +59,7 @@ import com.raytheon.uf.common.wmo.WMOTimeParser; * May 30, 2014 3226 bclement Initial creation * Jun 09, 2014 3226 bclement added encryption support * Jun 10, 2014 3226 bclement added filter support + * Jun 19, 2014 3226 bclement added validator callback * * * @@ -101,6 +103,13 @@ public class TotalLightningDecoder { public static final String TOTAL_LIGHTNING_KEYSTORE_PREFIX = "total.lightning"; + private static final DecryptedLightningValidator validator = new DecryptedLightningValidator() { + @Override + public boolean isValid(byte[] data) { + return validFlashPacket(data, COMBINATION_PACKET_HEADER_SIZE); + } + }; + /** * Parse total lightning data into BinLightningRecords * @@ -219,7 +228,7 @@ public class TotalLightningDecoder { fileName); try { return CIPHER.decryptData(pdata, baseTime.getTime(), - TOTAL_LIGHTNING_KEYSTORE_PREFIX); + TOTAL_LIGHTNING_KEYSTORE_PREFIX, validator); } catch (Exception e) { throw new DecoderException("Problem decrypting total lightning", e); } diff --git a/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/BinLightningAESKey.java b/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/BinLightningAESKey.java index 7bab813cb4..84cec6f724 100755 --- a/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/BinLightningAESKey.java +++ b/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/BinLightningAESKey.java @@ -8,6 +8,9 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.Key; import java.security.KeyStore; import java.security.KeyStoreException; @@ -29,6 +32,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; +import javax.crypto.spec.IvParameterSpec; + import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; @@ -47,6 +52,7 @@ import com.raytheon.uf.common.status.UFStatus; * 20130503 DCS 112 Wufeng Zhou To handle both the new encrypted data and legacy bit-shifted data * Jun 03, 2014 3226 bclement moved from com.raytheon.edex.plugin.binlightning to gov.noaa.nws.ost.edex.plugin.binlightning * Jun 09, 2014 3226 bclement refactored to support multiple stores for different data types + * Jun 19, 2014 3226 bclement added getInitializationVector() * * * @@ -67,6 +73,8 @@ public class BinLightningAESKey { public static final String CIPHER_ALGORITHM_SUFFIX = ".cipherAlgorithm"; + public static final String CIPHER_INITIALIZATION_VECTOR_SUFFIX = ".initializationVectorFile"; + public static final String DEFAULT_CIPHER_ALGORITHM = "AES"; private static final String CONF_PROPERTIES_FILE = "BinLightningAESKey.properties"; @@ -312,6 +320,32 @@ public class BinLightningAESKey { return props.getProperty(propertyPrefix + CIPHER_ALGORITHM_SUFFIX, DEFAULT_CIPHER_ALGORITHM); } + + /** + * Create a Cipher initialization vector parameter spec for data type + * + * @param propertyPrefix + * prefix for properties associated with a particular lightning + * data type + * @return null if not found or error occurred + */ + public static IvParameterSpec getInitializationVector(String propertyPrefix) { + IvParameterSpec rval = null; + String ivFileName = props.getProperty(propertyPrefix + + CIPHER_INITIALIZATION_VECTOR_SUFFIX); + if (ivFileName != null) { + Path ivPath = Paths.get(ivFileName); + try { + byte[] ivData = Files.readAllBytes(ivPath); + rval = new IvParameterSpec(ivData); + } catch (IOException e) { + logger.error( + "Unable to create initialization vector for type: " + + propertyPrefix, e); + } + } + return rval; + } private String alias; private Key key; diff --git a/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/DecryptedLightningValidator.java b/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/DecryptedLightningValidator.java new file mode 100644 index 0000000000..4cc1273e18 --- /dev/null +++ b/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/DecryptedLightningValidator.java @@ -0,0 +1,46 @@ +/** + * This software was developed and / or modified by Raytheon Company, + * pursuant to Contract DG133W-05-CQ-1067 with the US Government. + * + * U.S. EXPORT CONTROLLED TECHNICAL DATA + * This software product contains export-restricted data whose + * export/transfer/disclosure is restricted by U.S. law. Dissemination + * to non-U.S. persons whether in the United States or abroad requires + * an export license or other authorization. + * + * Contractor Name: Raytheon Company + * Contractor Address: 6825 Pine Street, Suite 340 + * Mail Stop B8 + * Omaha, NE 68106 + * 402.291.0100 + * + * See the AWIPS II Master Rights File ("Master Rights File.pdf") for + * further licensing information. + **/ +package gov.noaa.nws.ost.edex.plugin.binlightning; + +/** + * Callback to validate results of lightning data decryption + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 18, 2014 3226       bclement     Initial creation
+ * 
+ * 
+ * + * @author bclement + * @version 1.0 + */ +public interface DecryptedLightningValidator { + + /** + * @param data + * @return true if data is valid + */ + public boolean isValid(byte[] data); + +} diff --git a/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/EncryptedBinLightningCipher.java b/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/EncryptedBinLightningCipher.java index 04fc756759..c20185f26e 100755 --- a/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/EncryptedBinLightningCipher.java +++ b/ost/gov.noaa.nws.ost.edex.plugin.binlightning/src/gov/noaa/nws/ost/edex/plugin/binlightning/EncryptedBinLightningCipher.java @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import com.raytheon.uf.common.status.IUFStatusHandler; @@ -37,6 +38,7 @@ import com.raytheon.uf.common.status.UFStatus; * Jun 03, 2014 3226 bclement moved from com.raytheon.edex.plugin.binlightning to gov.noaa.nws.ost.edex.plugin.binlightning * handled null return from BinLightningAESKey.getBinLightningAESKeys() * Jun 09, 2014 3226 bclement refactored to support multiple stores for different data types + * Jun 19, 2014 3226 bclement added validator callback, added initialization vector support * * * @@ -88,15 +90,21 @@ public class EncryptedBinLightningCipher { if (keys == null) { keys = new BinLightningAESKey[0]; } + String algorithm = BinLightningAESKey + .getCipherAlgorithm(propertyPrefix); + IvParameterSpec iv = BinLightningAESKey + .getInitializationVector(propertyPrefix); HashMap cipherMap = new HashMap(); for (BinLightningAESKey key : keys) { try { SecretKeySpec skeySpec = (SecretKeySpec) key.getKey(); - String algorithm = BinLightningAESKey - .getCipherAlgorithm(propertyPrefix); - Cipher cipher = Cipher.getInstance(algorithm); - cipher.init(Cipher.DECRYPT_MODE, skeySpec); + Cipher cipher = Cipher.getInstance(algorithm); + if (iv != null) { + cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); + } else { + cipher.init(Cipher.DECRYPT_MODE, skeySpec); + } cipherMap.put(key.getAlias(), cipher); } catch (Exception e) { logger.error( @@ -120,14 +128,17 @@ public class EncryptedBinLightningCipher { * @param data * @param propertyPrefix * prefix for lightning type configuration + * @param validator + * used to validate decrypted data * @return * @throws IllegalBlockSizeException * @throws BadPaddingException */ - public byte[] decryptData(byte[] data, String propertyPrefix) + public byte[] decryptData(byte[] data, String propertyPrefix, + DecryptedLightningValidator validator) throws IllegalBlockSizeException, BadPaddingException, BinLightningDataDecryptionException { - return decryptData(data, null, propertyPrefix); + return decryptData(data, null, propertyPrefix, validator); } /** @@ -138,11 +149,14 @@ public class EncryptedBinLightningCipher { * @param dataDate * @param propertyPrefix * prefix for lightning type configuration + * @param validator + * used to validate decrypted data * @return * @throws IllegalBlockSizeException * @throws BadPaddingException */ - public byte[] decryptData(byte[] data, Date dataDate, String propertyPrefix) + public byte[] decryptData(byte[] data, Date dataDate, + String propertyPrefix, DecryptedLightningValidator validator) throws IllegalBlockSizeException, BadPaddingException, BinLightningDataDecryptionException { if (data == null) { @@ -179,8 +193,7 @@ public class EncryptedBinLightningCipher { // wrong key will decrypt data into random noise/garbage, so we need to do a sanity check to make sure // we are decrypting with the right key - if ( BinLightningDecoderUtil.isKeepAliveRecord(decryptedData) == false && BinLightningDecoderUtil.isLightningDataRecords(decryptedData) == false) { - //if (BinLigntningDecoderUtil.isValidMixedRecordData(decryptedData) == false) { // use this only if keep-alive record could be mixed with lightning records + if (!validator.isValid(decryptedData)) { throw new BinLightningDataDecryptionException("Decrypted data (" + decryptedData.length + " bytes) with key " + alias + " is not valid keep-alive or binLightning records.",