using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Diagnostics;
namespace PhoneHome
{
internal class CheckActiveTwo
{
internal string ProductName = String.Empty;
internal string ProductVersion = String.Empty;
internal string SerialNumber = String.Empty;
private string _LastGeneratedKey = String.Empty;
///
///
///
///
///
///
internal CheckActiveTwo(string ProductName, string ProductVersion, string SerialNumber)
{
if (!String.IsNullOrEmpty(ProductName) && !String.IsNullOrEmpty(ProductVersion) && !String.IsNullOrEmpty(SerialNumber))
{
this.ProductName = ProductName;
this.ProductVersion = ProductVersion;
this.SerialNumber = SerialNumber;
}
else
{
throw new ArgumentException("ProductName, ProductVersion, and SerialNumber can't be blank");
}
}
///
///
///
///
internal CheckActiveTwo(string strEncGeneratedString)
{
if (IsValidEncKey(strEncGeneratedString))
{
_LastGeneratedKey = strEncGeneratedString;
}
else
{
throw new ArgumentException("Not a valid Enc String");
}
}
#region Static Internal Utilities
///
/// Perform checksum on string
///
///
/// Checksum
internal static int PerformChecksum(string strAboutToBeChecksummed)
{
if (!String.IsNullOrEmpty(strAboutToBeChecksummed))
{
int nChecksum = 0;
for (int i = 0; i < strAboutToBeChecksummed.Length; ++i)
{
if (Char.IsDigit(strAboutToBeChecksummed[i]))
nChecksum = nChecksum + int.Parse(strAboutToBeChecksummed[i].ToString());
}
return nChecksum;
}
return 0;
}
///
/// Dash a String
///
///
internal static string MakeIntoDashSeperatedString(string strAboutToBeDashed, int DashEveryNthCharacter)
{
if (!String.IsNullOrEmpty(strAboutToBeDashed))
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < strAboutToBeDashed.Length; i++)
{
if ((i != 0) && ((i % DashEveryNthCharacter) == 0))
sb.Append("-");
sb.Append(strAboutToBeDashed[i]);
}
return sb.ToString();
}
return String.Empty;
}
///
/// Undash a String
///
///
internal static string MakeIntoDashUnseperatedString(string strAboutToBeUndashed)
{
if (!String.IsNullOrEmpty(strAboutToBeUndashed))
return strAboutToBeUndashed.Replace("-", "");
return String.Empty;
}
#endregion
#region Internal Methods
///
/// Generate a new Key to use - the key can be used to verify the serial number
///
/// a new Key
internal string GenerateNewKey()
{
// GenerateString For User to send
string KeyValue = MakeKey();
string EncrKey = EncodeShuffle(KeyValue);
_LastGeneratedKey = MakeIntoDashSeperatedString(EncrKey, 4);
// For Debugging
string UnEncoded = DecodeShuffle(EncrKey);
if (KeyValue != UnEncoded)
{
// something is terribly wrong with the Encryption
Debug.Assert(false);
}
return _LastGeneratedKey;
}
///
/// The function should really be called 'GeneratedPIN' but for reverse engineering
/// purpose, keeping them guessin * security by obscurity *
///
///
internal string GeneraledPiM()
{
if (!String.IsNullOrEmpty(_LastGeneratedKey))
{
int KeyChecksum = PerformChecksum(MakeKey());
int ShuffledChecksum = PerformChecksum(_LastGeneratedKey);
string Result = KeyChecksum.ToString() + ShuffledChecksum.ToString();
if (Result.Length < 4)
{
StringBuilder sb = new StringBuilder(Result);
int nRemainder = 4 - Result.Length;
while (nRemainder > 0) { sb.Append("7"); nRemainder--; }
Result = sb.ToString();
}
Result = Result.Substring(0, 4);
int nHour = DateTime.Now.ToUniversalTime().Hour;
nHour = (nHour <= 6) ? (nHour + 3) : (nHour - 2);
string strHour = String.Format("{0}", (nHour < 10) ? ("8" + nHour.ToString()) : (nHour.ToString()));
string fourdigitPin = (strHour[1] + Result[1].ToString() + strHour[0] + Result[3].ToString());
int nChecksumPin = PerformChecksum(fourdigitPin);
string strChecksumLastDigit = nChecksumPin.ToString()[nChecksumPin.ToString().Length - 1].ToString();
return fourdigitPin + strChecksumLastDigit;
}
else
{
GenerateNewKey();
return GeneraledPiM();
}
}
///
///
///
///
///
///
///
/// true, if successful, false otherwise
internal bool RetrieveValues(out DateTime dtStamp, out string ProductName, out string ProductVersion, out string SerialNumber)
{
dtStamp = DateTime.MinValue;
ProductName = String.Empty;
ProductVersion = String.Empty;
SerialNumber = String.Empty;
if (!String.IsNullOrEmpty(_LastGeneratedKey))
{
string Undashed = MakeIntoDashUnseperatedString(_LastGeneratedKey);
if (UnmakeKey(DecodeShuffle(Undashed), out dtStamp, out ProductName, out ProductVersion, out SerialNumber))
{
this.ProductName = ProductName;
this.ProductVersion = ProductVersion;
this.SerialNumber = SerialNumber;
return true;
}
}
return false;
}
#endregion
#region Private Key Generation Functions
private bool ContainsOnlyDigits(string strToCheckForDigits)
{
if (!String.IsNullOrEmpty(strToCheckForDigits))
{
for (int i = 0; i < strToCheckForDigits.Length; ++i)
{
if (!Char.IsDigit(strToCheckForDigits[i]))
return false;
}
return true;
}
return false;
}
///
/// Check to see if the Generated string being passed in is a valid generated string
///
///
/// true if valid, false otherwise
private bool IsValidEncKey(string strEncGeneratedString)
{
string Undashed = MakeIntoDashUnseperatedString(strEncGeneratedString);
DateTime dt;
string pName, pVersion, pSerial;
if (UnmakeKey(DecodeShuffle(Undashed), out dt, out pName, out pVersion, out pSerial))
return true;
return false;
}
///
/// Make a Key to send across (all the info the auth needs)
///
/// Key with needed Info
private string MakeKey()
{
//string dtShortTest = DateTime.Now.ToUniversalTime().ToShortDateString().Replace("/", "");
DateTime dtUniversal = DateTime.Now.ToUniversalTime();
string dtMonth = (dtUniversal.Month > 9) ? String.Format("{0}", dtUniversal.Month) : String.Format("0{0}", dtUniversal.Month);
string dtDay = (dtUniversal.Day > 9) ? String.Format("{0}", dtUniversal.Day) : String.Format("0{0}", dtUniversal.Day);
string dtYear = dtUniversal.Year.ToString();
string dtShort = String.Format("{0}{1}{2}", dtMonth, dtDay, dtYear);
string ProductId = ProductName.Substring(0, 1); // should always be 'M' or 'L' // so we use "LMXYZ"
string strKey = dtShort + "Z" + ProductId + "Y" + ProductVersion.Split('.')[0] + "X" + SerialNumber;
return strKey;
}
///
/// Unmake a key * Don't even know why i wrote this, prob. won't end up using this *
///
/// true if successful, false otheriwise
private bool UnmakeKey(string strAboutToBeUnkeyed, out DateTime dtStamp, out string ProductName, out string ProductVersion, out string SerialNumber)
{
dtStamp = DateTime.MinValue;
ProductName = "";
ProductVersion = "";
SerialNumber = "";
//string strKey = dtShort + "Z" + ProductId + "Y" + ProductVersion.Split('.')[0] + "X" + SerialNumber;
//0123456Z
try
{
if (!String.IsNullOrEmpty(strAboutToBeUnkeyed))
{
int nZIndex = strAboutToBeUnkeyed.IndexOf("Z");
int nYIndex = strAboutToBeUnkeyed.IndexOf("Y");
int nXIndex = strAboutToBeUnkeyed.IndexOf("X");
if (nZIndex == -1 || nYIndex == -1 || nXIndex == -1)
return false;
// dtShort
string strDT = strAboutToBeUnkeyed.Substring(0, nZIndex);
strDT = String.Format("{0}/{1}/{2}", strDT.Substring(0, 2), strDT.Substring(2, 2), strDT.Substring(4));
dtStamp = DateTime.Parse(strDT);
// ProductId
string ProductId = strAboutToBeUnkeyed.Substring(nZIndex + 1, 1);
if (ProductId == "L")
ProductName = "Lytec";
else if (ProductId == "M")
ProductName = "Medisoft";
else
return false;
// ProductVersion
string strProductVersion = strAboutToBeUnkeyed.Substring(nYIndex + 1, (nXIndex - nYIndex - 1));
if (!String.IsNullOrEmpty(strProductVersion) && ContainsOnlyDigits(strProductVersion))
ProductVersion = strProductVersion;
else
return false;
// Serial Number
SerialNumber = strAboutToBeUnkeyed.Substring(nXIndex + 1);
return !String.IsNullOrEmpty(SerialNumber) && ContainsOnlyDigits(SerialNumber);
}
}
catch (Exception) { /* ignore */ }
return false;
}
///
/// * Simple Encoder *
///
///
///
private string EncodeShuffle(string strAboutToBeEncodeShuffled)
{
const string Char_CodeLib = "ABCDEFGHIJKNOPQRSTUVW"; //20 - W is never used
const string Char_CodeLibExcluded = "LMXYZ"; //5
if (!String.IsNullOrEmpty(strAboutToBeEncodeShuffled))
{
List ResultStr = new List(strAboutToBeEncodeShuffled);
int nCount = ResultStr.Count;
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 3)
{
char c = ResultStr[i];
if (char.IsDigit(c))
{
int nChar = int.Parse(c.ToString());
ResultStr[i] = Char_CodeLib[nChar]; // 0..9
}
}
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 4)
{
char c = ResultStr[i];
if (char.IsDigit(c))
{
int nChar = int.Parse(c.ToString());
ResultStr[i] = Char_CodeLib[nChar + 10]; // 10..19
}
}
// Add Randomness to the end of the string
Random random = new Random();
int nRand = random.Next(1, 9);
// Perform a Random Shift * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + 2)
{
char c = ResultStr[i];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()))
{
int nIndexShifted = Char_CodeLib.IndexOf(c) + nRand;
int nIndexShiftedAdj = nIndexShifted % 21;
ResultStr[i] = Char_CodeLib[nIndexShiftedAdj]; // 0..20
}
}
// Perform another Random Swap * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + nRand)
{
char c = ResultStr[i];
int nOpposite = nCount - i - 1;
char o = ResultStr[nOpposite];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()) &&
char.IsLetter(o) && !Char_CodeLibExcluded.Contains(o.ToString()))
{
// swap
ResultStr[i] = o;
ResultStr[nOpposite] = c;
}
}
// Perform a Reversal
for (int i = 0; i < (nCount / 2); ++i)
{
char N1 = ResultStr[i];
char N2 = ResultStr[nCount - 1 - i];
// swap
ResultStr[i] = N2;
ResultStr[nCount - 1 - i] = N1;
}
// Add the Randomness to the string for proper decoding to occur
ResultStr.Add(Char.Parse(nRand.ToString()));
// And Return
return new String(ResultStr.ToArray());
}
return String.Empty;
}
///
/// * Simple Decoder *
///
///
///
private string DecodeShuffle(string strAboutToBeDecodeShuffled)
{
const string Char_CodeLib = "ABCDEFGHIJKNOPQRSTUVW"; //20
const string Char_CodeLibExcluded = "LMXYZ"; //5
try
{
if (!String.IsNullOrEmpty(strAboutToBeDecodeShuffled))
{
List ResultStr = new List(strAboutToBeDecodeShuffled);
// retrieve Randomness Factor
char cLast = ResultStr[ResultStr.Count - 1];
ResultStr.RemoveAt(ResultStr.Count - 1);
int nCount = ResultStr.Count;
int nRand = int.Parse(cLast.ToString());
// Perform a Reversal
for (int i = 0; i < (nCount / 2); ++i)
{
char N1 = ResultStr[i];
char N2 = ResultStr[nCount - 1 - i];
// swap
ResultStr[i] = N2;
ResultStr[nCount - 1 - i] = N1;
}
// Perform another Random Swap * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + nRand)
{
char c = ResultStr[i];
int nOpposite = nCount - i - 1;
char o = ResultStr[nOpposite];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()) &&
char.IsLetter(o) && !Char_CodeLibExcluded.Contains(o.ToString()))
{
// swap
ResultStr[i] = o;
ResultStr[nOpposite] = c;
}
}
// Perform a Random Shift * So that the code ALWAYS looks different from use to use *
for (int i = 0; i < nCount; i = i + 2)
{
char c = ResultStr[i];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()))
{
int nIndexShifted = Char_CodeLib.IndexOf(c) - nRand;
int nIndexShiftedAdj = (nIndexShifted < 0)? 21 + nIndexShifted : nIndexShifted;
ResultStr[i] = Char_CodeLib[nIndexShiftedAdj]; // 0..20
}
}
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 4)
{
char c = ResultStr[i];
if (char.IsLetter(c) && !Char_CodeLibExcluded.Contains(c.ToString()))
{
int nIndex = Char_CodeLib.IndexOf(c);
if (nIndex >= 10)
{
nIndex = nIndex - 10;
if (nIndex >= 0 && nIndex <= 9)
ResultStr[i] = Char.Parse(nIndex.ToString()); // 11..19
}
}
}
// Every N'th Digit do something
for (int i = 0; i < nCount; i = i + 3)
{
char c = ResultStr[i];
if (char.IsLetter(c))
{
int nIndex = Char_CodeLib.IndexOf(c);
if (nIndex >= 0 && nIndex <= 9)
ResultStr[i] = Char.Parse(nIndex.ToString()); // 1..9
}
}
// And Return
return new String(ResultStr.ToArray());
}
}
catch (Exception) { /* ignore */ }
return String.Empty;
}
#endregion
}
}