using System; using System.Text; using System.Collections.Generic; using System.IO; using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.OpenSsl; using Sockeye.Models; using Sockeye.Util; namespace Sockeye.Biz { //Key generator controller public static class KeyFactory { public const string PLUGIN_MBI_KEY = "MBI - Minimal browser interface"; public const string PLUGIN_WBI_KEY = "WBI - Web browser interface"; public const string PLUGIN_QBI_KEY = "QBI - QuickBooks interface"; public const string PLUGIN_QBOI_KEY = "QBOI - QuickBooks Online interface"; public const string PLUGIN_PTI_KEY = "PTI - US Sage 50/Peachtree interface"; public const string PLUGIN_QUICK_NOTIFICATION_KEY = "QuickNotification"; public const string PLUGIN_EXPORT_TO_XLS_KEY = "ExportToXls"; public const string PLUGIN_OUTLOOK_SCHEDULE_KEY = "OutlookSchedule"; public const string PLUGIN_OLI_KEY = "AyaNovaOLI"; public const string PLUGIN_IMPORT_EXPORT_CSV_DUPLICATE_KEY = "ImportExportCSVDuplicate"; public const string PLUGIN_RI_KEY = "RI - Responsive Interface"; private static Dictionary _plugins; //Generate a key message reply from a key selection object //CALLED BY LicenseController Generate route public static string GetKeyReply(dtoKeyOptions ko, LicenseTemplates t, rockfishContext ct) { //case 3542 ko.installByDate = System.DateTime.Now.AddYears(1);//changed from one month to one year string sKey = genKey(ko, ct); string sMsg = genMessage(sKey, ko, t); return sMsg; } //called by trialkeyrequesthandler.GenerateFromRequest //get a trial key for named regTo public static string GetTrialKey(string regTo, bool lite, LicenseTemplates t, string authorizedUserKeyGeneratorStamp, string emailAddress, rockfishContext ct)//case 3233 { DateTime dtoneMonth = System.DateTime.Now.AddMonths(1); long oneMonth = DateUtil.DateToEpoch(System.DateTime.Now.AddMonths(1)); dtoKeyOptions ko = new dtoKeyOptions(); //case 3233 ko.emailAddress = emailAddress; ko.customerId = 0; //not a customer so trial 0 ko.registeredTo = regTo; ko.supportExpiresDate = oneMonth; ko.isLite = lite; ko.installByDate = dtoneMonth; ko.authorizedUserKeyGeneratorStamp = authorizedUserKeyGeneratorStamp; if (lite) { ko.users = 1; } else { ko.users = 5; } ko.licenseType = "webRequestedTrial"; ko.qbi = true; ko.qbiSupportExpiresDate = oneMonth; ko.qboi = true; ko.qboiSupportExpiresDate = oneMonth; ko.pti = true; ko.ptiSupportExpiresDate = oneMonth; ko.exportToXls = true; ko.exportToXlsSupportExpiresDate = oneMonth; ko.outlookSchedule = true; ko.outlookScheduleSupportExpiresDate = oneMonth; ko.oli = true; ko.oliSupportExpiresDate = oneMonth; ko.importExportCSVDuplicate = true; ko.importExportCSVDuplicateSupportExpiresDate = oneMonth; if (!lite) { ko.quickNotification = true; ko.quickNotificationSupportExpiresDate = oneMonth; ko.mbi = true; ko.mbiSupportExpiresDate = oneMonth; ko.wbi = true; ko.wbiSupportExpiresDate = oneMonth; ko.ri = true; ko.riSupportExpiresDate = oneMonth; } string sKey = genKey(ko, ct); string sMsg = genMessage(sKey, ko, t); return sMsg; } //Take the key and the options and make a return message ready to send private static string genMessage(string sKey, dtoKeyOptions ko, LicenseTemplates template) { string sMessage = ""; if (ko.licenseType == "new") { if (ko.isLite) { sMessage = template.LiteNew; } else { sMessage = template.FullNew; } } else if (ko.licenseType == "addon") { if (ko.isLite) { sMessage = template.LiteAddOn; } else { sMessage = template.FullAddOn; } } else//licensed trial { if (ko.isLite) { sMessage = template.LiteTrial; } else { sMessage = template.FullTrial; } } //token substitutions sMessage = sMessage.Replace("[LicenseExpiryDate]", ko.installByDate.ToString("D"));//https://github.com/dotnet/coreclr/issues/2317 sMessage = sMessage.Replace("[LicenseDescription]", LicenseInfo(ko)); sMessage = sMessage.Replace("[LicenseKey]", sKey); return sMessage; } // Extra info to display about key at top of key message private static string LicenseInfo(dtoKeyOptions ko) { StringBuilder sb = new StringBuilder(); sb.Append("LICENSE DETAILS\r\n"); // sb.Append("This key must be installed before: "); // sb.Append(ko.installByDate.ToString("D")); // sb.Append("\r\n"); //if (kg.SelectedLicenseType == "Web requested trial") //{ // sb.Append("*** This temporary license key has been provided for limited evaluation purposes only *** \r\n"); // sb.Append("This license will expire and AyaNova usage will be restricted after: " + kg.Expires.ToLongDateString() + "\r\n\r\n"); //} if (ko.keyWillLockout) { sb.Append("*** This temporary license key is provided for evaluation use only pending payment ***\r\n"); sb.Append("This license will expire and AyaNova usage will be restricted after: " + DateUtil.EpochToString(ko.lockoutDate) + "\r\n"); sb.Append("\r\n"); sb.Append("A permanent license key will be sent to you when payment \r\n" + "has been received and processed. There will be no extensions or \r\n" + "exceptions. Please send in payment early enough to allow for \r\n" + "mail and processing time to ensure uninterrupted use of AyaNova" + (ko.isLite ? " Lite" : "") + ". \r\n\r\n"); } sb.Append("Registered to: "); sb.Append(ko.registeredTo); sb.Append("\r\n"); //case 3233 sb.Append("Fetch address: "); sb.Append(ko.emailAddress); sb.Append("\r\n"); sb.Append("Fetch code: "); sb.Append(ko.fetchCode); sb.Append("\r\n"); sb.Append("Scheduleable resources: "); switch (ko.users) { case 1: sb.AppendLine("1"); break; case 5: sb.AppendLine("Up to 5"); break; case 10: sb.AppendLine("Up to 10"); break; case 15: sb.AppendLine("Up to 15");//case 3550 break; case 20: sb.AppendLine("Up to 20"); break; case 50: sb.AppendLine("Up to 50"); break; case 999: sb.AppendLine("Up to 999"); break; } sb.AppendLine("Support and updates until: " + DateUtil.EpochToString(ko.supportExpiresDate) + "\r\n"); if (_plugins.Count > 0) { sb.Append("\r\n"); sb.Append("Plugins:\r\n"); foreach (KeyValuePair kv in _plugins) { sb.Append("\t"); sb.Append(kv.Key); sb.Append(" support and updates until: "); sb.Append(kv.Value.ToString("D")); sb.Append("\r\n"); } } return sb.ToString(); } public static string GenFetchCode() { //sufficient for this purpose //https://stackoverflow.com/a/1344258/8939 var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; var stringChars = new char[10]; var random = new Random(); for (int i = 0; i < stringChars.Length; i++) { stringChars[i] = chars[random.Next(chars.Length)]; } var finalString = new String(stringChars); return finalString; } /// /// Generate keycode based on passed in data /// This is called by both regular and trial license key routes /// /// private static string genKey(License l) { _plugins = new Dictionary(); try { StringBuilder sbKey = new StringBuilder(); StringWriter sw = new StringWriter(sbKey); l.FetchCode = GenFetchCode(); using (Newtonsoft.Json.JsonWriter w = new Newtonsoft.Json.JsonTextWriter(sw)) { w.Formatting = Newtonsoft.Json.Formatting.Indented; //outer object start w.WriteStartObject(); w.WritePropertyName("AyaNovaLicenseKey"); w.WriteStartObject();//start of key object w.WritePropertyName("SchemaVersion"); w.WriteValue("7"); //stamp a unique value in the key so it can be revoked later //used to use the digest value of the key for this with xml key //whole unix timestamp seconds but kept as a double to work beyond 2038 w.WritePropertyName("Id"); var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); string sId = vv.ToString(); if (sId.Contains(",")) sId = sId.Split('.')[0]; w.WriteValue(sId); w.WritePropertyName("Created"); w.WriteValue(System.DateTime.Now); w.WritePropertyName("Sub"); w.WriteValue("true"); w.WritePropertyName("RegisteredTo"); w.WriteValue(l.RegTo); //case 3233 w.WritePropertyName("EmailAddress"); w.WriteValue(l.FetchEmail); w.WritePropertyName("FetchCode"); w.WriteValue(l.FetchCode); //case 3187 - Source here //rockfish w.WritePropertyName("Source"); w.WriteValue(StringUtil.ToHex("RFID" + "420")); w.WritePropertyName("InstallableUntil"); w.WriteValue(l.MaintenanceExpire); w.WritePropertyName("TotalScheduleableUsers"); w.WriteValue(l.Users.ToString());//Needs to be a string to match rockfish format w.WritePropertyName("Expires"); w.WriteValue(l.MaintenanceExpire); if (l.LicenseExpire!=null) { w.WritePropertyName("LockDate"); w.WriteValue(l.LicenseExpire); } w.WritePropertyName("RequestedTrial"); w.WriteValue(l.TrialMode.ToString()); //PLUGINS w.WritePropertyName("Plugins"); w.WriteStartObject();//start of key object w.WritePropertyName("Plugin"); w.WriteStartArray(); if (l.MBI) AddLicensePlugin(w, PLUGIN_MBI_KEY, l.MBIExpires); if (l.WBI) AddLicensePlugin(w, PLUGIN_WBI_KEY, l.WBIExpires); if (l.QBI) AddLicensePlugin(w, PLUGIN_QBI_KEY, l.QBIExpires); if (l.QBOI) AddLicensePlugin(w, PLUGIN_QBOI_KEY, l.QBOIExpires); if (l.PTI) AddLicensePlugin(w, PLUGIN_PTI_KEY, l.PTIExpires); if (l.QuickNotification) AddLicensePlugin(w, PLUGIN_QUICK_NOTIFICATION_KEY, l.QuickNotificationExpires); if (l.ExportToXLS) AddLicensePlugin(w, PLUGIN_EXPORT_TO_XLS_KEY, l.ExportToXLSExpires); if (l.OutlookSchedule) AddLicensePlugin(w, PLUGIN_OUTLOOK_SCHEDULE_KEY, l.OutlookScheduleExpires); if (l.OLI) AddLicensePlugin(w, PLUGIN_OLI_KEY, l.OLIExpires); if (l.ImportExportCSVDuplicate) AddLicensePlugin(w, PLUGIN_IMPORT_EXPORT_CSV_DUPLICATE_KEY, l.ImportExportCSVDuplicateExpires); if (l.RI) AddLicensePlugin(w, PLUGIN_RI_KEY, l.RIExpires); //end of plugins array w.WriteEnd(); //end of plugins object w.WriteEndObject(); //end of AyaNova/AyaNovaLite key object w.WriteEndObject(); //close outer 'wrapper' object brace } w.WriteEndObject(); }//end of using statement // ## CALCULATE SIGNATURE //GET JSON as a string with whitespace stripped outside of delimited strings //http://stackoverflow.com/questions/8913138/minify-indented-json-string-in-net string keyNoWS = System.Text.RegularExpressions.Regex.Replace(sbKey.ToString(), "(\"(?:[^\"\\\\]|\\\\.)*\")|\\s+", "$1"); //**** Note this is our real 2016 private key var privatePEM = @"-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAz7wrvLDcKVMZ31HFGBnLWL08IodYIV5VJkKy1Z0n2snprhSi u3izxTyz+SLpftvKHJpky027ii7l/pL9Bo3JcjU5rKrxXavnE7TuYPjXn16dNLd0 K/ERSU+pXLmUaVN0nUWuGuUMoGJMEXoulS6pJiG11yu3BM9fL2Nbj0C6a+UwzEHF mns3J/daZOb4gAzMUdJfh9OJ0+wRGzR8ZxyC99Na2gDmqYglUkSMjwLTL/HbgwF4 OwmoQYJBcET0Wa6Gfb17SaF8XRBV5ZtpCsbStkthGeoXZkFriB9c1eFQLKpBYQo2 DW3H1MPG2nAlQZLbkJj5cSh7/t1bRF08m6P+EQIDAQABAoIBAQCGvTpxLRXgB/Kk EtmQBEsMx9EVZEwZeKIqKuDsBP8wvf4/10ql5mhT6kehtK9WhSDW5J2z8DtQKZMs SBKuCZE77qH2CPp9E17SPWzQoRbaW/gDlWpYhgf8URs89XH5zxO4XtXKw/4omRlV zLYiNR2pifv0EHqpOAg5KGzewdEo4VgXgtRWpHZLMpH2Q0/5ZIKMhstI6vFHP1p7 jmU4YI6uxiu7rVrZDmIUsAGoTdMabNqK/N8hKaoBiIto0Jn1ck26g+emLg8m160y Xciu5yFUU+PP1SJMUs+k1UnAWf4p46X9jRLQCBRue9o0Ntiq/75aljRoDvgdwDsR mg4ZANqxAoGBAPBoM5KoMZ4sv8ZFv8V+V8hgL5xiLgGoiwQl91mRsHRM/NQU5A/w tH8nmwUrJOrksV7kX9228smKmoliTptyGGyi1NPmSkA7cN9YYnENoOEBHCVNK9vh P+bkbMYUDNMW4fgOj09oXtQtMl5E2B3OTGoNwZ2w13YQJ8RIniLPsX7nAoGBAN01 eQNcUzQk9YrFGTznOs8udDLBfigDxaNnawvPueulJdBy6ZXDDrKmkQQA7xxl8YPr dNtBq2lOgnb6+smC15TaAfV/fb8BLmkSwdn4Fy0FApIXIEOnLq+wjkte98nuezl8 9KXDzaqNI9hPuk2i36tJuLLMH8hzldveWbWjSlRHAoGBAKRPE7CQtBjfjNL+qOta RrT0yJWhpMANabYUHNJi+K8ET2jEPnuGkFa3wwPtUPYaCABLJhprB9Unnid3wTIM 8RSO1ddd9jGgbqy3w9Bw+BvQnmQAMpG9iedNB+r5mSpM4XSgvuIO+4EYwuwbMXpt nVx+um4Eh75xnDxTRYGVYkLRAoGAaZVpUlpR+HSfooHbPv+bSWKB4ewLPCw4vHrT VErtEfW8q9b9eRcmP81TMFcFykc6VN4g47pfh58KlKHM7DwAjDLWdohIy89TiKGE V3acEUfv5y0UoFX+6ara8Ey+9upWdKUY3Lotw3ckoc3EPeQ84DQK7YSSswnAgLaL mS/8fWcCgYBjRefVbEep161d2DGruk4X7eNI9TFJ278h6ydW5kK9aTJuxkrtKIp4 CYf6emoB4mLXFPvAmnsalkhN2iB29hUZCXXSUjpKZrpijL54Wdu2S6ynm7aT97NF oArP0E2Vbow3JMxq/oeXmHbrLMLQfYyXwFmciLFigOtkd45bfHdrbA== -----END RSA PRIVATE KEY-----"; PemReader pr = new PemReader(new StringReader(privatePEM)); AsymmetricCipherKeyPair keys = (AsymmetricCipherKeyPair)pr.ReadObject(); var encoder = new UTF8Encoding(false, true); var inputData = encoder.GetBytes(keyNoWS); var signer = SignerUtilities.GetSigner("SHA256WITHRSA"); signer.Init(true, keys.Private); signer.BlockUpdate(inputData, 0, inputData.Length); var sign = signer.GenerateSignature(); var signature = Convert.ToBase64String(sign); System.Text.StringBuilder sbOut = new StringBuilder(); sbOut.AppendLine("[KEY"); sbOut.AppendLine(sbKey.ToString()); sbOut.AppendLine("KEY]"); sbOut.AppendLine("[SIGNATURE"); sbOut.AppendLine(signature); sbOut.AppendLine("SIGNATURE]"); // //case 3233 insert into db // License l = new License(); // l.DtCreated = DateUtil.NowAsEpoch(); // l.Code = ko.fetchCode; // l.CustomerId = ko.customerId; // l.Email = ko.emailAddress.ToLowerInvariant(); // l.Key = sbOut.ToString(); // l.RegTo = ko.registeredTo; // ct.License.Add(l); // ct.SaveChanges(); return sbOut.ToString(); } catch (Exception ex) { return (ex.Message); } } private static void AddLicensePlugin(Newtonsoft.Json.JsonWriter w, string pluginName, DateTime? pluginExpires) { //this dictionary is used by the additional message code to //make the human readable portion of the license _plugins.Add(pluginName, (DateTime)pluginExpires); //this is adding it to the actual key w.WriteStartObject(); w.WritePropertyName("Item"); w.WriteValue(pluginName); w.WritePropertyName("SubscriptionExpires"); w.WriteValue(pluginExpires); w.WriteEndObject(); //---------------- } //eoc } //eons }