CUST: - FwUpdateSw: - validate password file before installation

Common/../MeterPwdFile: - New CheckHashedPwdFile to validate password file with skeleton and password level 8 information
This commit is contained in:
Thomas Wiedebusch 2023-10-26 17:57:11 +02:00
parent 5abdbe7354
commit 79fa88c4e7
6 changed files with 94 additions and 20 deletions

View File

@ -223,6 +223,64 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
return true;
}
/// <summary>
/// Check the hashed password file:
/// - Checks if password level 8 is unequal to skeleton key
/// - Checks if password level 3 is unequal to password level 8 (level 3 may be overwritten by level 8
/// password hash)
/// - Builds skeleton key password hash and checks if this is placed at password level 3,
/// - Builds password level 8 hash and checks if this is placed at level 8.
/// </summary>
/// <param name="pwdFile"></param>
/// <param name="skeletonKey">SkeletonKey for comparison </param>
/// <param name="pwdLevel8"></param>
/// <returns></returns>
/// <remarks date="2023-Oct-26" author="Thomas Wiedebusch">
/// - Initial.
/// </remarks>
public Boolean CheckHashedPwdFile(Byte[] pwdFile, String skeletonKey, String pwdLevel8)
{
var retVal = false;
// the skeletonKey has to be unequally to the passwordLvl8
if (skeletonKey.Equals(pwdLevel8))
{
return false;
}
// compare hashed skeletonKey and passwordLvl8
for (var c = 0; c < MeterPwdDb.HashedPwdLength; c++)
{
// hashed level 3 and level 8 have to be unequal on at least one byte position
if (pwdFile[MeterPwdDb.SkeletonKeyIdx * MeterPwdDb.HashedPwdLength + c] !=
pwdFile[MeterPwdDb.PwdLevel8Idx * MeterPwdDb.HashedPwdLength + c])
{
retVal = true;
break;
}
}
// hash the skeleton and check if equal to hashed level 3
// hash the passwordLvl8 and check if equal to hashed level 8
using (var sha1 = new System.Security.Cryptography.SHA1Managed())
{
var skeletonHash = sha1.ComputeHash(Encoding.UTF8.GetBytes(skeletonKey));
var passwordLvl8Hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(pwdLevel8));
for (var c = 0; c < MeterPwdDb.HashedPwdLength; c++)
{
// if any byte is different the passwords do not match
if (pwdFile[MeterPwdDb.SkeletonKeyIdx * MeterPwdDb.HashedPwdLength + c] != skeletonHash[c] ||
pwdFile[MeterPwdDb.PwdLevel8Idx * MeterPwdDb.HashedPwdLength + c] != passwordLvl8Hash[c])
{
return false;
}
}
}
return retVal;
}
/// <summary>
/// Build skeleton key out of unique processor Id
/// </summary>

View File

@ -1341,14 +1341,14 @@ namespace Xylem.ServiceFwUpdate.Ui.FwUpdateBuilder
fwUpdateSafe.Updates.CordonelDeviceInfos = _cordonelUpdateList;
////TODO THW remove this DEBUG to map from current selection to TEST BOARD
//_cordonelUpdateList[0].CustomerSerialNumber = "8 SEN20 1975 6272";
//_cordonelUpdateList[0].PcbId = "182100041";
//GetPwdFromDb(_cordonelUpdateList[0]);
//fwUpdateSafe.License.Build = 5;
//var dateTime = fwUpdateSafe.License.ValidTo.AddDays(-1);
//fwUpdateSafe.License.ValidTo = dateTime;
//var addDays = fwUpdateSafe.SafeInfo.FwUpdateValidDate.AddDays(-1);
//fwUpdateSafe.SafeInfo.FwUpdateValidDate = addDays;
_cordonelUpdateList[0].CustomerSerialNumber = "8 SEN20 1975 6272";
_cordonelUpdateList[0].PcbId = "182100041";
GetPwdFromDb(_cordonelUpdateList[0]);
fwUpdateSafe.License.Build = 5;
var dateTime = fwUpdateSafe.License.ValidTo.AddDays(-1);
fwUpdateSafe.License.ValidTo = dateTime;
var addDays = fwUpdateSafe.SafeInfo.FwUpdateValidDate.AddDays(-1);
fwUpdateSafe.SafeInfo.FwUpdateValidDate = addDays;
////TODO THW remove this DEBUG to map from current selection to TEST BOARD
var serializedData = JsonConvert.SerializeObject(fwUpdateSafe);

