├── .gitignore ├── DotNetLicense.UnitTests ├── DotNetLicense.UnitTests.csproj ├── LicenseManagerTests.cs ├── Properties │ └── AssemblyInfo.cs ├── TestKeys.cs ├── TestLicenses.cs ├── testAlteredLicense.lic ├── testInvalidLicense.lic ├── testSignedLicense.lic └── testUnsignedLicense.lic ├── DotNetLicense ├── DotNetLicense.csproj ├── License.cs ├── LicenseManager.cs ├── LicenseVerificationException.cs ├── MITLicense.txt └── Properties │ └── AssemblyInfo.cs ├── DotNetLicensing.Examples.Northwind ├── App.config ├── App.xaml ├── App.xaml.cs ├── DotNetLicensing.Examples.Northwind.csproj ├── MVVM │ ├── DelegateCommand.cs │ └── ViewModel.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Models │ └── NorthwindLicense.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── ValidationRules │ └── NumberValidationRule.cs └── ViewModels │ └── ManageLicenseVM.cs ├── DotNetLicensing.sln └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/DotNetLicense.UnitTests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | {76E04B06-8BC4-4197-82F9-56195482DE60} 7 | Library 8 | Properties 9 | DotNetLicense.UnitTests 10 | DotNetLicense.UnitTests 11 | v4.5.2 12 | 512 13 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 14 | 10.0 15 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 16 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages 17 | False 18 | UnitTest 19 | 20 | 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | {18ba972c-45f0-476a-907d-ea7b549d478e} 61 | DotNetLicense 62 | 63 | 64 | 65 | 66 | Always 67 | 68 | 69 | Always 70 | 71 | 72 | Always 73 | 74 | 75 | Always 76 | 77 | 78 | 79 | 80 | 81 | 82 | False 83 | 84 | 85 | False 86 | 87 | 88 | False 89 | 90 | 91 | False 92 | 93 | 94 | 95 | 96 | 97 | 98 | 105 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/LicenseManagerTests.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using DotNetLicense; 3 | using System.IO; 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | 6 | namespace DotNetLicense.UnitTests 7 | { 8 | [TestClass] 9 | public class LicenseManagerTests 10 | { 11 | private string _classTestDirName; 12 | 13 | [TestInitialize] 14 | public void Setup() 15 | { 16 | _classTestDirName = "dotnetlicensingworkdir"; 17 | Directory.CreateDirectory(_classTestDirName); 18 | } 19 | 20 | [TestCleanup] 21 | public void Cleanup() 22 | { 23 | Directory.Delete(this._classTestDirName, true); 24 | } 25 | 26 | [TestMethod] 27 | public void CreateNewKeyPair() 28 | { 29 | LicenseManager manager = new LicenseManager(); 30 | manager.CreateKeyPairs(_classTestDirName, "testNewPair"); 31 | 32 | string expectedPublicKeyPath = string.Format("{0}\\testNewPair_public.key",_classTestDirName); 33 | string expectedPrivateKeyPath = string.Format("{0}\\testNewPair_private.key",_classTestDirName); 34 | Assert.IsTrue(File.Exists(expectedPublicKeyPath)); 35 | Assert.IsTrue(File.Exists(expectedPrivateKeyPath)); 36 | } 37 | 38 | [TestMethod] 39 | public void LoadPrivateKeyFromString() 40 | { 41 | LicenseManager manager = new LicenseManager(); 42 | manager.LoadPrivateKeyFromString(TestKeys.PrivateKey); 43 | Assert.IsNotNull(manager.PrivateKey); 44 | } 45 | 46 | [TestMethod] 47 | public void LoadPublicKeyFromString() 48 | { 49 | LicenseManager manager = new LicenseManager(); 50 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 51 | Assert.IsNotNull(manager.PublicKey); 52 | } 53 | 54 | [TestMethod] 55 | public void CreateNewLicense() 56 | { 57 | LicenseManager manager = new LicenseManager(); 58 | manager.LoadPrivateKeyFromString(TestKeys.PrivateKey); 59 | string expectedFilePath = string.Format("{0}\\testLicense.lic", _classTestDirName); 60 | manager.SignAndSaveNewLicense(TestLicenses.GetTestNewUnsignedLicense(), expectedFilePath); 61 | 62 | Assert.IsTrue(File.Exists(expectedFilePath)); 63 | } 64 | 65 | [TestMethod] 66 | public void LoadSignedLicense() 67 | { 68 | LicenseManager manager = new LicenseManager(); 69 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 70 | License testLicense = manager.LoadLicenseFromString(TestLicenses.GetTestSignedLicenseString()); 71 | 72 | Assert.IsNotNull(testLicense); 73 | } 74 | 75 | [TestMethod] 76 | [ExpectedException(typeof(LicenseVerificationException))] 77 | public void LoadUnSignedLicense() 78 | { 79 | LicenseManager manager = new LicenseManager(); 80 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 81 | License testLicense = manager.LoadLicenseFromString(TestLicenses.GetTestUnsignedLicenseString()); 82 | } 83 | 84 | [TestMethod] 85 | [ExpectedException(typeof(LicenseVerificationException))] 86 | public void LoadAlteredLicense() 87 | { 88 | LicenseManager manager = new LicenseManager(); 89 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 90 | License testLicense = manager.LoadLicenseFromString(TestLicenses.GetTestAlteredLicenseString()); 91 | } 92 | 93 | [TestMethod] 94 | [ExpectedException(typeof(LicenseVerificationException))] 95 | public void LoadInvalidLicense() 96 | { 97 | LicenseManager manager = new LicenseManager(); 98 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 99 | License testLicense = manager.LoadLicenseFromString(TestLicenses.GetTestInvalidLicenseString()); 100 | } 101 | 102 | [TestMethod] 103 | [ExpectedException(typeof(LicenseVerificationException))] 104 | public void LoadNonXml() 105 | { 106 | LicenseManager manager = new LicenseManager(); 107 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 108 | License testLicense = manager.LoadLicenseFromString(TestLicenses.GetNonXml()); 109 | } 110 | 111 | [TestMethod] 112 | public void ReadLicenseAttributes() 113 | { 114 | LicenseManager manager = new LicenseManager(); 115 | manager.LoadPublicKeyFromString(TestKeys.PublicKey); 116 | License testLicense = manager.LoadLicenseFromString(TestLicenses.GetTestSignedLicenseString()); 117 | 118 | string company = testLicense.GetAttribute("Company"); 119 | string licensedOn = testLicense.GetAttribute("LicensedOn"); 120 | 121 | Assert.AreEqual("Test Co.", company); 122 | Assert.AreEqual("6/24/2016", licensedOn); 123 | } 124 | 125 | 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetLicense.UnitTests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("DotNetLicense.UnitTests")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("76e04b06-8bc4-4197-82f9-56195482de60")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/TestKeys.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DotNetLicense.UnitTests 8 | { 9 | internal static class TestKeys 10 | { 11 | internal static string PublicKey 12 | { 13 | get 14 | { 15 | return @"jGc427H9GS8Vt5uSDvC4uOIEX+S7UXvRO8zCa44EADX4eGPUPjC23etgMK+QSBFfJc84GqSX9BPEuJmFLY5Z2NGRt1NT5CYA1ygYhsgqNtoGYNVcAfjPSvRw8LHg/QjqdPuXc5RL9/gY3S2zd0Qp2diRZCHuWwHU9UMVC/Adw9sLvUzC7tdfMrUhh4Ky8cgjWQLfEYF+knPWLn8CgpEmUlUjAxCSuoEW5v0tY/7ex4hJZlSYhZqynCTjzXvUPsaQhk0aIomEkdMPYhgb+wFU1gf5AhueZ1mpIkkSAcrqIbcKp+l4FRTgg0v05a0chv3K2aRZSr752xzYAsSW322Ifw==AQAB"; 16 | } 17 | } 18 | 19 | internal static string PrivateKey 20 | { 21 | get 22 | { 23 | return @"jGc427H9GS8Vt5uSDvC4uOIEX+S7UXvRO8zCa44EADX4eGPUPjC23etgMK+QSBFfJc84GqSX9BPEuJmFLY5Z2NGRt1NT5CYA1ygYhsgqNtoGYNVcAfjPSvRw8LHg/QjqdPuXc5RL9/gY3S2zd0Qp2diRZCHuWwHU9UMVC/Adw9sLvUzC7tdfMrUhh4Ky8cgjWQLfEYF+knPWLn8CgpEmUlUjAxCSuoEW5v0tY/7ex4hJZlSYhZqynCTjzXvUPsaQhk0aIomEkdMPYhgb+wFU1gf5AhueZ1mpIkkSAcrqIbcKp+l4FRTgg0v05a0chv3K2aRZSr752xzYAsSW322Ifw==AQAB

xXPffFqodSk8MlSXCblJ/k1prlBo2f63nGtn1s8FvWaJs/FXXLCeOjK0Sm0MDxFXpnt5za6BR4/6ixRle0OzDsxLqu4c9IfgJ/+Lf+/5DY55gj4kcDgpLPi4XaunDhndALV5KLr9hs8RgeSlJSwVKO2/9gAMB2X3CgdVugs1MHE=

tgjfdSmCRkCfQuzjIBYBUgcnvpcSj1zVQ3KdYN14tzWMY/rkWXNJly/75LWnMgbjKEcQtLZH9GOsaoMwgZ68ywKzdutp9+deTTIGl+wMyU2g9o0SCCYMjHpEalHEyMHV1T93dz9aUaWSl8dXIpC2qUPfY96x8H/wwxhtDLQxv+8=FtTRMLXi6Lk95qv1UwCD183nvGo71YkofgPFXAdQKJhkr9PmQCeEBEK8qiZ10IA23F9GtEvLUxUI6XAQU/J+D+X7keY6nuPfPYDFBqQe7jxdPHwnBnrX+AVCfEJO7Mh8z4osWlNU4XOsGJLxrZytTbBAFBfpTCm0KQq0FPEa02E=m1sfOuLeKA7m3TtG7A9buSIaLXLJiEj2ScX7wrvBVrsAwiNR13WpDLsLA7p0oyF1pN5hx5j59/1JHO4x664J+kin2Yo4ujZgKQnUzrvKfdMe2My04vd2Jj4DPanjhGLJmGG+F6ud7aidX6PlHb7b5cHjWVyqCFNoq1ihWQJAo0k=B+I9emFhSL02cEXwONalY2M+abvuYYTgQz7aT8AbU4mm+gZRiNcX7rFO+XfnWacqzbVz7fZ0kTEoKgnJl/CdH8c0/v7lzndgb7FqDqzLKs7i+Vjgao/BiGqWF22CZSh42W7MqeV4ov+VCZVhzQXfQ0HLFkVdfvi8sBRry+2zpeM=VwWzbBgJs45He6HlCXWSSKVt6LGwmHSR3uquplNDj43kD1pwtosjDLFS0Vo/pyt9OcYSFBFoTVPjXjdpIC9W6Ngb5PC00nfrlW+4o/F0mMLRqTsU5/P7J44SYl0eAjeAejlmSbDk1TDk2FH3JjkNZ4SfuNx/C9E62TlW1ithh35Vtm0wG1odueOQr2ei98k+UUavZ/SVOY41pPOYEM9NbpPsn54XixA80h+Wh4oCliEDnnkm9fhd/1juSGHI9eaZIUwmU7pT6TsJxoGKFFn0XvAhw+SLiqbHbHNwfP0gyQjaUQODji8Ty2Gmsz8y5I/Mevd+CMcnG4Bg2wrIoND1gQ==
"; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/TestLicenses.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DotNetLicense.UnitTests 9 | { 10 | internal static class TestLicenses 11 | { 12 | /// 13 | /// Gets a new, never saved, never signed licenses. 14 | /// 15 | /// 16 | internal static License GetTestNewUnsignedLicense() 17 | { 18 | License license = new License(); 19 | license.AddOrChangeAttribute("Company", "Test Co."); 20 | license.AddOrChangeAttribute("LicensedOn", DateTime.Now.ToShortDateString()); 21 | 22 | return license; 23 | } 24 | 25 | /// 26 | /// A valid, signed license that has been saved to disk. 27 | /// 28 | /// 29 | internal static string GetTestSignedLicenseString() 30 | { 31 | string licenseText = File.ReadAllText("testSignedLicense.lic"); 32 | return licenseText; 33 | } 34 | 35 | /// 36 | /// A saved license that has had it's signature removed. 37 | /// 38 | /// 39 | internal static string GetTestUnsignedLicenseString() 40 | { 41 | string licenseText = File.ReadAllText("testUnSignedLicense.lic"); 42 | return licenseText; 43 | } 44 | 45 | /// 46 | /// A saved license that was then altered (date changed to 2017) 47 | /// 48 | /// 49 | internal static string GetTestAlteredLicenseString() 50 | { 51 | string licenseText = File.ReadAllText("testAlteredLicense.lic"); 52 | return licenseText; 53 | } 54 | 55 | /// 56 | /// Gets an invalid license that is just junk XML and not actually a license at all. 57 | /// 58 | /// 59 | internal static string GetTestInvalidLicenseString() 60 | { 61 | string licenseText = File.ReadAllText("testInvalidLicense.lic"); 62 | return licenseText; 63 | } 64 | 65 | /// 66 | /// Gets an invalid string that is not even xml. 67 | /// 68 | /// 69 | internal static string GetNonXml() 70 | { 71 | return @"I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. 72 | I've watched c-beams glitter in the dark near the Tannhäuser Gate. All those ... moments will be lost in time, 73 | like tears...in rain. "; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/testAlteredLicense.lic: -------------------------------------------------------------------------------- 1 | 2 | Test Co. 3 | 6/24/2017 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | OBGRr7obZIJpBSfVfh7ZP6g924A= 14 | 15 | 16 | UHWTCYfLHNe3VE1c0DNt2YPezwLBS+zqkI85L5BGXZs+jFoW+tSU6aLCZA11FgoLAVQogQxi9+0wXDNmli7OWm6LYL1LRijbwiEL6ci4w3z0MtDUHT/dzOgbFDEtbe/3am/zDWTJCbh/nEn2VNJp9bkUKgT6JYyKqvNtfiQYgj0E7S5I5YU+Zllj/4Mmm/62TgjyIB5xCAA3ZTHZt9XRm18sORlmmalni0VWnidHjIhFU0eKddAZrkvbv29cebhJug13Derkfz8C5u38gpj9Jt7i5W5py/kuMDJ1N2tmF75z+8JM6SOU0td5cfC7AfAzTXVzjWgkYV79tskev9huSQ== 17 | 18 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/testInvalidLicense.lic: -------------------------------------------------------------------------------- 1 | 2 | I had a dream that I was a butterfly. 3 | -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/testSignedLicense.lic: -------------------------------------------------------------------------------- 1 | Test Co.6/24/2016OBGRr7obZIJpBSfVfh7ZP6g924A=UHWTCYfLHNe3VE1c0DNt2YPezwLBS+zqkI85L5BGXZs+jFoW+tSU6aLCZA11FgoLAVQogQxi9+0wXDNmli7OWm6LYL1LRijbwiEL6ci4w3z0MtDUHT/dzOgbFDEtbe/3am/zDWTJCbh/nEn2VNJp9bkUKgT6JYyKqvNtfiQYgj0E7S5I5YU+Zllj/4Mmm/62TgjyIB5xCAA3ZTHZt9XRm18sORlmmalni0VWnidHjIhFU0eKddAZrkvbv29cebhJug13Derkfz8C5u38gpj9Jt7i5W5py/kuMDJ1N2tmF75z+8JM6SOU0td5cfC7AfAzTXVzjWgkYV79tskev9huSQ== -------------------------------------------------------------------------------- /DotNetLicense.UnitTests/testUnsignedLicense.lic: -------------------------------------------------------------------------------- 1 | Test Co.6/24/2016 -------------------------------------------------------------------------------- /DotNetLicense/DotNetLicense.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {18BA972C-45F0-476A-907D-EA7B549D478E} 8 | Library 9 | Properties 10 | DotNetLicense 11 | DotNetLicense 12 | v4.5.2 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | bin\Release\DotNetLicense.XML 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /DotNetLicense/License.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Security.Cryptography; 5 | using System.Security.Cryptography.Xml; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | using System.Xml; 9 | using System.Xml.Linq; 10 | 11 | namespace DotNetLicense 12 | { 13 | /// 14 | /// Represents an instance of a License. You use the to create and read these licenses. 15 | /// 16 | public class License 17 | { 18 | private Dictionary _licenseAttributes; 19 | private SignedXml _signature; 20 | private XmlDocument _xmlLicense; 21 | 22 | #region Constructor 23 | /// 24 | /// Creates a new license. Use this when creating a license from scratch. 25 | /// 26 | public License() 27 | { 28 | _licenseAttributes = new Dictionary(); 29 | } 30 | 31 | /// 32 | /// Creates a license class from an existing XmlDocument representing a signed xml license. It must have been created using this class. 33 | /// 34 | /// 35 | public License(XmlDocument licenseContent) 36 | { 37 | _licenseAttributes = new Dictionary(); 38 | InitializeFromXmlFile(licenseContent); 39 | } 40 | 41 | /// 42 | /// Creates a license class from an existing string representing a signed xml license. 43 | /// 44 | /// 45 | public License(string licenseContent) 46 | { 47 | _licenseAttributes = new Dictionary(); 48 | XmlDocument xDoc = new XmlDocument(); 49 | try 50 | { 51 | xDoc.LoadXml(licenseContent); 52 | } 53 | catch (XmlException xmlEx) 54 | { 55 | throw new LicenseVerificationException("This license is not valid XML - it may be malformed! See inner exception for details.", xmlEx); 56 | } 57 | 58 | InitializeFromXmlFile(xDoc); 59 | } 60 | #endregion 61 | 62 | #region LicenseAttribute Management 63 | /// 64 | /// Adds or updates a license attribute. 65 | /// 66 | /// 67 | /// 68 | public void AddOrChangeAttribute(string name, string value) 69 | { 70 | if (_signature != null) throw new InvalidOperationException("This license has been signed, you may not change it."); 71 | 72 | if (_licenseAttributes.ContainsKey(name)) 73 | { 74 | _licenseAttributes[name] = value; 75 | } 76 | else 77 | { 78 | _licenseAttributes.Add(name, value); 79 | } 80 | } 81 | 82 | /// 83 | /// Gets a license attribute from the license. 84 | /// 85 | /// 86 | /// 87 | public string GetAttribute(string name) 88 | { 89 | if (_licenseAttributes.ContainsKey(name)) 90 | { 91 | return _licenseAttributes[name]; 92 | } 93 | else 94 | { 95 | throw new ArgumentException(string.Format("The license does not have an attribute named {0}", name)); 96 | } 97 | } 98 | 99 | /// 100 | /// Removes an attribute from the license. 101 | /// 102 | /// 103 | public void RemoveAttribute(string name) 104 | { 105 | if (_signature != null) throw new InvalidOperationException("This license has been signed, you may not change it."); 106 | 107 | if (_licenseAttributes.ContainsKey(name)) 108 | { 109 | _licenseAttributes.Remove(name); 110 | } 111 | else 112 | { 113 | throw new ArgumentException(string.Format("The license does not have an attribute named {0}", name)); 114 | } 115 | } 116 | #endregion 117 | 118 | /// 119 | /// Signs the license and generates XML from the attributes and private key. Once signed, the license may not be altered. 120 | /// 121 | /// 122 | /// 123 | public void Sign(string privateKey) 124 | { 125 | if (_signature != null) 126 | { 127 | throw new InvalidOperationException("This license has already been signed. You may not re-sign it."); 128 | } 129 | 130 | XmlDocument XDoc = new XmlDocument(); 131 | 132 | //Establish root element. 133 | XmlElement license = XDoc.CreateElement("license"); 134 | XDoc.AppendChild(license); 135 | 136 | foreach (var key in _licenseAttributes.Keys) 137 | { 138 | XmlElement licenseAttribute = XDoc.CreateElement("LicenseAttribute"); 139 | XmlAttribute nameAttribute = XDoc.CreateAttribute("Name"); 140 | nameAttribute.Value = key; 141 | 142 | licenseAttribute.Attributes.Append(nameAttribute); 143 | licenseAttribute.InnerText = _licenseAttributes[key]; 144 | 145 | license.AppendChild(licenseAttribute); 146 | } 147 | 148 | //Now we need to append the security signature, which needs to be regenerated. 149 | RSA encrKey = RSA.Create(); 150 | encrKey.FromXmlString(privateKey); 151 | 152 | SignedXml sxml = new SignedXml(XDoc); 153 | sxml.SigningKey = encrKey; 154 | sxml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigCanonicalizationUrl; 155 | 156 | // Add reference to XML data 157 | Reference r = new Reference(""); 158 | r.AddTransform(new XmlDsigEnvelopedSignatureTransform(false)); 159 | sxml.AddReference(r); 160 | 161 | // Build signature 162 | sxml.ComputeSignature(); 163 | 164 | // Attach signature to XML Document 165 | XmlElement sig = sxml.GetXml(); 166 | XDoc.DocumentElement.AppendChild(sig); 167 | 168 | _xmlLicense = XDoc; 169 | } 170 | 171 | /// 172 | /// Returns an XmlDocument object representing the license. 173 | /// 174 | /// 175 | public XmlDocument ToXml() 176 | { 177 | if (_xmlLicense == null) throw new InvalidOperationException("The license has not been loaded from xml or has not yet been signed - cannot generate XML."); 178 | return _xmlLicense; 179 | } 180 | 181 | /// 182 | /// Initializes a license from an XmlDocument object. 183 | /// 184 | /// 185 | public void FromXml(XmlDocument xmlDoc) 186 | { 187 | InitializeFromXmlFile(xmlDoc); 188 | } 189 | 190 | /// 191 | /// Returns the string representation of the XML license. 192 | /// 193 | /// 194 | public override string ToString() 195 | { 196 | if (_xmlLicense == null) return "Unloaded License."; 197 | return _xmlLicense.OuterXml; 198 | } 199 | 200 | /// 201 | /// Checks a license to ensure that it has not been validated. 202 | /// 203 | /// The public key that was used to generate this license. This is NOT the private key that is used at generation time. 204 | /// True or false. False means the file has been modified. 205 | public bool IsValid(string publicKey) 206 | { 207 | RSA key = RSA.Create(); 208 | key.FromXmlString(publicKey); 209 | 210 | SignedXml sxml = new SignedXml(this._xmlLicense); 211 | try 212 | { 213 | // Find signature node 214 | XmlNode sig = this._xmlLicense.GetElementsByTagName("Signature")[0]; 215 | sxml.LoadXml((XmlElement)sig); 216 | } 217 | catch 218 | { 219 | // Not signed! 220 | return false; 221 | } 222 | 223 | return sxml.CheckSignature(key); 224 | } 225 | 226 | /// 227 | /// Initializes the license from an XML file. 228 | /// 229 | /// 230 | private void InitializeFromXmlFile(XmlDocument licenseContent) 231 | { 232 | try 233 | { 234 | var xmlLicenseAttributes = licenseContent.GetElementsByTagName("LicenseAttribute"); 235 | 236 | foreach (XmlNode node in xmlLicenseAttributes) 237 | { 238 | string name = node.Attributes["Name"].Value; 239 | string value = node.InnerText; 240 | _licenseAttributes.Add(name, value); 241 | } 242 | 243 | _xmlLicense = licenseContent; 244 | } 245 | catch (Exception ex) 246 | { 247 | throw new Exception("Could not load license XML, it may be malformed. See inner exception for details", ex); 248 | } 249 | 250 | try 251 | { 252 | XmlElement signedElement = (XmlElement)licenseContent.SelectSingleNode("/license/Signature"); 253 | 254 | _signature = new SignedXml(signedElement); 255 | } 256 | catch 257 | { 258 | //There was no signature! 259 | _signature = null; 260 | } 261 | } 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /DotNetLicense/LicenseManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Security.Cryptography; 6 | using System.Security.Cryptography.Xml; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Xml; 10 | 11 | namespace DotNetLicense 12 | { 13 | /// 14 | /// The license manager class is used to create and load keys for the creation and loading instances of . 15 | /// 16 | public class LicenseManager 17 | { 18 | /// 19 | /// The public key that is used to verify that a license is valid. You must populate this to open / load licenses. 20 | /// 21 | public string PublicKey { get; private set; } 22 | 23 | /// 24 | /// Private key that is used to create signed licenses. You must popualte this in order to create a new license. 25 | /// 26 | public string PrivateKey { get; private set; } 27 | 28 | /// 29 | /// Loads a private key from the given filepath 30 | /// 31 | /// 32 | public void LoadPrivateKeyFromFile(string filepath) 33 | { 34 | PrivateKey = LoadFromDiskAndVerify(filepath); 35 | } 36 | 37 | /// 38 | /// Loads a public key from the given filepath. 39 | /// 40 | /// 41 | public void LoadPublicKeyFromFile(string filepath) 42 | { 43 | PublicKey = LoadFromDiskAndVerify(filepath); 44 | } 45 | 46 | /// 47 | /// Loads a private key from a string. 48 | /// 49 | /// An XML representation of an RSA key string. 50 | public void LoadPrivateKeyFromString(string keyString) 51 | { 52 | RSA encrKey = RSA.Create(); 53 | encrKey.FromXmlString(keyString); 54 | 55 | PrivateKey = keyString; 56 | } 57 | 58 | /// 59 | /// Loads a public key from a string. 60 | /// 61 | /// An XML representation of an RSA key string. 62 | public void LoadPublicKeyFromString(string keyString) 63 | { 64 | RSA encrKey = RSA.Create(); 65 | encrKey.FromXmlString(keyString); 66 | 67 | PublicKey = keyString; 68 | } 69 | 70 | /// 71 | /// Creates a new set of private and public key pairs and saves the files to thr specified directory. 72 | /// 73 | /// The directory the keys will be written to. 74 | /// The name of the keys, which will have _public or private appended to it. 75 | public void CreateKeyPairs(string directory, string keyPairName) 76 | { 77 | RSACryptoServiceProvider key = new RSACryptoServiceProvider(2048); 78 | 79 | string publicPrivateKeyXML = key.ToXmlString(true); 80 | string publicOnlyKeyXML = key.ToXmlString(false); 81 | 82 | string privateKeyFileName = string.Format("{0}\\{1}_private.key", directory, keyPairName); 83 | string publicKeyFileName = string.Format("{0}\\{1}_public.key", directory, keyPairName); 84 | 85 | StringToFile(publicKeyFileName, publicOnlyKeyXML); 86 | StringToFile(privateKeyFileName, publicPrivateKeyXML); 87 | } 88 | 89 | /// 90 | /// Uses the defined Public Key and saves the license to the given filepath. 91 | /// 92 | /// An instance of a to be saved to disk. 93 | /// The file path where the license will be saved. 94 | public void SignAndSaveNewLicense(License license, string filepath) 95 | { 96 | var textToSave = this.SignAndSaveNewLicense(license); 97 | 98 | try 99 | { 100 | File.WriteAllText(filepath, textToSave); 101 | } 102 | catch (Exception ex) 103 | { 104 | throw new Exception("Could not save license file to disk. See inner exception for details.", ex); 105 | } 106 | } 107 | 108 | /// 109 | /// Generates a license as an XML string. 110 | /// 111 | /// 112 | /// 113 | public string SignAndSaveNewLicense(License license) 114 | { 115 | if (String.IsNullOrEmpty(PrivateKey)) throw new InvalidOperationException(@"The private key has not been set - can not create a new license. 116 | Set the private key property before calling this method."); 117 | try 118 | { 119 | license.Sign(PrivateKey); 120 | } 121 | catch (Exception ex) 122 | { 123 | throw new Exception("Could not sign license. See inner exception for details.", ex); 124 | } 125 | 126 | return license.ToString(); 127 | } 128 | 129 | /// 130 | /// Loads a license from disk. Throws an exception if it is not valid. 131 | /// 132 | /// 133 | /// 134 | public License LoadLicenseFromDisk(string filepath) 135 | { 136 | if (String.IsNullOrEmpty(PublicKey)) throw new InvalidOperationException(@"The public key has not been set - can not verify if a license is valid. 137 | Set the public key property before calling this method."); 138 | string rawText = ""; 139 | try 140 | { 141 | rawText = File.ReadAllText(filepath); 142 | } 143 | catch (Exception ex) 144 | { 145 | throw new Exception("Could not read license file at {0} from disk. See inner exception for details.", ex); 146 | } 147 | 148 | License loadedLicense = new License(rawText); 149 | 150 | if (!loadedLicense.IsValid(PublicKey)) throw new LicenseVerificationException(string.Format("The license file at {0} is not valid!")); 151 | 152 | return loadedLicense; 153 | } 154 | 155 | /// 156 | /// Load a license from the given string. 157 | /// 158 | /// The string from which a license class is to be deserialized and instanciated into. 159 | /// 160 | public License LoadLicenseFromString(string licenseString) 161 | { 162 | if (String.IsNullOrEmpty(PublicKey)) throw new InvalidOperationException(@"The public key has not been set - can not verify if a license is valid. 163 | Set the public key property before calling this method."); 164 | License loadedLicense = new License(licenseString); 165 | 166 | if (!loadedLicense.IsValid(PublicKey)) throw new LicenseVerificationException(string.Format("The license file at {0} is not valid!",licenseString)); 167 | 168 | return loadedLicense; 169 | } 170 | 171 | /// 172 | /// Writes a string to a file. 173 | /// 174 | /// 175 | /// 176 | private void StringToFile(string outfile, string data) 177 | { 178 | StreamWriter outStream = System.IO.File.CreateText(outfile); 179 | outStream.Write(data); 180 | outStream.Close(); 181 | } 182 | 183 | /// 184 | /// Loads a file that is expected to be an XML RSA key. 185 | /// 186 | /// 187 | /// 188 | private string LoadFromDiskAndVerify(string filepath) 189 | { 190 | try 191 | { 192 | var rawText = File.ReadAllText(filepath); 193 | RSA encrKey = RSA.Create(); 194 | encrKey.FromXmlString(rawText); //Test parsing the xml to make sure its valid. 195 | 196 | return rawText; 197 | } 198 | catch (Exception ex) 199 | { 200 | throw new Exception("Could not load private key from disk. See inner exception for details.", ex); 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /DotNetLicense/LicenseVerificationException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace DotNetLicense 8 | { 9 | /// 10 | /// Exception thrown when a DotNetLicense license file is not valid. 11 | /// 12 | public class LicenseVerificationException : Exception 13 | { 14 | private string _message; 15 | /// 16 | /// A description of why the LicenseVerificationException was thrown. 17 | /// 18 | public override string Message 19 | { 20 | get 21 | { 22 | return _message; 23 | } 24 | } 25 | 26 | /// 27 | /// Creates a new license verification exception with a given message. 28 | /// 29 | /// A message describing the reason for the License exception. 30 | public LicenseVerificationException(string message) : base(message) 31 | { 32 | _message = message; 33 | } 34 | 35 | /// 36 | /// Creates a license exception with an inner exception and a message. 37 | /// 38 | /// A message describing the reason for the exception. 39 | /// The inner exception that caused the license exception. 40 | public LicenseVerificationException(string message, Exception innerException) : base(message,innerException) 41 | { 42 | _message = message; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DotNetLicense/MITLicense.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) <2016> Matthew Studley, Original code forked from Skyxoft 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), 5 | to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 6 | and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 7 | 8 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 12 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /DotNetLicense/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DotNetLicense")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("DotNetLicense")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("18ba972c-45f0-476a-907d-ea7b549d478e")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using DotNetLicensing.Examples.Northwind.MVVM; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Data; 6 | using System.Linq; 7 | using System.Threading.Tasks; 8 | using System.Windows; 9 | 10 | namespace DotNetLicensing.Examples.Northwind 11 | { 12 | /// 13 | /// Interaction logic for App.xaml 14 | /// 15 | public partial class App : Application 16 | { 17 | protected override void OnStartup(StartupEventArgs e) 18 | { 19 | base.OnStartup(e); 20 | ViewModel vm = new ViewModels.ManageLicenseVM(); 21 | Window view = new MainWindow(); 22 | view.Show(); 23 | view.DataContext = vm; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/DotNetLicensing.Examples.Northwind.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E87F0870-146D-452F-9C24-8294C2A53001} 8 | WinExe 9 | Properties 10 | DotNetLicensing.Examples.Northwind 11 | DotNetLicensing.Examples.Northwind 12 | v4.5.2 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 4.0 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | MSBuild:Compile 57 | Designer 58 | 59 | 60 | 61 | 62 | MSBuild:Compile 63 | Designer 64 | 65 | 66 | App.xaml 67 | Code 68 | 69 | 70 | MainWindow.xaml 71 | Code 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | Code 80 | 81 | 82 | True 83 | True 84 | Resources.resx 85 | 86 | 87 | True 88 | Settings.settings 89 | True 90 | 91 | 92 | ResXFileCodeGenerator 93 | Resources.Designer.cs 94 | 95 | 96 | SettingsSingleFileGenerator 97 | Settings.Designer.cs 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | {18ba972c-45f0-476a-907d-ea7b549d478e} 107 | DotNetLicense 108 | 109 | 110 | 111 | 118 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/MVVM/DelegateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows.Input; 7 | 8 | namespace DotNetLicensing.Examples.Northwind.MVVM 9 | { 10 | public class DelegateCommand : ICommand 11 | { 12 | private readonly Action _action; 13 | 14 | public DelegateCommand(Action action) 15 | { 16 | _action = action; 17 | } 18 | 19 | public void Execute(object parameter) 20 | { 21 | _action(); 22 | } 23 | 24 | public bool CanExecute(object parameter) 25 | { 26 | return true; 27 | } 28 | 29 | public event EventHandler CanExecuteChanged; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/MVVM/ViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace DotNetLicensing.Examples.Northwind.MVVM 9 | { 10 | public class ViewModel : INotifyPropertyChanged 11 | { 12 | public event PropertyChangedEventHandler PropertyChanged; 13 | 14 | protected void RaisePropertyChangedEvent(string propertyName) 15 | { 16 | var handler = PropertyChanged; 17 | if (handler != null) 18 | handler(this, new PropertyChangedEventArgs(propertyName)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DotNetLicensing.Examples.Northwind/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |