Files
ayanova7/keys/Generator/KeyRead.cs
2018-06-29 19:47:36 +00:00

685 lines
24 KiB
C#

using System;
using System.IO;
using System.Xml;
using System.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Data;
//JSON KEY
using System.Text;
using Newtonsoft.Json;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
namespace GroundZero.KeyCodes
{
/// <summary>
/// AyaNova .net key reader and validator
/// Used to rehydrate a key from a past key for add-on / subscription renewal etc
/// </summary>
public class KeyReader
{
private bool _IsValid;
private string _RegisteredTo;
private int _ScheduleableUsers;
// private bool _FeatureWebInterface;
private object _Expires;
private string _status;
private DateTime _Generated;
private DateTime _InstallableUntil;
private bool _Installable;
private double _SchemaVersion;
//private bool _FeatureMBIInterface;
private bool _RequestedTrial;
private DataTable dtPlugins;
private bool _Lite;
private bool _SubscriptionLicense;
private bool _Lockout;
private DateTime _LockoutDate;
public string RegisteredTo
{
get
{
return _RegisteredTo;
}
}
public string Status
{
get
{
return _status;
}
}
public int ScheduleableUsers
{
get
{
return _ScheduleableUsers;
}
}
public bool IsValid
{
get
{
return _IsValid;
}
}
public DateTime Generated
{
get
{
return _Generated;
}
}
public object Expires
{
get
{
return _Expires;
}
}
public DateTime InstallableUntil
{
get
{
return _InstallableUntil;
}
}
public bool Installable
{
get
{
return _Installable;
}
}
public double SchemaVersion
{
get
{
return _SchemaVersion;
}
}
public bool RequestedTrial
{
get
{
return _RequestedTrial;
}
}
public DataTable Plugins
{
get
{
return dtPlugins;
}
}
public bool Lite
{
get
{
return _Lite;
}
}
public bool SubscriptionLicense
{
get
{
return _SubscriptionLicense;
}
}
public bool Lockout
{
get
{
return _Lockout;
}
}
public DateTime LockoutDate
{
get
{
return _LockoutDate;
}
}
public KeyReader(string Key)
{
_IsValid = false;
// _FeatureWebInterface = false;
_Installable = false;
this._RegisteredTo = "";
this._ScheduleableUsers = 0;
this._SchemaVersion = 0;
this._status = "";
this._Expires = System.DateTime.Now;
_RequestedTrial = false;
this._SubscriptionLicense = false;//default for old license processing
_Lockout = false;
_LockoutDate = DateTime.MaxValue;
dtPlugins = new DataTable();
dtPlugins.Columns.Add("Plugin");
dtPlugins.Columns.Add("Version");
//case 2094
dtPlugins.Columns.Add("SubscriptionExpires");
_Installable = false;
//Ensure we have a key and strip out any unnecessary text
string sKeyType = "AyaNovaLiteLicenseKey";
_Lite = true;
if (Key.Contains("AyaNovaLicenseKey"))
{
sKeyType = "AyaNovaLicenseKey";
_Lite = false;
}
bool containsXML = Key.Contains("<?xml version=\"1.0\" encoding=\"utf-16\" standalone=\"yes\"?>");
bool containsJSON = Key.Contains("[KEY");
if (!containsXML && !containsJSON)
{
_IsValid = false;
_status = "Error: could not find license key in text provided";
return;
}
if (containsXML)
{
#region PARSE XML KEY
int nStart = Key.IndexOf("<?xml version=\"1.0\" encoding=\"utf-16\" standalone=\"yes\"?>");
int nEnd = Key.IndexOf("</" + sKeyType + ">");
if (nEnd == -1 || nStart == -1 || nEnd < nStart)
{
_IsValid = false;
_status = "Error: could not find license XML in license key provided";
return;
}
Key = Key.Substring(nStart, (nEnd + (("</" + sKeyType + ">").Length)) - nStart);
//validate key signature then get settings within key
// Get the XML content from the embedded XML public key.
Stream s = null;
string xmlkey = string.Empty;
try
{
// System.Reflection.Assembly ass=System.Reflection.Assembly.GetExecutingAssembly();
// string [] items=ass.GetManifestResourceNames();
// foreach(string ss in items)
// {
// string xy=ss;
// string ab=xy;
//
// }
System.Reflection.Assembly a = typeof(KeyReader).Assembly;
s = a.GetManifestResourceStream("GroundZero.KeyCodes.pubkey.xml");
// Read-in the XML content.
StreamReader reader = new StreamReader(s);
xmlkey = reader.ReadToEnd();
reader.Close();
}
catch (Exception ex)
{
_IsValid = false;
_status = "Error: could not import public key. " + ex.Message + "\r\n" + ex.InnerException;
return;
}
// Create an RSA crypto service provider from the embedded
// XML document resource (the public key).
RSACryptoServiceProvider csp = new RSACryptoServiceProvider();
csp.FromXmlString(xmlkey);
// Load the signed XML license file.
XmlDocument xmldoc = new XmlDocument();
try
{
xmldoc.LoadXml(Key);
}
catch (Exception ex)
{
_IsValid = false;
_status = "Error: exception in LoadXml:\r\n." + ex.Message + "\r\n" + ex.InnerException;
return;
}
// Create the signed XML object.
SignedXml sxml = new SignedXml(xmldoc);
try
{
// Get the XML Signature node and load it into the signed XML object.
XmlNode dsig = xmldoc.GetElementsByTagName("Signature",
SignedXml.XmlDsigNamespaceUrl)[0];
sxml.LoadXml((XmlElement)dsig);
}
catch (Exception ex)
{
_IsValid = false;
_status = "Error: no signature found." + ex.Message + "\r\n" + ex.InnerException;
return;
}
// Verify the signature.
if (!sxml.CheckSignature(csp))
{
_IsValid = false;
_status = "Error: Signature not valid, key has been tampered with.";
return;
}
_IsValid = true;
try
{
_SchemaVersion = XmlConvert.ToDouble(xmldoc.SelectSingleNode("/" + sKeyType + "/SchemaVersion").InnerText);
_RegisteredTo = xmldoc.SelectSingleNode("/" + sKeyType + "/RegisteredTo").InnerText;
_ScheduleableUsers = XmlConvert.ToInt32(xmldoc.SelectSingleNode("/" + sKeyType + "/TotalScheduleableUsers").InnerText);
_Generated = XmlConvert.ToDateTime(xmldoc.SelectSingleNode("/" + sKeyType + "/Created").InnerText, XmlDateTimeSerializationMode.Local);
_InstallableUntil = XmlConvert.ToDateTime(xmldoc.SelectSingleNode("/" + sKeyType + "/InstallableUntil").InnerText, XmlDateTimeSerializationMode.Local);
#region Revoked key check
string DigestValue = xmldoc.GetElementsByTagName("DigestValue")[0].InnerText;
switch (DigestValue)
{
#region Case 428
//<RegisteredTo>Braintek</RegisteredTo>,
case "mpBdutEgT9w8hWT/T1uwNmLGeLQ=":
//<RegisteredTo>MCCAIN RESEARCH LAB , INC</RegisteredTo>,
case "2pYzGIlMU18QomByUC4D72ViOyE=":
//<RegisteredTo>Standby Power System Consultants, Inc.</RegisteredTo>,
case "PlzMfZoVI4iR0Ws11yqaAf+4g5U=":
//<RegisteredTo>Snyder Services</RegisteredTo>,
case "EMmFEcwm78pskcWAIZ7z5CKdOxk=":
#endregion
#region Case 874
//<RegisteredTo>Vrobel's Heating & Cooling</RegisteredTo>,
case "dhkBn04QOYxysTnXTql/9VHkEtI=":
#endregion
#region Case 1167
//<RegisteredTo>Verhoeven kantoortotaal</RegisteredTo>
case "b75SpAQzm71JsRLNtosk0ty1Tsw=":
#endregion
#region Case 1191
// <RegisteredTo>CF Can Group</RegisteredTo>
case "i9/LC/6RVsoIT1X5YKlzBRA2T08=":
#endregion
#region Case 1364
// <RegisteredTo>Leavenworth County</RegisteredTo>
case "W2inW3VDw8FPzMdBHgE8k+U6gSg=":
// <RegisteredTo>mbernardinelli</RegisteredTo>
case "13OUStnOVvlJszgrUIcVxMcLkhw=":
// <RegisteredTo>Penney Lawn Service</RegisteredTo>
case "OSQOreX+pT0TczLrxb6ucOv4rF8=":
#endregion
#region Case 1862
// <RegisteredTo>Morris Waterworks</RegisteredTo>
case "8lPDmvrFCHnVxUDGzscSZKmGtgM=":
#endregion
_IsValid = false;
_status = "Error: Key is not valid due to NON-PAYMENT revoke list.";
return;
}
#endregion revoked key check
if (xmldoc.SelectSingleNode("/" + sKeyType + "/Expires") != null)
_Expires = XmlConvert.ToDateTime(xmldoc.SelectSingleNode("/" + sKeyType + "/Expires").InnerText, XmlDateTimeSerializationMode.Local);
else
_Expires = null;
//Case 999
if (xmldoc.SelectSingleNode("/" + sKeyType + "/RequestedTrial") != null)
_RequestedTrial = XmlConvert.ToBoolean(xmldoc.SelectSingleNode("/" + sKeyType + "/RequestedTrial").InnerText);
else
_RequestedTrial = false;
//Case 2094
if (xmldoc.SelectSingleNode("/" + sKeyType + "/Sub") != null)
_SubscriptionLicense = XmlConvert.ToBoolean(xmldoc.SelectSingleNode("/" + sKeyType + "/Sub").InnerText);
else
{
_SubscriptionLicense = false;
//default expiry to yesterday on v7 keys forcing new date to be selected in UI
_Expires = DateTime.Now.AddDays(-1);
}
//case 2094
if (xmldoc.SelectSingleNode("/" + sKeyType + "/LockDate") != null)
{
_Lockout = true;
_LockoutDate = XmlConvert.ToDateTime(xmldoc.SelectSingleNode("/" + sKeyType + "/LockDate").InnerText, XmlDateTimeSerializationMode.Local);
}
else
{
_Lockout = false;
_LockoutDate = DateTime.MaxValue;
}
//Case 2094
//deal with v7.3 licenses WBI
bool hasv7wbi = false;
if (!_SubscriptionLicense)
{
if (xmldoc.SelectSingleNode("/" + sKeyType + "/FeatureWebBrowserInterface") != null)
hasv7wbi = XmlConvert.ToBoolean(xmldoc.SelectSingleNode("/" + sKeyType + "/FeatureWebBrowserInterface").InnerText);
else
{
hasv7wbi = false;
//default expiry to yesterday on v7 keys forcing new date to be selected in UI
_Expires = DateTime.Now.AddDays(-1);
}
}
if (hasv7wbi)
{
//add it as a v7.4 plugin
DataRow dr = dtPlugins.NewRow();
dr["Plugin"] = "WBI - Web browser interface";
dr["SubscriptionExpires"] = DateTime.Now.AddDays(-1);
dtPlugins.Rows.Add(dr);
}
//Case 2094
//deal with v7.3 license MBI
bool hasv7mbi = false;
if (!_SubscriptionLicense)
{
if (xmldoc.SelectSingleNode("/" + sKeyType + "/FeatureMBIInterface") != null)
hasv7mbi = XmlConvert.ToBoolean(xmldoc.SelectSingleNode("/" + sKeyType + "/FeatureMBIInterface").InnerText);
else
{
hasv7mbi = false;
//default expiry to yesterday on v7 keys forcing new date to be selected in UI
_Expires = DateTime.Now.AddDays(-1);
}
}
if (hasv7mbi)
{
//add it as a v7.4 plugin
DataRow dr = dtPlugins.NewRow();
dr["Plugin"] = "MBI - Minimal browser interface";
dr["SubscriptionExpires"] = DateTime.Now.AddDays(-1);
dtPlugins.Rows.Add(dr);
}
//case 1053 plugins
XmlNodeList plugs = xmldoc.SelectNodes("//Plugin");
if (plugs != null && plugs.Count > 0)
{
foreach (XmlNode n in plugs)
{
DataRow dr = dtPlugins.NewRow();
dr["Plugin"] = n.SelectSingleNode("Item").InnerText;
//case 2094 SubscriptionExpires key
if (_SubscriptionLicense)
{
if (n.SelectSingleNode("SubscriptionExpires") != null)
dr["SubscriptionExpires"] = XmlConvert.ToDateTime(n.SelectSingleNode("SubscriptionExpires").InnerText, XmlDateTimeSerializationMode.Local);
}
else
{
dr["Version"] = n.SelectSingleNode("Version").InnerText;
//default expiry to yesterday on v7 keys forcing new date to be selected in UI
dr["SubscriptionExpires"] = DateTime.Now.AddDays(-1);
}
dtPlugins.Rows.Add(dr);
}
}
// ETC
_Installable = true;
}
catch (Exception ex)
{
_IsValid = false;
_status = "Error: Signature not valid - exception processing fields:\r\n." + ex.Message + "\r\n" + ex.InnerException;
return;
}
#endregion read XML format key
}
else
{
#region PARSE JSON KEY
string licenseFileData = Key;
//extract between [KEY and KEY]
if (!licenseFileData.Contains("[KEY") ||
!licenseFileData.Contains("KEY]") ||
!licenseFileData.Contains("[SIGNATURE") ||
!licenseFileData.Contains("SIGNATURE]"))
throw new System.FormatException("KEY IS NOT VALID! Missing one or more required delimiters");
string keyNoWS = System.Text.RegularExpressions.Regex.Replace(ExtractString(licenseFileData, "[KEY", "KEY]").Trim(), "(\"(?:[^\"\\\\]|\\\\.)*\")|\\s+", "$1");
string keySig = ExtractString(licenseFileData, "[SIGNATURE", "SIGNATURE]").Trim();
#region Check Signature
//***** NOTE: this is our real 2016 public key
var publicPem = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz7wrvLDcKVMZ31HFGBnL
WL08IodYIV5VJkKy1Z0n2snprhSiu3izxTyz+SLpftvKHJpky027ii7l/pL9Bo3J
cjU5rKrxXavnE7TuYPjXn16dNLd0K/ERSU+pXLmUaVN0nUWuGuUMoGJMEXoulS6p
JiG11yu3BM9fL2Nbj0C6a+UwzEHFmns3J/daZOb4gAzMUdJfh9OJ0+wRGzR8ZxyC
99Na2gDmqYglUkSMjwLTL/HbgwF4OwmoQYJBcET0Wa6Gfb17SaF8XRBV5ZtpCsbS
tkthGeoXZkFriB9c1eFQLKpBYQo2DW3H1MPG2nAlQZLbkJj5cSh7/t1bRF08m6P+
EQIDAQAB
-----END PUBLIC KEY-----";
PemReader pr = new PemReader(new StringReader(publicPem));
var KeyParameter = (Org.BouncyCastle.Crypto.AsymmetricKeyParameter)pr.ReadObject();
var signer = SignerUtilities.GetSigner("SHA256WITHRSA");
signer.Init(false, KeyParameter);
var expectedSig = Convert.FromBase64String(keySig);
var msgBytes = Encoding.UTF8.GetBytes(keyNoWS);
signer.BlockUpdate(msgBytes, 0, msgBytes.Length);
if (!signer.VerifySignature(expectedSig))
{
_IsValid = false;
_status = "Error: Signature not valid, key has been tampered with.";
return;
}
#endregion check signature
//valid key (has valid signature)
_IsValid = true;
try
{
#region Get Values
Newtonsoft.Json.Linq.JToken token = Newtonsoft.Json.Linq.JObject.Parse(keyNoWS);
_SchemaVersion = (double)token.SelectToken(sKeyType + ".SchemaVersion");
_RegisteredTo = (string)token.SelectToken(sKeyType + ".RegisteredTo");
_ScheduleableUsers = (int)token.SelectToken(sKeyType + ".TotalScheduleableUsers");
_Generated = (DateTime)token.SelectToken(sKeyType + ".Created");
_InstallableUntil = (DateTime)token.SelectToken(sKeyType + ".InstallableUntil");
//REVOKED KEY CHECK HERE IN FUTURE LIKE XML VERSION DOES?
if (token.SelectToken(sKeyType + ".Expires") != null)
{
_Expires = (DateTime)token.SelectToken(sKeyType + ".Expires");
if (((DateTime)_Expires).Year == 1)
throw new System.ArgumentOutOfRangeException("Expires out of range");
}
else
{
_Expires = DateTime.MaxValue;
}
if (token.SelectToken(sKeyType + ".RequestedTrial") != null)
{
_RequestedTrial = (bool)token.SelectToken(sKeyType + ".RequestedTrial");
}
else
{
_RequestedTrial = false;
}
if (token.SelectToken(sKeyType + ".Sub") != null)
{
_SubscriptionLicense = (bool)token.SelectToken(sKeyType + ".Sub");
}
else
{
_SubscriptionLicense = false;
//default expiry to yesterday on v7 keys forcing new date to be selected in UI
_Expires = DateTime.Now.AddDays(-1);
}
if (token.SelectToken(sKeyType + ".LockDate") != null)
{
_Lockout = true;
_LockoutDate = (DateTime)token.SelectToken(sKeyType + ".LockDate");
}
else
{
_LockoutDate = DateTime.MaxValue;
_Lockout = false;
}
//PLUGINS
Newtonsoft.Json.Linq.JArray p = (Newtonsoft.Json.Linq.JArray)token.SelectToken("AyaNovaLicenseKey.Plugins.Plugin");
for (int x = 0; x < p.Count; x++)
{
DataRow dr = dtPlugins.NewRow();
dr["Plugin"] = (string)p[x].SelectToken("Item");
dr["SubscriptionExpires"] = (DateTime)p[x].SelectToken("SubscriptionExpires");
dtPlugins.Rows.Add(dr);
}
_Installable = true;
#endregion get values
}
catch (Exception ex)
{
_IsValid = false;
_status = "Error: Signature not valid - exception processing fields:\r\n." + ex.Message + "\r\n" + ex.InnerException;
return;
}
#endregion parse json key
}
}//end of function
/// <summary>
/// Extract string between tokens
/// </summary>
/// <param name="s"></param>
/// <param name="openTag"></param>
/// <param name="closeTag"></param>
/// <returns></returns>
string ExtractString(string s, string openTag, string closeTag)
{
int startIndex = s.IndexOf(openTag) + openTag.Length;
int endIndex = s.IndexOf(closeTag, startIndex);
return s.Substring(startIndex, endIndex - startIndex);
}
//=======================================
//eoc
}
}