View File

@ -52,6 +52,8 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
private GenesisMeter _currentGenesis;
private readonly MeterBatch _meterBatch;
private Byte[] _hashedPwdFile;
private String _passwordLvl8;
private String _skeletonKey;
// port settings
private MeterPortScanner _serialPortScanner;
@ -3006,15 +3008,15 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
}
// Search the PCB ID and extract password for login
String password = null;
String skeletonKey = null;
_skeletonKey = null;
_passwordLvl8 = null;
_genesisInUpdateList = false;
if (_cordonelDeviceInfos != null)
{
foreach (var device in _cordonelDeviceInfos.Where(device => _currentGenesis.PcbId == device.PcbId))
{
skeletonKey = device.PwdContainer.SkeletonKey;
password = device.PwdContainer.PasswordLvl8;
_skeletonKey = device.PwdContainer.SkeletonKey;
_passwordLvl8 = device.PwdContainer.PasswordLvl8;
if (!string.IsNullOrEmpty(device.CustomerSerialNumber))
_customerSerialNumber = device.CustomerSerialNumber;
@ -3026,7 +3028,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
}
}
if (password == null || skeletonKey == null)
if (_passwordLvl8 == null || _skeletonKey == null)
{
_processState = ProcessState.Error;
return false;
@ -3038,7 +3040,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
// This login may be time consuming on readout of application information
// first try to login with password Level 8, this is needed if the password file is installed
if (LoginAndSpecialSetupProcedure(password))
if (LoginAndSpecialSetupProcedure(_passwordLvl8))
{
LogText(Resources.StrLoginPwdLevel8);
_passwordFileIsCorrupted = false;
@ -3057,7 +3059,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
Thread.Sleep(5000);
// Use the skeleton key for login as the password file may not be installed or invalid
if (LoginAndSpecialSetupProcedure(skeletonKey))
if (LoginAndSpecialSetupProcedure(_skeletonKey))
{
LogText(Resources.StrLoginSkeletonKey);
return true;
@ -3736,13 +3738,12 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
return;
}
//TODO THW avoid installation of password file if hash of level 3 equals level 8
//TODO THW avoid installation if password file level 3 is unequal hashed skeletonKey
//TODO THW avoid installation if password file level 8 is unequal hashed password
InfoProcessActive(lblPasswordFileCheck, Resources.StrPasswordFileRestoreActive);
// try to install password, first get the password file from device info
var pwdFileObject = new MeterPwdFile(_currentGenesis);
if (_hashedPwdFile != null && _hashedPwdFile.Length == MeterPwdDb.PwdFileLength)
if (_hashedPwdFile != null &&
_hashedPwdFile.Length == MeterPwdDb.PwdFileLength &&
pwdFileObject.CheckHashedPwdFile(_hashedPwdFile , _skeletonKey, _passwordLvl8))
{
SetControlsCommunicationActive();
_currentGenesis?.ReLogin();
@ -3768,7 +3769,7 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw
// the password file is NOT in the password container
else
{
InfoProcessFailed(lblPasswordFileCheck, Resources.StrPasswordNotDelivered);
InfoProcessFailed(lblPasswordFileCheck, Resources.StrPasswordFileFromSafeInvalid);
_processState = errorExitState;
}

View File

@ -745,6 +745,15 @@ namespace Xylem.ServiceFwUpdate.Ui.ServiceFwUpdateSw.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Password file from FW update safe is invalid!.
/// </summary>
internal static string StrPasswordFileFromSafeInvalid {
get {
return ResourceManager.GetString("StrPasswordFileFromSafeInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to ERROR: Password file not installed or invalid!.
/// </summary>

View File

@ -604,4 +604,7 @@
<data name="StrTestReportSafeBuiltOperator" xml:space="preserve">
<value>FW-Update Builderoperator ID:</value>
</data>
<data name="StrPasswordFileFromSafeInvalid" xml:space="preserve">
<value>FEHLER: Paßwortdatei vom FW Update Safe ist ungültig!</value>
</data>
</root>

View File

@ -604,4 +604,7 @@
<data name="StrTestReportSafeBuiltOperator" xml:space="preserve">
<value>FW-Update Builder Operator ID:</value>
</data>
<data name="StrPasswordFileFromSafeInvalid" xml:space="preserve">
<value>ERROR: Password file from FW update safe is invalid!</value>
</data>
</root>