Omaha #3226 moved ost lightning code to new plugin
fixed NPE when missing encryption config Change-Id: I8ef6004f44b686918220e7729a499e456787a834 Former-commit-id: 5421b666fc52e849e4ad5b39e2328a5c90a42408
This commit is contained in:
parent
e5ffd0f40c
commit
664d9282c3
14 changed files with 399 additions and 220 deletions
|
@ -1,7 +1,11 @@
|
||||||
#Thu Mar 26 10:16:39 CDT 2009
|
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
org.eclipse.jdt.core.compiler.source=1.6
|
org.eclipse.jdt.core.compiler.source=1.7
|
||||||
|
|
|
@ -2,14 +2,16 @@ Manifest-Version: 1.0
|
||||||
Bundle-ManifestVersion: 2
|
Bundle-ManifestVersion: 2
|
||||||
Bundle-Name: Binlightning Plug-in
|
Bundle-Name: Binlightning Plug-in
|
||||||
Bundle-SymbolicName: com.raytheon.edex.plugin.binlightning
|
Bundle-SymbolicName: com.raytheon.edex.plugin.binlightning
|
||||||
Bundle-Version: 1.12.1174.qualifier
|
Bundle-Version: 1.14.0.qualifier
|
||||||
Bundle-Vendor: RAYTHEON
|
Bundle-Vendor: RAYTHEON
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||||
Export-Package: com.raytheon.edex.plugin.binlightning.dao
|
Export-Package: com.raytheon.edex.plugin.binlightning.dao
|
||||||
Import-Package: com.raytheon.edex.esb,
|
Import-Package: com.raytheon.edex.esb,
|
||||||
com.raytheon.edex.exception,
|
com.raytheon.edex.exception,
|
||||||
com.raytheon.edex.plugin,
|
com.raytheon.edex.plugin,
|
||||||
|
com.raytheon.uf.common.status,
|
||||||
com.raytheon.uf.common.wmo,
|
com.raytheon.uf.common.wmo,
|
||||||
|
gov.noaa.nws.ost.edex.plugin.binlightning,
|
||||||
org.apache.commons.logging
|
org.apache.commons.logging
|
||||||
Require-Bundle: com.raytheon.uf.common.dataplugin.binlightning;bundle-version="1.12.1174",
|
Require-Bundle: com.raytheon.uf.common.dataplugin.binlightning;bundle-version="1.12.1174",
|
||||||
com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174",
|
com.raytheon.uf.common.dataplugin;bundle-version="1.12.1174",
|
||||||
|
|
|
@ -19,30 +19,41 @@
|
||||||
**/
|
**/
|
||||||
package com.raytheon.edex.plugin.binlightning;
|
package com.raytheon.edex.plugin.binlightning;
|
||||||
|
|
||||||
import gov.noaa.nws.ost.edex.plugin.binlightning.BinLigntningDecoderUtil;
|
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.EncryptedBinLightningCipher;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import javax.crypto.BadPaddingException;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
|
|
||||||
import com.raytheon.edex.esb.Headers;
|
import com.raytheon.edex.esb.Headers;
|
||||||
import com.raytheon.edex.exception.DecoderException;
|
import com.raytheon.edex.exception.DecoderException;
|
||||||
import com.raytheon.edex.plugin.AbstractDecoder;
|
import com.raytheon.edex.plugin.AbstractDecoder;
|
||||||
|
import com.raytheon.edex.plugin.binlightning.impl.BinLightningFactory;
|
||||||
|
import com.raytheon.edex.plugin.binlightning.impl.IBinLightningDecoder;
|
||||||
|
import com.raytheon.edex.plugin.binlightning.impl.LightningDataSource;
|
||||||
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
import com.raytheon.uf.common.dataplugin.PluginDataObject;
|
||||||
import com.raytheon.uf.common.dataplugin.PluginException;
|
|
||||||
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
|
import com.raytheon.uf.common.dataplugin.binlightning.BinLightningRecord;
|
||||||
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
|
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
|
||||||
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
|
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
|
||||||
|
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||||
|
import com.raytheon.uf.common.status.UFStatus;
|
||||||
import com.raytheon.uf.common.time.DataTime;
|
import com.raytheon.uf.common.time.DataTime;
|
||||||
import com.raytheon.uf.common.time.TimeRange;
|
import com.raytheon.uf.common.time.TimeRange;
|
||||||
|
import com.raytheon.uf.common.time.util.TimeUtil;
|
||||||
import com.raytheon.uf.common.wmo.WMOHeader;
|
import com.raytheon.uf.common.wmo.WMOHeader;
|
||||||
import com.raytheon.uf.common.wmo.WMOTimeParser;
|
import com.raytheon.uf.common.wmo.WMOTimeParser;
|
||||||
import com.raytheon.uf.edex.decodertools.core.DecoderTools;
|
import com.raytheon.uf.edex.decodertools.core.DecoderTools;
|
||||||
import com.raytheon.uf.edex.decodertools.time.TimeTools;
|
import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AWIPS decoder adapter strategy for binary lightning data.<br/>
|
* AWIPS decoder adapter strategy for binary lightning data.<br/>
|
||||||
|
@ -84,6 +95,9 @@ import com.raytheon.uf.edex.decodertools.time.TimeTools;
|
||||||
* and to used WMO header to distinguish bit-shifted
|
* and to used WMO header to distinguish bit-shifted
|
||||||
* GLD360 and NLDN data.
|
* GLD360 and NLDN data.
|
||||||
* May 14, 2014 2536 bclement moved WMO Header to common
|
* May 14, 2014 2536 bclement moved WMO Header to common
|
||||||
|
* Jun 03, 2014 3226 bclement removed unused WMO patterns, switched to UFStatus
|
||||||
|
* removed TimeTools usage, removed constructDataURI() call
|
||||||
|
* added decodeBinLightningData() and decodeBitShiftedBinLightningData() from BinLightningDecoderUtil
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -91,16 +105,14 @@ import com.raytheon.uf.edex.decodertools.time.TimeTools;
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
public class BinLightningDecoder extends AbstractDecoder {
|
public class BinLightningDecoder extends AbstractDecoder {
|
||||||
private static final String SFUS_PATTERN = "SFUS41 KWBC \\d{6}[^\\r\\n]*[\\r\\n]+";
|
|
||||||
|
|
||||||
private static final String SFPA_PATTERN = "SFPA41 KWBC \\d{6}[^\\r\\n]*[\\r\\n]+";
|
|
||||||
|
|
||||||
// Allow ingest up to 10 minutes into the future.
|
// Allow ingest up to 10 minutes into the future.
|
||||||
private static final long TEN_MINUTES = 10 * 60 * 1000L;
|
private static final long TEN_MINUTES = 10 * 60 * 1000L;
|
||||||
|
|
||||||
private final SimpleDateFormat SDF;
|
private final SimpleDateFormat SDF;
|
||||||
|
|
||||||
private final Log logger = LogFactory.getLog(getClass());
|
private static final IUFStatusHandler logger = UFStatus
|
||||||
|
.getHandler(BinLightningDecoder.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default lightning strike type for FLASH messages. RT_FLASH documents
|
* Default lightning strike type for FLASH messages. RT_FLASH documents
|
||||||
|
@ -166,7 +178,8 @@ public class BinLightningDecoder extends AbstractDecoder {
|
||||||
// both encrypted data and legacy data
|
// both encrypted data and legacy data
|
||||||
//
|
//
|
||||||
|
|
||||||
List<LightningStrikePoint> strikes = BinLigntningDecoderUtil.decodeBinLightningData(data, pdata, traceId, wmoHdr, baseTime.getTime());
|
List<LightningStrikePoint> strikes = decodeBinLightningData(
|
||||||
|
data, pdata, traceId, wmoHdr, baseTime.getTime());
|
||||||
|
|
||||||
if (strikes == null) { // keep-alive record, log and return
|
if (strikes == null) { // keep-alive record, log and return
|
||||||
logger.info(traceId + " - found keep-alive record. ignore for now.");
|
logger.info(traceId + " - found keep-alive record. ignore for now.");
|
||||||
|
@ -189,7 +202,7 @@ public class BinLightningDecoder extends AbstractDecoder {
|
||||||
return new PluginDataObject[0];
|
return new PluginDataObject[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
Calendar c = TimeTools.copy(baseTime);
|
Calendar c = TimeUtil.newCalendar(baseTime);
|
||||||
if (c == null) {
|
if (c == null) {
|
||||||
throw new DecoderException(traceId + " - Error decoding times");
|
throw new DecoderException(traceId + " - Error decoding times");
|
||||||
}
|
}
|
||||||
|
@ -212,14 +225,7 @@ public class BinLightningDecoder extends AbstractDecoder {
|
||||||
|
|
||||||
if (report != null) {
|
if (report != null) {
|
||||||
report.setTraceId(traceId);
|
report.setTraceId(traceId);
|
||||||
//report.setPluginName("binlightning"); // line disappear in OB15.5.3
|
reports = new PluginDataObject[] { report };
|
||||||
try {
|
|
||||||
report.constructDataURI();
|
|
||||||
reports = new PluginDataObject[] { report };
|
|
||||||
} catch (PluginException e) {
|
|
||||||
logger.error("Error constructing datauri", e);
|
|
||||||
throw new DecoderException("Error constructing datauri", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -229,6 +235,261 @@ public class BinLightningDecoder extends AbstractDecoder {
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decode bin lightning data, able to handle both legacy bit-shifted and new
|
||||||
|
* encryted data
|
||||||
|
*
|
||||||
|
* The BinLightningDecoder.decode() method will use this method to decode
|
||||||
|
* data, which will try to decrypt first, and decode the old fashioned way
|
||||||
|
* when decryption fails
|
||||||
|
*
|
||||||
|
* @author Wufeng Zhou
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* - data content from file, including WMO header section
|
||||||
|
* @param pdata
|
||||||
|
* - data with WMO header stripped, optional, if null, will strip
|
||||||
|
* WMO header internally from passed in data parameter
|
||||||
|
* @param traceId
|
||||||
|
* - the file name of the data to be deoced
|
||||||
|
* @param wmoHdr
|
||||||
|
* - WMOHeader, added 12/24/2013 to help distinguish bit-shifted
|
||||||
|
* NLDN and GLD360 data (GLD data will have header starts like
|
||||||
|
* SFPA)
|
||||||
|
* @param dataDate
|
||||||
|
* - date of the data, optional, used as a hint to find
|
||||||
|
* appropriate encryption key faster
|
||||||
|
* @return null if keep-alive record, otherwise a list (could be empty) of
|
||||||
|
* LightningStrikePoint
|
||||||
|
*/
|
||||||
|
public static List<LightningStrikePoint> decodeBinLightningData(
|
||||||
|
byte[] data, byte[] pdata, String traceId, WMOHeader wmoHdr,
|
||||||
|
Date dataDate) {
|
||||||
|
if (pdata == null) { // if data without header not passed, we'll strip
|
||||||
|
// the WMO header here
|
||||||
|
WMOHeader header = new WMOHeader(data);
|
||||||
|
if (header.isValid() && header.getMessageDataStart() > 0) {
|
||||||
|
pdata = new byte[data.length - header.getMessageDataStart()];
|
||||||
|
System.arraycopy(data, header.getMessageDataStart(), pdata, 0,
|
||||||
|
data.length - header.getMessageDataStart());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<LightningStrikePoint> strikes = new ArrayList<LightningStrikePoint>();
|
||||||
|
boolean needDecrypt = true; // set as default unless clear evidence says
|
||||||
|
// otherwise
|
||||||
|
boolean decodeDone = false;
|
||||||
|
EncryptedBinLightningCipher cipher = new EncryptedBinLightningCipher();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Using different WMO headers to indicate whether the data is encrypted
|
||||||
|
// or not would be a nice option.
|
||||||
|
// However, that idea has been discussed but not adopted.
|
||||||
|
// If in the future, WMO header can be different for legacy and
|
||||||
|
// encrypted data, or some other metadata can be used to decide
|
||||||
|
// whether deceyption is needed, logic can be added here.
|
||||||
|
//
|
||||||
|
// Before that happens, we'll use hints and trial & error to decode the
|
||||||
|
// data
|
||||||
|
// Hints: Per lightning data format spec, there are 3 bytes in the WMO
|
||||||
|
// header starting line that indicates the size of the encrypted block
|
||||||
|
// or the ASCII sequence # for legacy bit-shifted data
|
||||||
|
// However, the starting line is optional and AWIPS decode may not see
|
||||||
|
// it at all because TG will strip that starting line away
|
||||||
|
// We'll try to use this hint first, if is is not found, then trial and
|
||||||
|
// error way to decrypt and decode
|
||||||
|
//
|
||||||
|
// As of 11/05/2013, There is change in data spec. that the 3-bytes will
|
||||||
|
// not be encoded as encrypted block size anymore (it will always be
|
||||||
|
// transmission sequence # if present)
|
||||||
|
// So there should have some minor changes in the logic below for
|
||||||
|
// decoding the data.
|
||||||
|
// However, as reading into the
|
||||||
|
// com.raytheon.edex.plugin.binlightning.impl.BinLightningFactory.getDecoder()
|
||||||
|
// and follow-on code, we see the following data patterns
|
||||||
|
// for legacy bit-shifted data, which could be used to reduce guess-work
|
||||||
|
// in data decryption:
|
||||||
|
// The bit-shifted data will have multiple groups of the following
|
||||||
|
// patterns:
|
||||||
|
// 1-byte (unsigned byte): for size count
|
||||||
|
// 1-byte (unsigned byte): for flash type:
|
||||||
|
// 0x96 for FLASH_RPT (message size is 6 bytes each)
|
||||||
|
// 0x97 for RT_FLASH_RPT (message size is 8 bytes each)
|
||||||
|
// 0xd0 for OTHER_RPT (The D2D decoders declare but do not define this
|
||||||
|
// message, so unimplemented decoder)
|
||||||
|
// 0xd1 for COMM_RPT (The D2D decoders declare but do not define this
|
||||||
|
// message, so unimplemented decoder)
|
||||||
|
// 4-bytes: date time
|
||||||
|
// multiple of 6 or 8 bytes (as determined by 2nd byte flash type) with
|
||||||
|
// count indicated in 1st byte
|
||||||
|
//
|
||||||
|
// So this is be used to determine whether the data need to be
|
||||||
|
// decrypted.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* // looks like previous assumption on block size bytes are not valid
|
||||||
|
* any more. 11/20/2013 if (data != null) { byte[] sizeSeqBytes =
|
||||||
|
* BinLigntningDecoderUtil.findSizeOrSeqBytesFromWMOHeader(data); if
|
||||||
|
* (sizeSeqBytes != null) { // if this is in the header (which may not),
|
||||||
|
* use that as a hint to determine which decoding route to go if
|
||||||
|
* (BinLigntningDecoderUtil
|
||||||
|
* .isPossibleWMOHeaderSequenceNumber(sizeSeqBytes) &&
|
||||||
|
* BinLigntningDecoderUtil
|
||||||
|
* .getEncryptedBlockSizeFromWMOHeader(sizeSeqBytes) != pdata.length) {
|
||||||
|
* // looks like a sequence #, and if treat as size, it does not equal
|
||||||
|
* to the data block size, so most likely legacy data needDecrypt =
|
||||||
|
* false; } } }
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (needDecrypt) {
|
||||||
|
try {
|
||||||
|
// NOTE: 11/14/2013 WZ:
|
||||||
|
// encrypted test data on TNCF (got from Melissa Porricelli)
|
||||||
|
// seems to have extra 4 bytes (0x0d 0x0d 0x0a 0x03) at the end,
|
||||||
|
// making the data size not a multiple of 16. However, original
|
||||||
|
// test data do not have this trailing bytes. while NCEP test
|
||||||
|
// data has extra 8 trailing bytes.
|
||||||
|
// Brain Rapp's email on 11/13/2013 confirms that Unidata LDM
|
||||||
|
// software used by AWIPS II will strips off all SBN protocol
|
||||||
|
// headers
|
||||||
|
// that precede the WMO header and adds its own 11 byte header
|
||||||
|
// like this: "soh cr cr nl 2 5 4 sp cr cr nl". It
|
||||||
|
// also adds a four byte trailer consisting of "cr cr nl etx"
|
||||||
|
// (0x0d 0x0d 0x0a 0x03)
|
||||||
|
// So, it seems necessary to trim trailing bytes if it is not
|
||||||
|
// multiple of 16, warning messages will be logged though
|
||||||
|
int dataLengthToBeDecrypted = pdata.length;
|
||||||
|
if (pdata.length % 16 != 0) {
|
||||||
|
dataLengthToBeDecrypted = pdata.length
|
||||||
|
- (pdata.length % 16);
|
||||||
|
logger.warn(traceId + " - Data length from file " + traceId
|
||||||
|
+ " is " + pdata.length + " bytes, trailing "
|
||||||
|
+ (pdata.length - dataLengthToBeDecrypted)
|
||||||
|
+ " bytes has been trimmed to "
|
||||||
|
+ dataLengthToBeDecrypted
|
||||||
|
+ " bytes for decryption.");
|
||||||
|
}
|
||||||
|
byte[] encryptedData = new byte[dataLengthToBeDecrypted];
|
||||||
|
encryptedData = Arrays.copyOfRange(pdata, 0,
|
||||||
|
dataLengthToBeDecrypted);
|
||||||
|
|
||||||
|
byte[] decryptedData = cipher.decryptData(encryptedData,
|
||||||
|
dataDate);
|
||||||
|
// decrypt ok, then decode, first check if keep-alive record
|
||||||
|
if (BinLightningDecoderUtil.isKeepAliveRecord(decryptedData)) {
|
||||||
|
logger.info(traceId
|
||||||
|
+ " - Keep-alive record detected, ignore for now.");
|
||||||
|
decodeDone = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// not keep-alive record, then check data validity and decode
|
||||||
|
// into an ArrayList<LightningStrikePoint> of strikes
|
||||||
|
if (BinLightningDecoderUtil
|
||||||
|
.isLightningDataRecords(decryptedData)) {
|
||||||
|
strikes = BinLightningDecoderUtil
|
||||||
|
.decodeDecryptedBinLightningData(decryptedData);
|
||||||
|
decodeDone = true;
|
||||||
|
} else {
|
||||||
|
logger.info(traceId
|
||||||
|
+ " - Failed data validity check of the decrypted data, will try decode the old-fashioned way.");
|
||||||
|
decodeDone = false;
|
||||||
|
}
|
||||||
|
} catch (IllegalBlockSizeException e) {
|
||||||
|
logger.info(traceId
|
||||||
|
+ " - "
|
||||||
|
+ e.getMessage()
|
||||||
|
+ ": Decryption failed, will try decode the old-fashioned way.");
|
||||||
|
decodeDone = false;
|
||||||
|
} catch (BadPaddingException e) {
|
||||||
|
logger.info(traceId
|
||||||
|
+ " - "
|
||||||
|
+ e.getMessage()
|
||||||
|
+ ": Decryption failed, will try decode the old-fashioned way.");
|
||||||
|
decodeDone = false;
|
||||||
|
} catch (BinLightningDataDecryptionException e) {
|
||||||
|
logger.info(traceId
|
||||||
|
+ " - "
|
||||||
|
+ e.getMessage()
|
||||||
|
+ ": Decryption failed, will try decode the old-fashioned way.");
|
||||||
|
decodeDone = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decodeDone == false) { // not decoded through decrypt->decode
|
||||||
|
// process, try the legacy decoder
|
||||||
|
logger.info(traceId + " - decoding as bit-shifted data");
|
||||||
|
// bit-shifting data format check call here will get us some more
|
||||||
|
// information on the data, also can compare the strikes with the
|
||||||
|
// decoder result
|
||||||
|
int estimatedStrikes = BinLightningDecoderUtil
|
||||||
|
.getBitShiftedDataStrikeCount(pdata);
|
||||||
|
strikes = decodeBitShiftedBinLightningData(pdata, wmoHdr);
|
||||||
|
if (estimatedStrikes != strikes.size()) {
|
||||||
|
logger.warn(traceId
|
||||||
|
+ ": bit-shifted decoder found "
|
||||||
|
+ strikes
|
||||||
|
+ " strikes, which is different from estimate from data pattern examination: "
|
||||||
|
+ estimatedStrikes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strikes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extracted from the original {@link #decode(byte[], Headers)} method then
|
||||||
|
* modified by Wufeng Zhou
|
||||||
|
*
|
||||||
|
* @param pdata
|
||||||
|
* @param wmoHdr
|
||||||
|
* - WMOHeader, added 12/24/2013 to help distinguish bit-shifted
|
||||||
|
* NLDN and GLD360 data (GLD data will have header starts like
|
||||||
|
* SFPA)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static List<LightningStrikePoint> decodeBitShiftedBinLightningData(
|
||||||
|
byte[] pdata, WMOHeader wmoHdr) {
|
||||||
|
List<LightningStrikePoint> strikes = new ArrayList<LightningStrikePoint>();
|
||||||
|
|
||||||
|
IBinDataSource msgData = new LightningDataSource(pdata);
|
||||||
|
|
||||||
|
boolean continueDecode = true;
|
||||||
|
while (continueDecode) {
|
||||||
|
IBinLightningDecoder decoder = BinLightningFactory
|
||||||
|
.getDecoder(msgData);
|
||||||
|
|
||||||
|
switch (decoder.getError()) {
|
||||||
|
case IBinLightningDecoder.NO_ERROR: {
|
||||||
|
for (LightningStrikePoint strike : decoder) {
|
||||||
|
// use WMO Header to distinguish NLDN or GLD360 data because
|
||||||
|
// no bit-shifted data spec available for GLD360.
|
||||||
|
// 12/24/2013, WZ
|
||||||
|
// The WMO header start string is defined in
|
||||||
|
// BinLightningAESKey.properties file (normally, GLD360 data
|
||||||
|
// will have WMO header
|
||||||
|
// starts with SFPA41, or SFPA99 for test data.)
|
||||||
|
String gld360WMOHeaderString = BinLightningAESKey
|
||||||
|
.getProps().getProperty(
|
||||||
|
"binlightning.gld360WMOHeaderStartString",
|
||||||
|
"");
|
||||||
|
if (gld360WMOHeaderString.trim().equals("") == false
|
||||||
|
&& wmoHdr.getWmoHeader().startsWith(
|
||||||
|
gld360WMOHeaderString)) {
|
||||||
|
// GLD360 data based on the setup
|
||||||
|
strike.setLightSource("GLD");
|
||||||
|
}
|
||||||
|
strikes.add(strike);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
continueDecode = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strikes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a trace identifier for the source data.
|
* Set a trace identifier for the source data.
|
||||||
*
|
*
|
||||||
|
|
|
@ -24,4 +24,11 @@
|
||||||
version="0.0.0"
|
version="0.0.0"
|
||||||
unpack="false"/>
|
unpack="false"/>
|
||||||
|
|
||||||
|
<plugin
|
||||||
|
id="gov.noaa.nws.ost.edex.plugin.binlightning"
|
||||||
|
download-size="0"
|
||||||
|
install-size="0"
|
||||||
|
version="0.0.0"
|
||||||
|
unpack="false"/>
|
||||||
|
|
||||||
</feature>
|
</feature>
|
||||||
|
|
7
ost/gov.noaa.nws.ost.edex.plugin.binlightning/.classpath
Normal file
7
ost/gov.noaa.nws.ost.edex.plugin.binlightning/.classpath
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
28
ost/gov.noaa.nws.ost.edex.plugin.binlightning/.project
Normal file
28
ost/gov.noaa.nws.ost.edex.plugin.binlightning/.project
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>gov.noaa.nws.ost.edex.plugin.binlightning</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.pde.PluginNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.7
|
|
@ -0,0 +1,13 @@
|
||||||
|
Manifest-Version: 1.0
|
||||||
|
Bundle-ManifestVersion: 2
|
||||||
|
Bundle-Name: OST Binlightning
|
||||||
|
Bundle-SymbolicName: gov.noaa.nws.ost.edex.plugin.binlightning
|
||||||
|
Bundle-Version: 1.14.0.qualifier
|
||||||
|
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
|
||||||
|
Import-Package: com.raytheon.uf.common.dataplugin.binlightning,
|
||||||
|
com.raytheon.uf.common.dataplugin.binlightning.dataaccess,
|
||||||
|
com.raytheon.uf.common.dataplugin.binlightning.impl,
|
||||||
|
com.raytheon.uf.common.status,
|
||||||
|
com.raytheon.uf.common.wmo,
|
||||||
|
com.raytheon.uf.edex.decodertools.core
|
||||||
|
Export-Package: gov.noaa.nws.ost.edex.plugin.binlightning
|
|
@ -0,0 +1,4 @@
|
||||||
|
source.. = src/
|
||||||
|
output.. = bin/
|
||||||
|
bin.includes = META-INF/,\
|
||||||
|
.
|
|
@ -27,13 +27,14 @@ import java.util.TreeMap;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import com.raytheon.uf.common.status.UFStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BinLightningAESKey
|
* BinLightningAESKey
|
||||||
*
|
*
|
||||||
* Simple representation of bin lightning AES encryption key and its associated key aliases in the keystore
|
* Simple representation of bin lightning AES encryption key and its associated
|
||||||
|
* key aliases in the keystore
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*
|
*
|
||||||
|
@ -42,6 +43,7 @@ import org.apache.commons.logging.LogFactory;
|
||||||
* Date Ticket# Engineer Description
|
* Date Ticket# Engineer Description
|
||||||
* ------------ ---------- ----------- --------------------------
|
* ------------ ---------- ----------- --------------------------
|
||||||
* 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
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -63,7 +65,8 @@ public class BinLightningAESKey {
|
||||||
private static final Pattern KEY_ALIAS_PREFIX_PATTERN = Pattern.compile(KEY_ALIAS_PREFIX);
|
private static final Pattern KEY_ALIAS_PREFIX_PATTERN = Pattern.compile(KEY_ALIAS_PREFIX);
|
||||||
private static final SimpleDateFormat KEY_ALIAS_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
|
private static final SimpleDateFormat KEY_ALIAS_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(BinLightningAESKey.class);
|
private static IUFStatusHandler logger = UFStatus
|
||||||
|
.getHandler(BinLightningAESKey.class);
|
||||||
|
|
||||||
private static Properties props = new Properties();
|
private static Properties props = new Properties();
|
||||||
private static KeyStore keystore;
|
private static KeyStore keystore;
|
|
@ -9,24 +9,14 @@ import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
|
|
||||||
import com.raytheon.edex.plugin.binlightning.impl.BinLightningFactory;
|
|
||||||
import com.raytheon.edex.plugin.binlightning.impl.IBinLightningDecoder;
|
|
||||||
import com.raytheon.edex.plugin.binlightning.impl.LightningDataSource;
|
|
||||||
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
|
import com.raytheon.uf.common.dataplugin.binlightning.impl.LightningStrikePoint;
|
||||||
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgMsgType;
|
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgMsgType;
|
||||||
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
|
import com.raytheon.uf.common.dataplugin.binlightning.impl.LtgStrikeType;
|
||||||
import com.raytheon.uf.common.wmo.WMOHeader;
|
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||||
|
import com.raytheon.uf.common.status.UFStatus;
|
||||||
import com.raytheon.uf.edex.decodertools.core.BasePoint;
|
import com.raytheon.uf.edex.decodertools.core.BasePoint;
|
||||||
import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BinLigntningDecoderUtil
|
* BinLigntningDecoderUtil
|
||||||
|
@ -44,12 +34,16 @@ import com.raytheon.uf.edex.decodertools.core.IBinDataSource;
|
||||||
* ------------ ---------- ----------- --------------------------
|
* ------------ ---------- ----------- --------------------------
|
||||||
* 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
|
||||||
* 20140501 Wufeng Zhou Fix the encrypted decoding with correct offset
|
* 20140501 Wufeng Zhou Fix the encrypted decoding with correct offset
|
||||||
|
* Jun 03, 2014 3226 bclement renamed from BinLigntningDecoderUtil to BinLightningDecoderUtil
|
||||||
|
* moved from com.raytheon.edex.plugin.binlightning to gov.noaa.nws.ost.edex.plugin.binlightning
|
||||||
|
* moved decodeBinLightningData() and decodeBitShiftedBinLightningData()
|
||||||
|
* to BinLightningDecoder to solve circular dependency
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
* @author Wufeng Zhou
|
* @author Wufeng Zhou
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class BinLigntningDecoderUtil {
|
public class BinLightningDecoderUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message type for keep alive data records.
|
* Message type for keep alive data records.
|
||||||
|
@ -84,47 +78,10 @@ public class BinLigntningDecoderUtil {
|
||||||
static final byte OTHER_RPT = (byte)0xD0;
|
static final byte OTHER_RPT = (byte)0xD0;
|
||||||
static final byte COMM_RPT = (byte)0xD1;
|
static final byte COMM_RPT = (byte)0xD1;
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(BinLigntningDecoderUtil.class);
|
private static IUFStatusHandler logger = UFStatus
|
||||||
|
.getHandler(BinLightningDecoderUtil.class);
|
||||||
|
|
||||||
/**
|
|
||||||
* extracted from the decode() of the original
|
|
||||||
* com.raytheon.edex.plugin.binlightning.BinLightningDecoder class
|
|
||||||
*
|
|
||||||
* @param pdata
|
|
||||||
* @param wmoHdr - WMOHeader, added 12/24/2013 to help distinguish bit-shifted NLDN and GLD360 data (GLD data will have header starts like SFPA)
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static List<LightningStrikePoint> decodeBitShiftedBinLightningData(byte[] pdata, WMOHeader wmoHdr) {
|
|
||||||
List<LightningStrikePoint> strikes = new ArrayList<LightningStrikePoint>();
|
|
||||||
|
|
||||||
IBinDataSource msgData = new LightningDataSource(pdata);
|
|
||||||
|
|
||||||
boolean continueDecode = true;
|
|
||||||
while (continueDecode) {
|
|
||||||
IBinLightningDecoder decoder = BinLightningFactory.getDecoder(msgData);
|
|
||||||
|
|
||||||
switch (decoder.getError()) {
|
|
||||||
case IBinLightningDecoder.NO_ERROR: {
|
|
||||||
for (LightningStrikePoint strike : decoder) {
|
|
||||||
// use WMO Header to distinguish NLDN or GLD360 data because no bit-shifted data spec available for GLD360. 12/24/2013, WZ
|
|
||||||
// The WMO header start string is defined in BinLightningAESKey.properties file (normally, GLD360 data will have WMO header
|
|
||||||
// starts with SFPA41, or SFPA99 for test data.)
|
|
||||||
String gld360WMOHeaderString = BinLightningAESKey.getProps().getProperty("binlightning.gld360WMOHeaderStartString", "");
|
|
||||||
if (gld360WMOHeaderString.trim().equals("") == false && wmoHdr.getWmoHeader().startsWith(gld360WMOHeaderString)) {
|
|
||||||
// GLD360 data based on the setup
|
|
||||||
strike.setLightSource("GLD");
|
|
||||||
}
|
|
||||||
strikes.add(strike);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
continueDecode = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strikes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decode the new bin lightning data, after the data record is decrypted, and it is not keep-alive record
|
* decode the new bin lightning data, after the data record is decrypted, and it is not keep-alive record
|
||||||
|
@ -170,8 +127,9 @@ public class BinLigntningDecoderUtil {
|
||||||
int strokeType = buffer.getShort() & 0xffff; // 0x0000 for cloud-to-ground, 0x00ff for cloud-to-cloud, 0xffff for total flash
|
int strokeType = buffer.getShort() & 0xffff; // 0x0000 for cloud-to-ground, 0x00ff for cloud-to-cloud, 0xffff for total flash
|
||||||
short strokeKiloAmps = buffer.getShort(); // valid range: -254 to 254, specifically 16 bit signed integer
|
short strokeKiloAmps = buffer.getShort(); // valid range: -254 to 254, specifically 16 bit signed integer
|
||||||
int strokeMultiplicity = buffer.getShort() & 0xffff; // i.e. stroke count, valid range: 0 to 15
|
int strokeMultiplicity = buffer.getShort() & 0xffff; // i.e. stroke count, valid range: 0 to 15
|
||||||
int strokeDuration = buffer.getShort() & 0xffff; // valid range: 0 to 65535 (i.e., looks like unsigned short)
|
// int strokeDuration = buffer.getShort() & 0xffff; // valid range:
|
||||||
int reserved = buffer.getShort() & 0xffff;
|
// 0 to 65535 (i.e., looks like unsigned short)
|
||||||
|
// int reserved = buffer.getShort() & 0xffff;
|
||||||
|
|
||||||
// Create the strike record from the report info and base time information.
|
// Create the strike record from the report info and base time information.
|
||||||
BasePoint base = new BasePoint(lat, lon);
|
BasePoint base = new BasePoint(lat, lon);
|
||||||
|
@ -236,134 +194,7 @@ public class BinLigntningDecoderUtil {
|
||||||
return strikes;
|
return strikes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Decode bin lightning data, able to handle both legacy bit-shifted and new encryted data
|
|
||||||
*
|
|
||||||
* The modified BinLightningDecoder.decode() method will use this method to decode data, which
|
|
||||||
* will try to decrypt first, and decode the old fashioned way when decryption fails
|
|
||||||
*
|
|
||||||
* @param data - data content from file, including WMO header section
|
|
||||||
* @param pdata - data with WMO header stripped, optional, if null, will strip WMO header internally from passed in data parameter
|
|
||||||
* @param traceId - the file name of the data to be deoced
|
|
||||||
* @param wmoHdr - WMOHeader, added 12/24/2013 to help distinguish bit-shifted NLDN and GLD360 data (GLD data will have header starts like SFPA)
|
|
||||||
* @param dataDate - date of the data, optional, used as a hint to find appropriate encryption key faster
|
|
||||||
* @return null if keep-alive record, otherwise a list (could be empty) of LightningStrikePoint
|
|
||||||
*/
|
|
||||||
public static List<LightningStrikePoint> decodeBinLightningData(byte[] data, byte[] pdata, String traceId, WMOHeader wmoHdr, Date dataDate) {
|
|
||||||
if (pdata == null) { // if data without header not passed, we'll strip the WMO header here
|
|
||||||
WMOHeader header = new WMOHeader(data);
|
|
||||||
if (header.isValid() && header.getMessageDataStart() > 0) {
|
|
||||||
pdata = new byte[data.length - header.getMessageDataStart()];
|
|
||||||
System.arraycopy(data, header.getMessageDataStart(), pdata, 0, data.length - header.getMessageDataStart());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<LightningStrikePoint> strikes = new ArrayList<LightningStrikePoint>();
|
|
||||||
boolean needDecrypt = true; // set as default unless clear evidence says otherwise
|
|
||||||
boolean decodeDone = false;
|
|
||||||
EncryptedBinLightningCipher cipher = new EncryptedBinLightningCipher();
|
|
||||||
|
|
||||||
//
|
|
||||||
// Using different WMO headers to indicate whether the data is encrypted or not would be a nice option.
|
|
||||||
// However, that idea has been discussed but not adopted.
|
|
||||||
// If in the future, WMO header can be different for legacy and encrypted data, or some other metadata can be used to decide
|
|
||||||
// whether deceyption is needed, logic can be added here.
|
|
||||||
//
|
|
||||||
// Before that happens, we'll use hints and trial & error to decode the data
|
|
||||||
// Hints: Per lightning data format spec, there are 3 bytes in the WMO header starting line that indicates the size of the encrypted block
|
|
||||||
// or the ASCII sequence # for legacy bit-shifted data
|
|
||||||
// However, the starting line is optional and AWIPS decode may not see it at all because TG will strip that starting line away
|
|
||||||
// We'll try to use this hint first, if is is not found, then trial and error way to decrypt and decode
|
|
||||||
//
|
|
||||||
// As of 11/05/2013, There is change in data spec. that the 3-bytes will not be encoded as encrypted block size anymore (it will always be transmission sequence # if present)
|
|
||||||
// So there should have some minor changes in the logic below for decoding the data.
|
|
||||||
// However, as reading into the com.raytheon.edex.plugin.binlightning.impl.BinLightningFactory.getDecoder() and follow-on code, we see the following data patterns
|
|
||||||
// for legacy bit-shifted data, which could be used to reduce guess-work in data decryption:
|
|
||||||
// The bit-shifted data will have multiple groups of the following patterns:
|
|
||||||
// 1-byte (unsigned byte): for size count
|
|
||||||
// 1-byte (unsigned byte): for flash type:
|
|
||||||
// 0x96 for FLASH_RPT (message size is 6 bytes each)
|
|
||||||
// 0x97 for RT_FLASH_RPT (message size is 8 bytes each)
|
|
||||||
// 0xd0 for OTHER_RPT (The D2D decoders declare but do not define this message, so unimplemented decoder)
|
|
||||||
// 0xd1 for COMM_RPT (The D2D decoders declare but do not define this message, so unimplemented decoder)
|
|
||||||
// 4-bytes: date time
|
|
||||||
// multiple of 6 or 8 bytes (as determined by 2nd byte flash type) with count indicated in 1st byte
|
|
||||||
//
|
|
||||||
// So this is be used to determine whether the data need to be decrypted.
|
|
||||||
|
|
||||||
/*
|
|
||||||
// looks like previous assumption on block size bytes are not valid any more. 11/20/2013
|
|
||||||
if (data != null) {
|
|
||||||
byte[] sizeSeqBytes = BinLigntningDecoderUtil.findSizeOrSeqBytesFromWMOHeader(data);
|
|
||||||
if (sizeSeqBytes != null) {
|
|
||||||
// if this is in the header (which may not), use that as a hint to determine which decoding route to go
|
|
||||||
if (BinLigntningDecoderUtil.isPossibleWMOHeaderSequenceNumber(sizeSeqBytes)
|
|
||||||
&& BinLigntningDecoderUtil.getEncryptedBlockSizeFromWMOHeader(sizeSeqBytes) != pdata.length) {
|
|
||||||
// looks like a sequence #, and if treat as size, it does not equal to the data block size, so most likely legacy data
|
|
||||||
needDecrypt = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (needDecrypt) {
|
|
||||||
try {
|
|
||||||
// NOTE: 11/14/2013 WZ:
|
|
||||||
// encrypted test data on TNCF (got from Melissa Porricelli) seems to have extra 4 bytes (0x0d 0x0d 0x0a 0x03) at the end,
|
|
||||||
// making the data size not a multiple of 16. However, original test data do not have this trailing bytes. while NCEP test
|
|
||||||
// data has extra 8 trailing bytes.
|
|
||||||
// Brain Rapp's email on 11/13/2013 confirms that Unidata LDM software used by AWIPS II will strips off all SBN protocol headers
|
|
||||||
// that precede the WMO header and adds its own 11 byte header like this: "soh cr cr nl 2 5 4 sp cr cr nl". It
|
|
||||||
// also adds a four byte trailer consisting of "cr cr nl etx" (0x0d 0x0d 0x0a 0x03)
|
|
||||||
// So, it seems necessary to trim trailing bytes if it is not multiple of 16, warning messages will be logged though
|
|
||||||
int dataLengthToBeDecrypted = pdata.length;
|
|
||||||
if (pdata.length % 16 != 0) {
|
|
||||||
dataLengthToBeDecrypted = pdata.length - (pdata.length % 16);
|
|
||||||
logger.warn(traceId + " - Data length from file " + traceId + " is " + pdata.length + " bytes, trailing " +
|
|
||||||
(pdata.length - dataLengthToBeDecrypted) + " bytes has been trimmed to " + dataLengthToBeDecrypted + " bytes for decryption.");
|
|
||||||
}
|
|
||||||
byte[] encryptedData = new byte[dataLengthToBeDecrypted];
|
|
||||||
encryptedData = Arrays.copyOfRange(pdata, 0, dataLengthToBeDecrypted);
|
|
||||||
|
|
||||||
byte[] decryptedData = cipher.decryptData(encryptedData, dataDate);
|
|
||||||
// decrypt ok, then decode, first check if keep-alive record
|
|
||||||
if (BinLigntningDecoderUtil.isKeepAliveRecord(decryptedData)) {
|
|
||||||
logger.info(traceId + " - Keep-alive record detected, ignore for now.");
|
|
||||||
decodeDone = true;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// not keep-alive record, then check data validity and decode into an ArrayList<LightningStrikePoint> of strikes
|
|
||||||
if (BinLigntningDecoderUtil.isLightningDataRecords(decryptedData)) {
|
|
||||||
strikes = BinLigntningDecoderUtil.decodeDecryptedBinLightningData(decryptedData);
|
|
||||||
decodeDone = true;
|
|
||||||
} else {
|
|
||||||
logger.info(traceId + " - Failed data validity check of the decrypted data, will try decode the old-fashioned way.");
|
|
||||||
decodeDone = false;
|
|
||||||
}
|
|
||||||
} catch (IllegalBlockSizeException e) {
|
|
||||||
logger.info(traceId + " - " + e.getMessage() + ": Decryption failed, will try decode the old-fashioned way.");
|
|
||||||
decodeDone = false;
|
|
||||||
} catch (BadPaddingException e) {
|
|
||||||
logger.info(traceId + " - " + e.getMessage() + ": Decryption failed, will try decode the old-fashioned way.");
|
|
||||||
decodeDone = false;
|
|
||||||
} catch (BinLightningDataDecryptionException e) {
|
|
||||||
logger.info(traceId + " - " + e.getMessage() + ": Decryption failed, will try decode the old-fashioned way.");
|
|
||||||
decodeDone = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (decodeDone == false) { // not decoded through decrypt->decode process, try the legacy decoder
|
|
||||||
logger.info(traceId + " - decoding as bit-shifted data");
|
|
||||||
// bit-shifting data format check call here will get us some more information on the data, also can compare the strikes with the decoder result
|
|
||||||
int estimatedStrikes = getBitShiftedDataStrikeCount(pdata);
|
|
||||||
strikes = BinLigntningDecoderUtil.decodeBitShiftedBinLightningData(pdata, wmoHdr);
|
|
||||||
if (estimatedStrikes != strikes.size()) {
|
|
||||||
logger.warn(traceId + ": bit-shifted decoder found " + strikes + " strikes, which is different from estimate from data pattern examination: " + estimatedStrikes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return strikes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the bytes passed are a standard "NWS Keep Alive" message.
|
* Determines if the bytes passed are a standard "NWS Keep Alive" message.
|
|
@ -6,6 +6,7 @@ package gov.noaa.nws.ost.edex.plugin.binlightning;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -15,13 +16,14 @@ import javax.crypto.Cipher;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
import javax.crypto.spec.SecretKeySpec;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import com.raytheon.uf.common.status.IUFStatusHandler;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import com.raytheon.uf.common.status.UFStatus;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EncryptedBinLightningCipher
|
* EncryptedBinLightningCipher
|
||||||
*
|
*
|
||||||
* Use AES secret keys found in configured keystore to decrypt bin lightning data
|
* Use AES secret keys found in configured keystore to decrypt bin lightning
|
||||||
|
* data
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
*
|
*
|
||||||
|
@ -30,6 +32,8 @@ import org.apache.commons.logging.LogFactory;
|
||||||
* Date Ticket# Engineer Description
|
* Date Ticket# Engineer Description
|
||||||
* ------------ ---------- ----------- --------------------------
|
* ------------ ---------- ----------- --------------------------
|
||||||
* 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
|
||||||
|
* handled null return from BinLightningAESKey.getBinLightningAESKeys()
|
||||||
*
|
*
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
@ -51,6 +55,9 @@ public class EncryptedBinLightningCipher {
|
||||||
protected HashMap<String, Cipher> initialValue() {
|
protected HashMap<String, Cipher> initialValue() {
|
||||||
// get AES keys from keystore and create encryption and decryption ciphers from them
|
// get AES keys from keystore and create encryption and decryption ciphers from them
|
||||||
BinLightningAESKey[] keys = BinLightningAESKey.getBinLightningAESKeys();
|
BinLightningAESKey[] keys = BinLightningAESKey.getBinLightningAESKeys();
|
||||||
|
if (keys == null) {
|
||||||
|
keys = new BinLightningAESKey[0];
|
||||||
|
}
|
||||||
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 {
|
||||||
|
@ -67,7 +74,8 @@ public class EncryptedBinLightningCipher {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private static Log logger = LogFactory.getLog(EncryptedBinLightningCipher.class);
|
private static IUFStatusHandler logger = UFStatus
|
||||||
|
.getHandler(EncryptedBinLightningCipher.class);
|
||||||
|
|
||||||
public EncryptedBinLightningCipher() {
|
public EncryptedBinLightningCipher() {
|
||||||
|
|
||||||
|
@ -122,7 +130,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 ( BinLigntningDecoderUtil.isKeepAliveRecord(decryptedData) == false && BinLigntningDecoderUtil.isLightningDataRecords(decryptedData) == false) {
|
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 (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 "
|
||||||
+ preferredKeyList.get(i).getAlias() + " is not valid keep-alive or binLightning records.", decryptedData);
|
+ preferredKeyList.get(i).getAlias() + " is not valid keep-alive or binLightning records.", decryptedData);
|
||||||
|
@ -163,7 +171,11 @@ public class EncryptedBinLightningCipher {
|
||||||
* @return preferred key list order
|
* @return preferred key list order
|
||||||
*/
|
*/
|
||||||
private List<BinLightningAESKey> findPreferredKeyOrderForData(Date dataDate) {
|
private List<BinLightningAESKey> findPreferredKeyOrderForData(Date dataDate) {
|
||||||
List<BinLightningAESKey> defKeyList = Arrays.asList(BinLightningAESKey.getBinLightningAESKeys());
|
BinLightningAESKey[] binLightningAESKeys = BinLightningAESKey.getBinLightningAESKeys();
|
||||||
|
if (binLightningAESKeys == null || binLightningAESKeys.length < 1) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
List<BinLightningAESKey> defKeyList = Arrays.asList(binLightningAESKeys);
|
||||||
if (dataDate == null) {
|
if (dataDate == null) {
|
||||||
return defKeyList; // use default order
|
return defKeyList; // use default order
|
||||||
}
|
}
|
Loading…
Add table
Reference in a new issue