diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterPwdFile.cs b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterPwdFile.cs
index bc6f2c21..69e0cfd1 100644
--- a/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterPwdFile.cs
+++ b/Common/Hardware/WaterMeter/Genesis/GenesisFile/MeterPwdFile.cs
@@ -12,19 +12,37 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
///
public class MeterPwdFile
{
+ // The FwUpdateSw references this string
public const String StrPasswordFileName = "0\\password";
private readonly GenesisMeter _genesisMeter;
private readonly MeterFile _meterFile;
- private Byte[] _hashedPasswordFile;
//seven passwords are needed for Level 1, 2, 4, 5, 6, 7, Level 3 will be generated
//out of the ProcessorUID.
- //private const Int32 PwdLevels = 7;
+
+ ///
+ /// Hashed password file return
+ ///
+ public Byte[] HashedPasswordFile
+ {
+ get;
+ private set;
+ }
+
+ ///
+ /// Ctor for usage of build of password file without writing it
+ ///
+ ///
+ /// - Initial.
+ ///
+ public MeterPwdFile()
+ {
+ }
///
/// Ctor
///
///
- ///
+ ///
/// - Initial.
///
public MeterPwdFile(GenesisMeter genesisMeter)
@@ -45,11 +63,11 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
///
/// - Initial.
///
- public Boolean SetHashedPwdFile(Byte[] hashedPwdFile)
+ private Boolean SetHashedPwdFile(Byte[] hashedPwdFile)
{
if (MeterPwdDb.PwdFileLength != hashedPwdFile.Length) return false;
- _hashedPasswordFile = new Byte[hashedPwdFile.Length];
- _hashedPasswordFile = hashedPwdFile;
+ HashedPasswordFile = new Byte[hashedPwdFile.Length];
+ HashedPasswordFile = hashedPwdFile;
return true;
}
@@ -113,37 +131,95 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
///
/// Build the password file out of the clear text passwords.
- /// The Level 3 password is already preset.
+ /// The Level 3 password is already preset with skeletonKey.
+ ///
+ /// The skeleton key has to be unequal to the level 8 password, otherwise the skeleton key has been
+ /// overwritten with this password level 8 locking out all applications which need this key at the
+ /// level 3 to login in the configuration of the Cordonel.
+ ///
+ /// ATTENTION - PRECONDITIONS:
+ /// All passwords have to be preset in the list of passwords:
+ /// Level 1: random from password service
+ /// Level 2: random from password service
+ /// Level 3: skeletonKey, this is the initial password used in production, used by applications to
+ /// login to the configuration system of the Cordonel
+ /// Level 4: random from password service
+ /// Level 5: random from password service
+ /// Level 6: random from password service
+ /// Level 7: random from password service
+ /// Level 8: random from password service, this is the passwordLvl8 used in production after
+ /// password file installation
+ ///
+ /// Checks ( each failed check is going to throw an exception):
+ /// - Checks for individual clear text password length,
+ /// - Checks if list of clear text passwords are containing 8 levels,
+ /// - Checks that password level 3 is set to skeleton key,
+ /// - Checks that skeleton key is unequal to password level 8,
+ /// - Check file size of generated password file.
+ ///
///
- /// 8 sorted passwords levels: 1, 2, 3, 4, 5, 6, 7, 8
+ /// 8 sorted passwords levels: 1, 2, skeletonKey, 4, 5, 6, 7, 8
/// unique ID of processor used for password level 3
/// SkeletonKey for comparison
///
///
/// - Initial.
///
- ///
+ ///
/// - All 8 password levels will be passed,
/// - Password Level 3 will be compared with data base skeletonKey,
/// - SHA 1 of passwords.
///
- public Boolean BuildPwdFile(List pwdLevels, UInt64 processorUid, String dbSkeletonKey)
+ ///
+ /// - Throw exception if clear text password length is out of range.
+ /// - Throw exception if password list is out of range.
+ /// - Throw exception if password level3 does not contain the skeleton key.
+ /// - Throw exception if skeletonKey is overwritten with passwordLvl8.
+ /// - Throw exception if password file is out of range.
+ ///
+ public Boolean BuildPwdFile(List passwords, UInt64 processorUid, String dbSkeletonKey)
{
- if (!Encoding.UTF8.GetBytes(dbSkeletonKey).SequenceEqual(pwdLevels[2]))
+ // The length of each password has to be 12 bytes
+ if (passwords.Any( x => x.Length != MeterPwdDb.ClearTextPwdLength))
{
- throw new ApplicationException("Level 3 Password is unequal to the old Data Base Content!");
+ throw new ApplicationException("Individual password length is out of range! " +
+ $"Expected length for each password: {MeterPwdDb.ClearTextPwdLength}");
}
- var ret = new List();
+ // The password list has to contain 8 passwords
+ if (passwords.Count != MeterPwdDb.PwdLevels)
+ {
+ throw new ApplicationException("Number of passwords is out of range! " +
+ $"Expected: {MeterPwdDb.PwdLevels}, " +
+ $"Transmitted: {passwords.Count }");
+ }
+ // The skeleton key has to be preset on level 3
+ if (!Encoding.UTF8.GetBytes(dbSkeletonKey).SequenceEqual(passwords[MeterPwdDb.SkeletonKeyIdx]))
+ {
+ throw new ApplicationException("SkeletonKey is not set on password file level 3!");
+ }
+ // The skeleton key has to be unequal to the level 8 password
+ if (Encoding.UTF8.GetBytes(dbSkeletonKey).SequenceEqual(passwords[MeterPwdDb.PwdLevel8Idx]))
+ {
+ throw new ApplicationException("SkeletonKey is overwritten with password level 8!");
+ }
+ var hashedPasswords = new List();
- foreach (var keyLvl in pwdLevels)
+ foreach (var password in passwords)
{
using (var sha1 = new System.Security.Cryptography.SHA1Managed())
{
- var hash = sha1.ComputeHash(keyLvl);
- ret.AddRange(hash.ToList());
+ var passwordHash = sha1.ComputeHash(password);
+ hashedPasswords.AddRange(passwordHash.ToList());
}
}
- _hashedPasswordFile = ret.ToArray();
+ // The password file size has to be 160 bytes
+ if (hashedPasswords.ToArray().Length != MeterPwdDb.PwdFileLength)
+ {
+ throw new ApplicationException("Generated password file is out of range! " +
+ $"Expected: {MeterPwdDb.PwdFileLength}, " +
+ $"Transmitted: {hashedPasswords.ToArray().Length }");
+ }
+ HashedPasswordFile = hashedPasswords.ToArray();
return true;
}
@@ -177,12 +253,33 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
}
///
- /// Write the meter password file, which was generated at or
+ /// This function combines the write, read back and verification of the password file.
+ /// Write password file and compare it
+ /// The hashed password file can be set or has been preprocessed using the
+ ///
+ /// optional hashed password file with constant length as byte array
+ /// true if password file could be written, read back byte by byte
+ /// and compared being identical
+ ///
+ /// - Initial, imported from ProductionProcessPasswordFile.
+ ///
+ public Boolean WriteAndVerifyMeterPwdFile(Byte[] hashedPwdFile = null)
+ {
+ if (UnlockEraseWriteMeterPwdFile())
+ {
+ if (WriteMeterPwdFile(hashedPwdFile))
+ {
+ return VerifyMeterPwdFile();
+ }
+ }
+ return false;
+ }
+ ///
+ /// Write the meter password file which was generated at or
/// use the already hashed password file if this is already pre-generated.
/// The password file has a unique length of .
///
- /// hashed password file with constant length as byte array
- ///
+ /// optional hashed password file with constant length as byte array
/// true if length matches the expectations and password file could be written
///
///
@@ -198,33 +295,36 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
if (!SetHashedPwdFile(hashedPwdFile)) return false;
}
- if (_hashedPasswordFile != null && _meterFile != null && _genesisMeter != null
- && _genesisMeter.IsLoggedOn && _hashedPasswordFile.Length == MeterPwdDb.PwdFileLength)
+ if (HashedPasswordFile != null && _meterFile != null && _genesisMeter != null
+ && _genesisMeter.IsLoggedOn && HashedPasswordFile.Length == MeterPwdDb.PwdFileLength)
{
- return _meterFile.WriteMeterFile(StrPasswordFileName, _hashedPasswordFile);
+ return _meterFile.WriteMeterFile(StrPasswordFileName, HashedPasswordFile);
}
return false;
}
///
- /// Verify Meter password file
- /// generated passowrd file has to be present
+ /// Verify Meter password file.
+ /// optional hashed password file with constant length as byte array
+ /// true if the read value is identical with the preset or given hashed value
///
///
- ///
+ ///
/// - Initial.
///
- public Boolean VerifyMeterPwdFile()
+ public Boolean VerifyMeterPwdFile(Byte[] hashedPwdFile = null)
{
- if (_hashedPasswordFile == null)
+ if (hashedPwdFile != null)
+ {
+ if (!SetHashedPwdFile(hashedPwdFile)) return false;
+ }
+ if (HashedPasswordFile == null)
{
return false;
}
-
- return _meterFile.VerifyMeterFile(StrPasswordFileName, _hashedPasswordFile);
-
+ return _meterFile.VerifyMeterFile(StrPasswordFileName, HashedPasswordFile);
}
///
diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdDb.cs b/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdDb.cs
index bfd7194b..591379e8 100644
--- a/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdDb.cs
+++ b/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdDb.cs
@@ -16,9 +16,24 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd
public class MeterPwdDb
{
///
- /// password file length is 160 bytes (8 passwords a 20 bytes SHA1)
+ /// 8 passwords needed for clear the text passwords ans the password file
///
- public const Int32 PwdFileLength = 160;
+ public const Int32 PwdLevels = 8;
+
+ ///
+ /// Each password will generate a 20 bytes hash constant due to SHA1 algorithm
+ ///
+ public const Int32 HashedPwdLength = 20;
+
+ ///
+ /// password file length is 160 bytes (8 passwords a 20 bytes hashed)
+ ///
+ public const Int32 PwdFileLength = PwdLevels * HashedPwdLength;
+
+ ///
+ /// 8 passwords needed for the password file
+ ///
+ public const Int32 ClearTextPwdLength = 12;
///
/// Skeleton key index in password list.
@@ -60,7 +75,7 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd
///
public List ListOfPasswords = new List();
///
- /// Ident for password server (BSI) can be radioaddress or pcbid
+ /// Ident for password server (BSI) can be radio address or pcbid
///
public String PasswordFileIdent { get; set; }
///
diff --git a/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdHandlerDb.cs b/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdHandlerDb.cs
index 6e8d41e4..785ab928 100644
--- a/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdHandlerDb.cs
+++ b/Common/Hardware/WaterMeter/Genesis/GenesisPwd/MeterPwdHandlerDb.cs
@@ -56,7 +56,10 @@ namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd
}
///
- /// Collect order number, radio address, skeleton key, password hashes and passwords from DB.
+ /// Overwrites the (production) password used for production in DB.
+ /// Initially this (production) password is set to the skeletonKey as the password file is not installed.
+ /// After installation of the password file the (production) password has to be set to the level 8 password
+ /// being able to access the meter with the production tools and the GTB.
///
/// input the PcbId
/// output of passwordContainer
diff --git a/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionCheckShippingState.cs b/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionCheckShippingState.cs
index 163b4d9f..1921566b 100644
--- a/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionCheckShippingState.cs
+++ b/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionCheckShippingState.cs
@@ -154,6 +154,7 @@ namespace ProductionUiCordonel.ProductionProcesses.Actions
throw;
}
//;
+ //TODO ROLAND only new meters can be tested which have a LUT installed
if (Meter.LutCrc != $@"0x{int.Parse(res[8]):X4}")
{
currentProcessState = ProductionProcessState.Error;
diff --git a/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionProcessPasswordFile.cs b/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionProcessPasswordFile.cs
index 9d77e116..c9c7ba43 100644
--- a/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionProcessPasswordFile.cs
+++ b/Common/ProductionUiCordonel/ProductionProcesses/Actions/ProductionProcessPasswordFile.cs
@@ -135,8 +135,17 @@ namespace ProductionUiCordonel.ProductionProcesses.Actions
#region realWork
public Boolean CreatePasswordFile()
{
- _meterPwdFile = new MeterPwdFile(Meter);
- return _meterPwdFile.BuildPwdFile(_pwdContainer.ListOfPasswords, 1, _pwdContainer.Skeleton);
+ try
+ {
+ _meterPwdFile = new MeterPwdFile(Meter);
+ return _meterPwdFile.BuildPwdFile(_pwdContainer.ListOfPasswords, 1, _pwdContainer.Skeleton);
+ }
+ catch (Exception e)
+ {
+ // log error message of wrong generated password file
+ NewStatus(e.Message);
+ return false;
+ }
}
public Boolean WriteAndVerifyPasswordFileToMeter()
{
diff --git a/Common/Ui/GenesisToolBox/frmPassword.Designer.cs b/Common/Ui/GenesisToolBox/frmPassword.Designer.cs
index fe2f68dd..c22ea105 100644
--- a/Common/Ui/GenesisToolBox/frmPassword.Designer.cs
+++ b/Common/Ui/GenesisToolBox/frmPassword.Designer.cs
@@ -32,7 +32,7 @@
this.btnGet = new System.Windows.Forms.Button();
this.btnSet = new System.Windows.Forms.Button();
this.txtPcbID = new System.Windows.Forms.TextBox();
- this.txtPassword = new System.Windows.Forms.TextBox();
+ this.txtSkeletonKey = new System.Windows.Forms.TextBox();
this.lblPcbID = new System.Windows.Forms.Label();
this.label1 = new System.Windows.Forms.Label();
this.grpSetup = new System.Windows.Forms.GroupBox();
@@ -84,13 +84,13 @@
this.txtPcbID.TabIndex = 2;
this.txtPcbID.TextChanged += new System.EventHandler(this.txtPcbID_TextChanged);
//
- // txtPassword
+ // txtSkeletonKey
//
- this.txtPassword.Location = new System.Drawing.Point(118, 67);
- this.txtPassword.Name = "txtPassword";
- this.txtPassword.Size = new System.Drawing.Size(102, 20);
- this.txtPassword.TabIndex = 3;
- this.txtPassword.TextChanged += new System.EventHandler(this.txtPassword_TextChanged);
+ this.txtSkeletonKey.Location = new System.Drawing.Point(118, 67);
+ this.txtSkeletonKey.Name = "txtSkeletonKey";
+ this.txtSkeletonKey.Size = new System.Drawing.Size(102, 20);
+ this.txtSkeletonKey.TabIndex = 3;
+ this.txtSkeletonKey.TextChanged += new System.EventHandler(this.txtPassword_TextChanged);
//
// lblPcbID
//
@@ -203,7 +203,7 @@
this.grpDataBase.Controls.Add(this.barProgressDb);
this.grpDataBase.Controls.Add(this.label1);
this.grpDataBase.Controls.Add(this.lblPcbID);
- this.grpDataBase.Controls.Add(this.txtPassword);
+ this.grpDataBase.Controls.Add(this.txtSkeletonKey);
this.grpDataBase.Controls.Add(this.txtPcbID);
this.grpDataBase.Controls.Add(this.btnSet);
this.grpDataBase.Controls.Add(this.btnGet);
@@ -303,7 +303,7 @@
private System.Windows.Forms.Button btnGet;
private System.Windows.Forms.Button btnSet;
private System.Windows.Forms.TextBox txtPcbID;
- private System.Windows.Forms.TextBox txtPassword;
+ private System.Windows.Forms.TextBox txtSkeletonKey;
private System.Windows.Forms.Label lblPcbID;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.GroupBox grpSetup;
diff --git a/Common/Ui/GenesisToolBox/frmPassword.cs b/Common/Ui/GenesisToolBox/frmPassword.cs
index 34cebccc..b403c0c2 100644
--- a/Common/Ui/GenesisToolBox/frmPassword.cs
+++ b/Common/Ui/GenesisToolBox/frmPassword.cs
@@ -104,14 +104,15 @@ namespace Xylem.Common.Ui.GenesisToolBox
}
var responseJson = sr.ReadToEnd();
//TODO THW hide skeleton key if read from DB
- txtPassword.Text = responseJson.Trim('"');
+ //txtSkeletonKey.Text = responseJson.Trim('"');
+ txtSkeletonKey.Text = a.Skeleton;
txtLvl8.Text = autoPassword;
lblConnectDb.Text = @"Connected to PWD DB";
lblConnectDb.ForeColor = Color.Green;
////TODO TEST ONLY remove here _isReadyPasswordFile
_isReadyPasswordFile = true;
- btnWritePwdFile.Enabled = true;
+ //btnWritePwdFile.Enabled = true;
////TODO remove until here
}));
@@ -140,7 +141,7 @@ namespace Xylem.Common.Ui.GenesisToolBox
var passwordSetServiceUrl = ServiceUrls.GenesisSetPasswordServiceUrl();
#pragma warning restore CS0618 // Type or member is obsolete
var http = (HttpWebRequest)WebRequest.Create(passwordSetServiceUrl + txtPcbID.Text
- + "&Password=" + txtPassword.Text);
+ + "&Password=" + txtSkeletonKey.Text);
var response = (HttpWebResponse)http.GetResponse();
var responseStream = response.GetResponseStream();
if (responseStream == null)
@@ -250,7 +251,7 @@ namespace Xylem.Common.Ui.GenesisToolBox
lblConnectPcb.Text = StrNotConnected;
lblConnectPcb.ForeColor = Color.Red;
txtPcbID.Text = "";
- txtPassword.Text = "";
+ txtSkeletonKey.Text = "";
btnGet.Enabled = false;
btnSet.Enabled = false;
if (!string.IsNullOrEmpty(cbComSlot.SelectedItem.ToString()) &&
@@ -324,7 +325,7 @@ namespace Xylem.Common.Ui.GenesisToolBox
lblConnectDb.ForeColor = Color.Red;
btnConnect.Enabled = true;
txtPcbID.Text = "";
- txtPassword.Text = "";
+ txtSkeletonKey.Text = "";
btnGet.Enabled = false;
btnSet.Enabled = false;
btnWritePwdFile.Enabled = false;
@@ -343,13 +344,13 @@ namespace Xylem.Common.Ui.GenesisToolBox
}
lblConnectDb.Text = StrNotConnected;
lblConnectDb.ForeColor = Color.Red;
- txtPassword.Text = "";
+ txtSkeletonKey.Text = "";
}
private void txtPassword_TextChanged(Object sender, EventArgs e)
{
//setting is only allowed if genesis is not connected
- if (txtPcbID.Text.Length > 7 && txtPassword.Text.Length == 12
+ if (txtPcbID.Text.Length > 7 && txtSkeletonKey.Text.Length == 12
&& lblConnectPcb.Text == StrNotConnected)
{
btnSet.Enabled = true;