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.Util; using Sockeye.Models; namespace Sockeye.Biz { //Key generator controller public static class RavenKeyFactory { //Jan 2023 values public const int TRIAL_KEY_SUBSCRIPTION_PERIOD_DAYS = 7; public const int TRIAL_KEY_SUBSCRIPTION_CUSTOMER_USERS = 25555;//SEEDING required public const int TRIAL_KEY_SUBSCRIPTION_MAX_DATA_GB = 20; public const int TRIAL_KEY_PERPETUAL_PERIOD_DAYS = 14; public const int TRIAL_KEY_USERS = 5000;//SEEDING required minimum //Unlicensed token private const string UNLICENSED_TOKEN = "UNLICENSED"; //REVOKED token public const string REVOKED_TOKEN = "REVOKED"; //LICENSE USER COUNT FEATURES //SUBSCRIPTION private const string ACTIVE_INTERNAL_USERS_FEATURE_NAME = "ActiveInternalUsers"; private const string ACTIVE_CUSTOMER_USERS_FEATURE_NAME = "ActiveCustomerUsers"; private const string MAXIMUM_DATA_GB_FEATURE_NAME = "MaximumDataGB"; //Add-on's / integrations //This feature name means it's a trial key private const string TRIAL_FEATURE_NAME = "TrialMode"; /// /// RAVEN key generator /// /// internal static void GenerateAndSetRavenKey(License l) { if (string.IsNullOrWhiteSpace(l.RegTo)) throw new ArgumentException("RegisteredTo is required", "RegisteredTo"); if (string.IsNullOrWhiteSpace(l.DbId)) throw new ArgumentException("DBId is required", "DbId"); //license serial number var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); string sId = vv.ToString(); if (sId.Contains(",")) sId = sId.Split('.')[0]; StringBuilder sbKey = new StringBuilder(); StringWriter sw = new StringWriter(sbKey); using (Newtonsoft.Json.JsonWriter w = new Newtonsoft.Json.JsonTextWriter(sw)) { w.Formatting = Newtonsoft.Json.Formatting.Indented; //outer object start w.WriteStartObject(); w.WritePropertyName("Key"); w.WriteStartObject();//start of key object w.WritePropertyName("LicenseFormat"); w.WriteValue("8"); w.WritePropertyName("Id"); w.WriteValue(sId); w.WritePropertyName("RegisteredTo"); w.WriteValue(l.RegTo); w.WritePropertyName("DBID"); w.WriteValue(l.DbId); w.WritePropertyName("Perpetual"); w.WriteValue(l.PGroup == ProductGroup.RavenPerpetual); w.WritePropertyName("LicenseExpiration"); w.WriteValue(l.LicenseExpire); w.WritePropertyName("MaintenanceExpiration"); w.WriteValue(l.MaintenanceExpire); //FEATURES w.WritePropertyName("Features"); w.WriteStartArray(); if (l.TrialMode) { w.WriteStartObject(); w.WritePropertyName("Name"); w.WriteValue(TRIAL_FEATURE_NAME); w.WriteEndObject(); } //USERS w.WriteStartObject(); w.WritePropertyName("Name"); w.WriteValue(ACTIVE_INTERNAL_USERS_FEATURE_NAME); w.WritePropertyName("Count"); w.WriteValue(l.Users); w.WriteEndObject(); if (l.PGroup == ProductGroup.RavenSubscription) { //CUSTOMER USERS w.WriteStartObject(); w.WritePropertyName("Name"); w.WriteValue(ACTIVE_CUSTOMER_USERS_FEATURE_NAME); w.WritePropertyName("Count"); w.WriteValue(l.CustomerUsers); w.WriteEndObject(); //MAX DATA GB w.WriteStartObject(); w.WritePropertyName("Name"); w.WriteValue(MAXIMUM_DATA_GB_FEATURE_NAME); w.WritePropertyName("Count"); w.WriteValue(l.MaxDataGB); w.WriteEndObject(); } //end of features array w.WriteEnd(); //End of "Key" property 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]"); l.Key = sbOut.ToString(); } #region old stuff #region license classes // //DTO object returned on license query // public class LicenseFeature // { // //name of feature / product // public string Feature { get; set; } // //Optional count for items that require it // public long Count { get; set; } // } // //DTO object for parsed key // internal class AyaNovaLicenseKey // { // public AyaNovaLicenseKey() // { // Features = new List(); // RegisteredTo = UNLICENSED_TOKEN; // //Id = RegisteredTo; // LicenseFormat = "8"; // var vv = Math.Truncate((DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); // string sId = vv.ToString(); // if (sId.Contains(",")) // sId = sId.Split('.')[0]; // Id = sId; // } // public override string ToString() // { // System.Text.StringBuilder sb = new StringBuilder(); // sb.AppendLine($"Registered to: {RegisteredTo}"); // sb.AppendLine($"Database id: {DbId}"); // sb.AppendLine($"Type: {(Perpetual ? "Perpetual" : "Subscription")}"); // if (WillExpire) // sb.AppendLine($"Available for use until: {LicenseExpiration.ToLongDateString()}"); // if (Perpetual) // sb.AppendLine($"Support and updates available until: {MaintenanceExpiration.ToLongDateString()}"); // foreach (LicenseFeature f in Features) // { // if (f.Feature == TRIAL_FEATURE_NAME) // { // sb.AppendLine("Temporary license for evaluation"); // continue; // } // //default for items added later not tokenized // if (f.Count > 0) // sb.AppendLine($"{f.Feature}: {f.Count}"); // else // sb.AppendLine($"{f.Feature}"); // } // return sb.ToString(); // } // public bool IsEmpty // { // get // { // //Key is empty if it's not registered to anyone or there are no features in it // return string.IsNullOrWhiteSpace(RegisteredTo) || (Features == null || Features.Count == 0); // } // } // /// // /// Fetch the license status of the feature in question // /// // /// // /// LicenseFeature object or null if there is no license // public LicenseFeature GetLicenseFeature(string Feature) // { // if (IsEmpty) // return null; // string lFeature = Feature.ToLowerInvariant(); // foreach (LicenseFeature l in Features) // { // if (l.Feature.ToLowerInvariant() == lFeature) // { // return l; // } // } // return null; // } // /// // /// Check for the existance of license feature // /// // /// // /// bool // public bool HasLicenseFeature(string Feature) // { // if (IsEmpty) // return false; // string lFeature = Feature.ToLowerInvariant(); // foreach (LicenseFeature l in Features) // { // if (l.Feature.ToLowerInvariant() == lFeature) // { // return true; // } // } // return false; // } // public bool WillExpire // { // get // { // return LicenseExpiration < DateUtil.EmptyDateValue; // } // } // public bool LicenseExpired // { // get // { // return LicenseExpiration > DateTime.Now; // } // } // public bool MaintenanceExpired // { // get // { // return MaintenanceExpiration > DateTime.Now; // } // } // public bool TrialLicense // { // get // { // return HasLicenseFeature(TRIAL_FEATURE_NAME); // } // } // public string LicenseFormat { get; set; } // public string Id { get; set; } // public string RegisteredTo { get; set; } // public string DbId { get; set; } // public bool Perpetual { get; set; } // public DateTime LicenseExpiration { get; set; } // public DateTime MaintenanceExpiration { get; set; } // public List Features { get; set; } // } #endregion // public static string GetRavenTrialKey(License l)//string dbid, string CompanyName, bool Perpetual) // { // //Build a sample test key, sign it and return it // AyaNovaLicenseKey k = new AyaNovaLicenseKey(); // k.LicenseFormat = "8"; // k.RegisteredTo = l.RegTo; // k.DbId = l.DbId; // k.Perpetual = l.PGroup == ProductGroup.RavenPerpetual; // //flag as trial key not regular key // k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 }); // if (k.Perpetual) // { // //trial period time limit // //Normal code, uncomment this when done testing expiration dates of perpetual // k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS); // //Testing code for 3 minute long evaluation license in case need to test with a key that expires // // #warning FYI ROCKFISH is SET TO GENERATE A VERY SHORT TEST KEY // // k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddMinutes(3); //TEST VALUE FOR DIAGNOSING LICENSE EXPIRATION ISSUES // //5k inside staff users will cover huge seeding level easily // k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 }); // } // else // { // //SUBSCRIPTION // //trial period time limit // k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS);//NOTE: this preserves the current time, should it be set to midnight or something? // //20k customer contacts will cover huge seeding level easily // //5k inside staff users will cover huge seeding level easily // k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 }); // k.Features.Add(new LicenseFeature() { Feature = ACTIVE_CUSTOMER_USERS_FEATURE_NAME, Count = 20000 }); // k.Features.Add(new LicenseFeature() { Feature = MAXIMUM_DATA_GB_FEATURE_NAME, Count = 20 }); // } // return GenerateRavenKey(k); // } // //TESTING ONLY this is for development purposes only // //No external usage // public static string GetRavenTestKey(string dbid, bool Perpetual) // { // //Build a sample test key, sign it and return it // AyaNovaLicenseKey k = new AyaNovaLicenseKey(); // k.LicenseFormat = "8"; // k.RegisteredTo = "GZ TestCo Inc."; // k.DbId = dbid; // k.Perpetual = Perpetual; // if (Perpetual) // { // k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS); // //5k inside staff users will cover huge seeding level easily // k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 }); // } // else // { // //SUBSCRIPTION // k.MaintenanceExpiration = k.LicenseExpiration = DateTime.UtcNow.AddDays(TRIAL_PERIOD_DAYS); // //20k customer contacts will cover huge seeding level easily // //5k inside staff users will cover huge seeding level easily // k.Features.Add(new LicenseFeature() { Feature = ACTIVE_INTERNAL_USERS_FEATURE_NAME, Count = 5000 }); // k.Features.Add(new LicenseFeature() { Feature = ACTIVE_CUSTOMER_USERS_FEATURE_NAME, Count = 20000 }); // k.Features.Add(new LicenseFeature() { Feature = MAXIMUM_DATA_GB_FEATURE_NAME, Count = 20 }); // } // k.Features.Add(new LicenseFeature() { Feature = TRIAL_FEATURE_NAME, Count = 0 }); // return GenerateRavenKey(k); // } #endregion old stuff //eoc } //eons }