using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisCore;
using Xylem.Common.Hardware.WaterMeter.Genesis.GenesisPwd;
namespace Xylem.Common.Hardware.WaterMeter.Genesis.GenesisFile
{
///
/// Password file operations
///
public class MeterPwdFile
{
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;
///
/// Ctor
///
///
///
/// - Initial.
///
public MeterPwdFile(GenesisMeter genesisMeter)
{
_genesisMeter = genesisMeter;
_meterFile = new MeterFile(_genesisMeter);
}
///
/// Set the already hashed password file if this is already pre-generated.
/// This is the preparation to the .
/// The password file has a unique length of .
///
/// hashed password file with constant length as byte array
///
/// true if length matches the expectations
///
/// - Initial.
///
public Boolean SetHashedPwdFile(Byte[] hashedPwdFile)
{
if (MeterPwdDb.PwdFileLength != hashedPwdFile.Length) return false;
_hashedPasswordFile = new Byte[hashedPwdFile.Length];
_hashedPasswordFile = hashedPwdFile;
return true;
}
/////
///// Build the password file out of the clear text passwords and the processor UID,
///// password Level 3 has to be build out of the Processor UID.
/////
///// 7 sorted passwords levels: 1, 2, 4, 5, 6, 7, 8
///// unique ID of processor used for password level 3
///// SkeletonKey from data base for comparison
/////
/////
///// - Initial.
/////
/////
///// - Insert of Level 3 password with skeletonKey,
///// - SHA 1 of passwords.
/////
/////
///// - .
/////
/////
///// - Set Level 3 password to modified from processor UID,
///// - Removed skeletonKey as this cannot be used here!
/////
/////
///// - Set Level 3 password to dbSkeletonKey if processorUid is unknown (processorUid == 1)!
/////
//public Boolean BuildPwdFile(List pwdLevels, UInt64 processorUid, String dbSkeletonKey)
//{
// if (pwdLevels.Count != PwdLevels || processorUid == 0 ||
// string.IsNullOrEmpty(dbSkeletonKey) && processorUid == 1)
// {
// return false;
// }
// // selective Level 3 password
// if (processorUid == 1 && !string.IsNullOrEmpty(dbSkeletonKey))
// {
// pwdLevels.Insert(2, Encoding.UTF8.GetBytes(dbSkeletonKey));
// }
// else
// {
// pwdLevels.Insert(2,Encoding.UTF8.GetBytes(BuildLevel3Pwd(processorUid)));
// }
// var ret = new List();
// foreach (var keyLvl in pwdLevels)
// {
// using (var sha1 = new System.Security.Cryptography.SHA1Managed())
// {
// var hash = sha1.ComputeHash(keyLvl);
// ret.AddRange(hash.ToList());
// }
// }
// _hashedPasswordFile = ret.ToArray();
// return true;
//}
///
/// Build the password file out of the clear text passwords.
/// The Level 3 password is already preset.
///
/// 8 sorted passwords levels: 1, 2, 3, 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)
{
if (!Encoding.UTF8.GetBytes(dbSkeletonKey).SequenceEqual(pwdLevels[2]))
{
throw new ApplicationException("Level 3 Password is unequal to the old Data Base Content!");
}
var ret = new List();
foreach (var keyLvl in pwdLevels)
{
using (var sha1 = new System.Security.Cryptography.SHA1Managed())
{
var hash = sha1.ComputeHash(keyLvl);
ret.AddRange(hash.ToList());
}
}
_hashedPasswordFile = ret.ToArray();
return true;
}
///
/// Build skeleton key out of unique processor Id
///
///
///
///
/// - Initial.
///
public static String BuildSkeletonKey(UInt64 processorUid)
{
return $"{(UInt16)((processorUid >> 48) ^ (processorUid >> 32)):X4}" +
$"{(UInt32)((processorUid >> 16) ^ processorUid):X8}";
}
///
/// Build level 3 password out of unique processor Id
///
///
///
///
/// - Initial.
///
public static String BuildLevel3Pwd(UInt64 processorUid)
{
//password level 3 algorithm
return $"{(UInt16)((processorUid >> 48) ^ processorUid):X4}" +
$"{(UInt32)((processorUid >> 32) ^ processorUid):X8}";
}
///
/// 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
///
/// true if length matches the expectations and password file could be written
///
///
/// - Initial.
///
///
/// - Modified to take optional hashed password file as input.
///
public Boolean WriteMeterPwdFile(Byte[] hashedPwdFile = null)
{
if (hashedPwdFile != null)
{
if (!SetHashedPwdFile(hashedPwdFile)) return false;
}
if (_hashedPasswordFile != null && _meterFile != null && _genesisMeter != null
&& _genesisMeter.IsLoggedOn && _hashedPasswordFile.Length == MeterPwdDb.PwdFileLength)
{
return _meterFile.WriteMeterFile(StrPasswordFileName, _hashedPasswordFile);
}
return false;
}
///
/// Verify Meter password file
/// generated passowrd file has to be present
///
///
///
/// - Initial.
///
public Boolean VerifyMeterPwdFile()
{
if (_hashedPasswordFile == null)
{
return false;
}
return _meterFile.VerifyMeterFile(StrPasswordFileName, _hashedPasswordFile);
}
///
/// Erase the meter password file
///
///
///
/// - Initial.
///
public Boolean EraseMeterPwdFile()
{
if (_meterFile != null && _genesisMeter != null && _genesisMeter.IsLoggedOn)
{
return _meterFile.EraseMeterFile(StrPasswordFileName);
}
return false;
}
///
/// Unlock access to password file for write and erase
///
///
///
/// - Initial.
///
public Boolean UnlockEraseWriteMeterPwdFile()
{
if (_meterFile != null && _genesisMeter != null && _genesisMeter.IsLoggedOn)
{
return _meterFile.UnlockEraseWriteMeterFile(StrPasswordFileName);
}
return false;
}
}
}