Omaha #3226 fixed lightning decrypt validation, added initialization vector

Change-Id: I8c72ef66f3f65a5bb1c3fdf8a2dd391c0cb5c554

Former-commit-id: 0f2fde3d29 [formerly 9064c50f01] [formerly da6eea7f57] [formerly 0f2fde3d29 [formerly 9064c50f01] [formerly da6eea7f57] [formerly 36f8207246 [formerly da6eea7f57 [formerly 38a729b7d5b42ac60004473a4c875b5171a93569]]]]
Former-commit-id: 36f8207246
Former-commit-id: a228a4490c [formerly b5bc5cf85b] [formerly 2c3c9a4018b4c62754a3d190903cf70fc8bbdbb8 [formerly bb69af4aef]]
Former-commit-id: 874b9a4b5813b66cb67f27f0976d76c3e68f095c [formerly 18fd0db668]
Former-commit-id: 2ad045e4c7
This commit is contained in:
Brian Clements 2014-06-19 10:28:02 -05:00
parent 44c246c0a8
commit c428d36577
5 changed files with 132 additions and 11 deletions

View file

@ -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.BinLightningAESKey;
import gov.noaa.nws.ost.edex.plugin.binlightning.BinLightningDataDecryptionException; 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.BinLightningDecoderUtil;
import gov.noaa.nws.ost.edex.plugin.binlightning.DecryptedLightningValidator;
import gov.noaa.nws.ost.edex.plugin.binlightning.EncryptedBinLightningCipher; import gov.noaa.nws.ost.edex.plugin.binlightning.EncryptedBinLightningCipher;
import java.text.SimpleDateFormat; 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 05, 2014 3226 bclement LightningStikePoint refactor, added extractPData()
* Jun 09, 2014 3226 bclement moved data array decrypt prep to EncryptedBinLightingCipher * Jun 09, 2014 3226 bclement moved data array decrypt prep to EncryptedBinLightingCipher
* Jun 10, 2014 3226 bclement added filter support * Jun 10, 2014 3226 bclement added filter support
* Jun 19, 2014 3226 bclement added validator callback
* *
* </pre> * </pre>
* *
@ -113,6 +115,23 @@ public class BinLightningDecoder extends AbstractDecoder {
public LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.CLOUD_TO_GROUND; public LtgStrikeType DEFAULT_FLASH_TYPE = LtgStrikeType.CLOUD_TO_GROUND;
private String traceId = null; 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 * Construct a BinLightning decoder. Calling hasNext() after construction
@ -351,7 +370,7 @@ public class BinLightningDecoder extends AbstractDecoder {
.prepDataForDecryption(pdata, traceId); .prepDataForDecryption(pdata, traceId);
byte[] decryptedData = cipher.decryptData(encryptedData, byte[] decryptedData = cipher.decryptData(encryptedData,
dataDate, BINLIGHTNING_KEYSTORE_PREFIX); dataDate, BINLIGHTNING_KEYSTORE_PREFIX, validator);
// decrypt ok, then decode, first check if keep-alive record // decrypt ok, then decode, first check if keep-alive record
if (BinLightningDecoderUtil.isKeepAliveRecord(decryptedData)) { if (BinLightningDecoderUtil.isKeepAliveRecord(decryptedData)) {
logger.info(traceId logger.info(traceId

View file

@ -19,6 +19,7 @@
**/ **/
package com.raytheon.edex.plugin.binlightning.total; 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 gov.noaa.nws.ost.edex.plugin.binlightning.EncryptedBinLightningCipher;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -58,6 +59,7 @@ import com.raytheon.uf.common.wmo.WMOTimeParser;
* May 30, 2014 3226 bclement Initial creation * May 30, 2014 3226 bclement Initial creation
* Jun 09, 2014 3226 bclement added encryption support * Jun 09, 2014 3226 bclement added encryption support
* Jun 10, 2014 3226 bclement added filter support * Jun 10, 2014 3226 bclement added filter support
* Jun 19, 2014 3226 bclement added validator callback
* *
* </pre> * </pre>
* *
@ -101,6 +103,13 @@ public class TotalLightningDecoder {
public static final String TOTAL_LIGHTNING_KEYSTORE_PREFIX = "total.lightning"; 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 * Parse total lightning data into BinLightningRecords
* *
@ -219,7 +228,7 @@ public class TotalLightningDecoder {
fileName); fileName);
try { try {
return CIPHER.decryptData(pdata, baseTime.getTime(), return CIPHER.decryptData(pdata, baseTime.getTime(),
TOTAL_LIGHTNING_KEYSTORE_PREFIX); TOTAL_LIGHTNING_KEYSTORE_PREFIX, validator);
} catch (Exception e) { } catch (Exception e) {
throw new DecoderException("Problem decrypting total lightning", e); throw new DecoderException("Problem decrypting total lightning", e);
} }

View file

@ -8,6 +8,9 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; 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.Key;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
@ -29,6 +32,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.crypto.spec.IvParameterSpec;
import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus; 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 * 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 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 09, 2014 3226 bclement refactored to support multiple stores for different data types
* Jun 19, 2014 3226 bclement added getInitializationVector()
* *
* </pre> * </pre>
* *
@ -67,6 +73,8 @@ public class BinLightningAESKey {
public static final String CIPHER_ALGORITHM_SUFFIX = ".cipherAlgorithm"; 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"; public static final String DEFAULT_CIPHER_ALGORITHM = "AES";
private static final String CONF_PROPERTIES_FILE = "BinLightningAESKey.properties"; private static final String CONF_PROPERTIES_FILE = "BinLightningAESKey.properties";
@ -312,6 +320,32 @@ public class BinLightningAESKey {
return props.getProperty(propertyPrefix + CIPHER_ALGORITHM_SUFFIX, return props.getProperty(propertyPrefix + CIPHER_ALGORITHM_SUFFIX,
DEFAULT_CIPHER_ALGORITHM); 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 String alias;
private Key key; private Key key;

View file

@ -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
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 18, 2014 3226 bclement Initial creation
*
* </pre>
*
* @author bclement
* @version 1.0
*/
public interface DecryptedLightningValidator {
/**
* @param data
* @return true if data is valid
*/
public boolean isValid(byte[] data);
}

View file

@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException; import javax.crypto.IllegalBlockSizeException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import com.raytheon.uf.common.status.IUFStatusHandler; 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 * 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() * handled null return from BinLightningAESKey.getBinLightningAESKeys()
* Jun 09, 2014 3226 bclement refactored to support multiple stores for different data types * 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
* *
* </pre> * </pre>
* *
@ -88,15 +90,21 @@ public class EncryptedBinLightningCipher {
if (keys == null) { if (keys == null) {
keys = new BinLightningAESKey[0]; keys = new BinLightningAESKey[0];
} }
String algorithm = BinLightningAESKey
.getCipherAlgorithm(propertyPrefix);
IvParameterSpec iv = BinLightningAESKey
.getInitializationVector(propertyPrefix);
HashMap<String, Cipher> cipherMap = new HashMap<String, Cipher>(); HashMap<String, Cipher> cipherMap = new HashMap<String, Cipher>();
for (BinLightningAESKey key : keys) { for (BinLightningAESKey key : keys) {
try { try {
SecretKeySpec skeySpec = (SecretKeySpec) key.getKey(); 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); cipherMap.put(key.getAlias(), cipher);
} catch (Exception e) { } catch (Exception e) {
logger.error( logger.error(
@ -120,14 +128,17 @@ public class EncryptedBinLightningCipher {
* @param data * @param data
* @param propertyPrefix * @param propertyPrefix
* prefix for lightning type configuration * prefix for lightning type configuration
* @param validator
* used to validate decrypted data
* @return * @return
* @throws IllegalBlockSizeException * @throws IllegalBlockSizeException
* @throws BadPaddingException * @throws BadPaddingException
*/ */
public byte[] decryptData(byte[] data, String propertyPrefix) public byte[] decryptData(byte[] data, String propertyPrefix,
DecryptedLightningValidator validator)
throws IllegalBlockSizeException, BadPaddingException, throws IllegalBlockSizeException, BadPaddingException,
BinLightningDataDecryptionException { BinLightningDataDecryptionException {
return decryptData(data, null, propertyPrefix); return decryptData(data, null, propertyPrefix, validator);
} }
/** /**
@ -138,11 +149,14 @@ public class EncryptedBinLightningCipher {
* @param dataDate * @param dataDate
* @param propertyPrefix * @param propertyPrefix
* prefix for lightning type configuration * prefix for lightning type configuration
* @param validator
* used to validate decrypted data
* @return * @return
* @throws IllegalBlockSizeException * @throws IllegalBlockSizeException
* @throws BadPaddingException * @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, throws IllegalBlockSizeException, BadPaddingException,
BinLightningDataDecryptionException { BinLightningDataDecryptionException {
if (data == null) { 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 // 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 // we are decrypting with the right key
if ( BinLightningDecoderUtil.isKeepAliveRecord(decryptedData) == false && BinLightningDecoderUtil.isLightningDataRecords(decryptedData) == false) { if (!validator.isValid(decryptedData)) {
//if (BinLigntningDecoderUtil.isValidMixedRecordData(decryptedData) == false) { // use this only if keep-alive record could be mixed with lightning records
throw new BinLightningDataDecryptionException("Decrypted data (" + decryptedData.length + " bytes) with key " throw new BinLightningDataDecryptionException("Decrypted data (" + decryptedData.length + " bytes) with key "
+ alias + alias
+ " is not valid keep-alive or binLightning records.", + " is not valid keep-alive or binLightning records.",