@@ -164,12 +164,18 @@ public static void AssertEvaluationLicense()
164164
165165 private static readonly int [ ] revokedSubs = { 4018 , 4019 , 4041 , 4331 , 4581 } ;
166166
167- private static LicenseKey __activatedLicense ;
167+ private class __ActivatedLicense
168+ {
169+ internal readonly LicenseKey LicenseKey ;
170+ internal __ActivatedLicense ( LicenseKey licenseKey ) => LicenseKey = licenseKey ;
171+ }
172+
173+ private static __ActivatedLicense __activatedLicense ;
168174 public static void RegisterLicense ( string licenseKeyText )
169175 {
170176 JsConfig . InitStatics ( ) ;
171177
172- if ( __activatedLicense != null ) //Skip multple license registrations. Use RemoveLicense() to reset.
178+ if ( __activatedLicense != null ) //Skip multiple license registrations. Use RemoveLicense() to reset.
173179 return ;
174180
175181 string subId = null ;
@@ -183,7 +189,7 @@ public static void RegisterLicense(string licenseKeyText)
183189 if ( int . TryParse ( subId , out var subIdInt ) && revokedSubs . Contains ( subIdInt ) )
184190 throw new LicenseException ( "This subscription has been revoked. " + ContactDetails ) ;
185191
186- var key = PclExport . Instance . VerifyLicenseKeyText ( licenseKeyText ) ;
192+ var key = VerifyLicenseKeyText ( licenseKeyText ) ;
187193 ValidateLicenseKey ( key ) ;
188194 }
189195 catch ( Exception ex )
@@ -226,7 +232,7 @@ private static void ValidateLicenseKey(LicenseKey key)
226232 if ( key . Type == LicenseType . Trial && DateTime . UtcNow > key . Expiry )
227233 throw new LicenseException ( $ "This trial license has expired on { key . Expiry : d} ." + ContactDetails ) . Trace ( ) ;
228234
229- __activatedLicense = key ;
235+ __activatedLicense = new __ActivatedLicense ( key ) ;
230236 }
231237
232238 public static void RemoveLicense ( )
@@ -236,7 +242,7 @@ public static void RemoveLicense()
236242
237243 public static LicenseFeature ActivatedLicenseFeatures ( )
238244 {
239- return __activatedLicense != null ? __activatedLicense . GetLicensedFeatures ( ) : LicenseFeature . None ;
245+ return __activatedLicense ? . LicenseKey . GetLicensedFeatures ( ) ?? LicenseFeature . None ;
240246 }
241247
242248 public static void ApprovedUsage ( LicenseFeature licenseFeature , LicenseFeature requestedFeature ,
@@ -423,12 +429,192 @@ public static string GetHashKeyToSign(this LicenseKey key)
423429
424430 public static Exception GetInnerMostException ( this Exception ex )
425431 {
426- //Extract true exception from static intializers (e.g. LicenseException)
432+ //Extract true exception from static initializers (e.g. LicenseException)
427433 while ( ex . InnerException != null )
428434 {
429435 ex = ex . InnerException ;
430436 }
431437 return ex ;
432438 }
439+
440+ //License Utils
441+ public static bool VerifySignedHash ( byte [ ] DataToVerify , byte [ ] SignedData , System . Security . Cryptography . RSAParameters Key )
442+ {
443+ try
444+ {
445+ var RSAalg = new System . Security . Cryptography . RSACryptoServiceProvider ( ) ;
446+ RSAalg . ImportParameters ( Key ) ;
447+ return RSAalg . VerifySha1Data ( DataToVerify , SignedData ) ;
448+
449+ }
450+ catch ( System . Security . Cryptography . CryptographicException ex )
451+ {
452+ Tracer . Instance . WriteError ( ex ) ;
453+ return false ;
454+ }
455+ }
456+
457+ public static LicenseKey VerifyLicenseKeyText ( string licenseKeyText )
458+ {
459+ #if NET45 || NETCORE2_1
460+ LicenseKey key ;
461+ try
462+ {
463+ if ( ! licenseKeyText . VerifyLicenseKeyText ( out key ) )
464+ throw new ArgumentException ( "licenseKeyText" ) ;
465+ }
466+ catch ( Exception e )
467+ {
468+ if ( ! VerifyLicenseKeyTextFallback ( licenseKeyText , out key ) )
469+ throw ;
470+ }
471+ return key ;
472+ #else
473+ return licenseKeyText . ToLicenseKey ( ) ;
474+ #endif
475+ }
476+
477+ private static void FromXml ( this System . Security . Cryptography . RSA rsa , string xml )
478+ {
479+ #if NET45
480+ rsa . FromXmlString ( xml ) ;
481+ #else
482+ //throws PlatformNotSupportedException
483+ var csp = ExtractFromXml ( xml ) ;
484+ rsa . ImportParameters ( csp ) ;
485+ #endif
486+ }
487+
488+ #if ! NET45
489+ private static System . Security . Cryptography . RSAParameters ExtractFromXml ( string xml )
490+ {
491+ var csp = new System . Security . Cryptography . RSAParameters ( ) ;
492+ using ( var reader = System . Xml . XmlReader . Create ( new StringReader ( xml ) ) )
493+ {
494+ while ( reader . Read ( ) )
495+ {
496+ if ( reader . NodeType != System . Xml . XmlNodeType . Element )
497+ continue ;
498+
499+ var elName = reader . Name ;
500+ if ( elName == "RSAKeyValue" )
501+ continue ;
502+
503+ do {
504+ reader . Read ( ) ;
505+ } while ( reader . NodeType != System . Xml . XmlNodeType . Text && reader . NodeType != System . Xml . XmlNodeType . EndElement ) ;
506+
507+ if ( reader . NodeType == System . Xml . XmlNodeType . EndElement )
508+ continue ;
509+
510+ var value = reader . Value ;
511+ switch ( elName )
512+ {
513+ case "Modulus" :
514+ csp . Modulus = Convert . FromBase64String ( value ) ;
515+ break ;
516+ case "Exponent" :
517+ csp . Exponent = Convert . FromBase64String ( value ) ;
518+ break ;
519+ case "P" :
520+ csp . P = Convert . FromBase64String ( value ) ;
521+ break ;
522+ case "Q" :
523+ csp . Q = Convert . FromBase64String ( value ) ;
524+ break ;
525+ case "DP" :
526+ csp . DP = Convert . FromBase64String ( value ) ;
527+ break ;
528+ case "DQ" :
529+ csp . DQ = Convert . FromBase64String ( value ) ;
530+ break ;
531+ case "InverseQ" :
532+ csp . InverseQ = Convert . FromBase64String ( value ) ;
533+ break ;
534+ case "D" :
535+ csp . D = Convert . FromBase64String ( value ) ;
536+ break ;
537+ }
538+ }
539+
540+ return csp ;
541+ }
542+ }
543+ #endif
544+
545+ public static bool VerifyLicenseKeyText ( this string licenseKeyText , out LicenseKey key )
546+ {
547+ var publicRsaProvider = new System . Security . Cryptography . RSACryptoServiceProvider ( ) ;
548+ publicRsaProvider . FromXml ( LicenseUtils . LicensePublicKey ) ;
549+ var publicKeyParams = publicRsaProvider . ExportParameters ( false ) ;
550+
551+ key = licenseKeyText . ToLicenseKey ( ) ;
552+ var originalData = key . GetHashKeyToSign ( ) . ToUtf8Bytes ( ) ;
553+ var signedData = Convert . FromBase64String ( key . Hash ) ;
554+
555+ return VerifySignedHash ( originalData , signedData , publicKeyParams ) ;
556+ }
557+
558+ public static bool VerifyLicenseKeyTextFallback ( this string licenseKeyText , out LicenseKey key )
559+ {
560+ System . Security . Cryptography . RSAParameters publicKeyParams ;
561+ try
562+ {
563+ var publicRsaProvider = new System . Security . Cryptography . RSACryptoServiceProvider ( ) ;
564+ publicRsaProvider . FromXml ( LicenseUtils . LicensePublicKey ) ;
565+ publicKeyParams = publicRsaProvider . ExportParameters ( false ) ;
566+ }
567+ catch ( Exception ex )
568+ {
569+ throw new Exception ( "Could not import LicensePublicKey" , ex ) ;
570+ }
571+
572+ try
573+ {
574+ key = licenseKeyText . ToLicenseKeyFallback ( ) ;
575+ }
576+ catch ( Exception ex )
577+ {
578+ throw new Exception ( "Could not deserialize LicenseKeyText Manually" , ex ) ;
579+ }
580+
581+ byte [ ] originalData ;
582+ byte [ ] signedData ;
583+
584+ try
585+ {
586+ originalData = key . GetHashKeyToSign ( ) . ToUtf8Bytes ( ) ;
587+ }
588+ catch ( Exception ex )
589+ {
590+ throw new Exception ( "Could not convert HashKey to UTF-8" , ex ) ;
591+ }
592+
593+ try
594+ {
595+ signedData = Convert . FromBase64String ( key . Hash ) ;
596+ }
597+ catch ( Exception ex )
598+ {
599+ throw new Exception ( "Could not convert key.Hash from Base64" , ex ) ;
600+ }
601+
602+ try
603+ {
604+ return VerifySignedHash ( originalData , signedData , publicKeyParams ) ;
605+ }
606+ catch ( Exception ex )
607+ {
608+ throw new Exception ( $ "Could not Verify License Key ({ originalData . Length } , { signedData . Length } )", ex ) ;
609+ }
610+ }
611+
612+ public static bool VerifySha1Data ( this System . Security . Cryptography . RSACryptoServiceProvider RSAalg , byte [ ] unsignedData , byte [ ] encryptedData )
613+ {
614+ using ( var sha = new System . Security . Cryptography . SHA1CryptoServiceProvider ( ) )
615+ {
616+ return RSAalg . VerifyData ( unsignedData , sha , encryptedData ) ;
617+ }
618+ }
433619 }
434620}
0 commit comments