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 { /// /// AyaNova .net key reader and validator /// Used to rehydrate a key from a past key for add-on / subscription renewal etc /// 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(""); 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(""); int nEnd = Key.IndexOf(""); 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 + (("").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 //Braintek, case "mpBdutEgT9w8hWT/T1uwNmLGeLQ=": //MCCAIN RESEARCH LAB , INC, case "2pYzGIlMU18QomByUC4D72ViOyE=": //Standby Power System Consultants, Inc., case "PlzMfZoVI4iR0Ws11yqaAf+4g5U=": //Snyder Services, case "EMmFEcwm78pskcWAIZ7z5CKdOxk=": #endregion #region Case 874 //Vrobel's Heating & Cooling, case "dhkBn04QOYxysTnXTql/9VHkEtI=": #endregion #region Case 1167 //Verhoeven kantoortotaal case "b75SpAQzm71JsRLNtosk0ty1Tsw=": #endregion #region Case 1191 // CF Can Group case "i9/LC/6RVsoIT1X5YKlzBRA2T08=": #endregion #region Case 1364 // Leavenworth County case "W2inW3VDw8FPzMdBHgE8k+U6gSg=": // mbernardinelli case "13OUStnOVvlJszgrUIcVxMcLkhw=": // Penney Lawn Service case "OSQOreX+pT0TczLrxb6ucOv4rF8=": #endregion #region Case 1862 // Morris Waterworks 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 /// /// Extract string between tokens /// /// /// /// /// 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 } }