суббота, 10 декабря 2011 г.

Custom protected storage

During a long time Manco .NET Licensing System supported 2 kinds of the protected storage: Windows Registry and Isolated Storage. No matter that it looks like enough for most .NET Framework scenarios there are environments and applications which require another approach. For example, Windows Azure Partial Trust role have not access to the Windows Registry or Isolated Storage.  To make it possible to use our protection library in those scenarios we introduced ability to create custom protected storage which will better suit the needs of your application.

In this article I’ll show how custom protected storage can be implemented using very simple scenario using temporary files.

Note: Pay attentions, this is just an example which demonstrates how the custom protected storage can be implemented. The temp folder isn't a good and secure place to store licensing information.

Mostly implementation of the license protection is the same as for other licensing schemas. The difference is in the protected storage only. We suppose that you have read at least “Quick Start” section in our product documentation, so we will show the peculiarity of the custom protected storage only.
First of all you should change mode of the protected storage in the License Manager to the “Custom”:



Now you should regenerate ILicenseKeyProvider and replace it in the protected application.

As next step you should create class which will implement Manco.Licensing.IProtectedStorage interface:
[C#]
 
/// <summary>
/// Custom protected storage which uses temporary file.
/// Pay attentions, this is just an example which demonstrates how the
/// custom protected storage can be implemented. The temp folder isn't a good
/// and secure place to store licensing information.
/// </summary>
public class TempFileProtectedStorage : IProtectedStorage
{
       public TempFileProtectedStorage()
       {
       }
           
       /// <summary>
       /// Gets or sets path of the temporary file.
       /// </summary>
       private string FilePath
       {
             get;
             set;
       } 

       /// <summary>
       /// Gets or sets protected assembly.
       /// </summary>
       private Assembly ProtectedAssembly
       {
             get;
             set;
       } 

       /// <summary>
       /// Dispose protected storage object
       /// </summary>
       public void Dispose()
       {
       } 

       /// <summary>
       /// Gets stream to read license document from the protected storage
       /// </summary>
       /// <returns>Stream to read document from</returns>
       public System.IO.Stream GetInputStream()
       {
             FileStream fileStream = File.Open(this.FilePath,
FileMode.OpenOrCreate,
FileAccess.ReadWrite,
FileShare.None);
             if (fileStream.Length > 0)
             {
                    StreamReader reader = new StreamReader(fileStream);
                    reader.ReadLine(); 

                    string lsEncrLicense = reader.ReadLine();
                    reader.Close();
                    fileStream.Close(); 

                    byte[] encrypted = Convert.FromBase64String(lsEncrLicense);
                    MemoryStream stream = new MemoryStream(encrypted); 

                    return stream;
             }
             else
             {
                    fileStream.Close();
                    return null;
             }
       } 

       /// <summary>
       /// Initialize protected storage.
       /// </summary>
       /// <param name="licenseKeyProvider">License key provider.</param>
       public void Initialize(ILicenseKeyProvider licenseKeyProvider)
       {
             this.FilePath = null; 

             // In this example we use name of the product to create
             // temporary folder.
             this.ProtectedAssembly = licenseKeyProvider.GetType().Assembly;
             AssemblyProductAttribute attribute =
                    (AssemblyProductAttribute)Attribute.GetCustomAttribute(
                    this.ProtectedAssembly, typeof(AssemblyProductAttribute));
             if (attribute != null && !string.IsNullOrEmpty(attribute.Product))
             {
                    string folderPath = Path.Combine(
Path.GetTempPath(), attribute.Product); 

                    if (!Directory.Exists(folderPath))
                    {
                           Directory.CreateDirectory(folderPath);
                    }                          

                    // Use public key as index to search license file.
                    string publicKey =
this.GetPublicKeyHexString(
this.ProtectedAssembly.GetName().GetPublicKey()); 

                    string[] files = Directory.GetFiles(folderPath);
                    foreach (string file in files)
                    {
                           try
                           {
                                  StreamReader loReader = new StreamReader(
File.Open(file,
FileMode.Open,
FileAccess.ReadWrite,
FileShare.None));
                                  string textLine = loReader.ReadLine();
                                  loReader.Close(); 

                                  if (textLine == publicKey)
                                  {
                                        this.FilePath = file;
                                        break;
                                  }
                           }
                           catch
                           {
                           }
                    }

                    if (this.FilePath == null)
                    {
                           this.FilePath = Path.Combine(
folderPath,
Path.GetRandomFileName());
                    }
             }
             else
             {
                    throw new ArgumentException("Product name isn't set in the protected assembly!");
             }
       } 

       /// <summary>
       /// Write byte array to the protected storage.
       /// </summary>
       /// <param name="toWrite">Byte array to write.</param>
       public void WriteByteArray(byte[] toWrite)
       {
             if (!string.IsNullOrEmpty(this.FilePath))
             {
                    FileStream fileStream = File.Open(
this.FilePath,
FileMode.Create,
FileAccess.Write,
FileShare.None);
                    StreamWriter writer = new StreamWriter(fileStream);
                    string publicKey = this.GetPublicKeyHexString(
this.ProtectedAssembly.GetName().GetPublicKey());
                    writer.WriteLine(publicKey); 

                    string lsEncrLicense = Convert.ToBase64String(toWrite);
                    writer.WriteLine(lsEncrLicense); 

                    writer.Close();
                    fileStream.Close();
             }
       } 

       private string GetPublicKeyHexString(byte[] publicKey)
       {
             string stringKey = string.Empty; 

             foreach (byte b in publicKey)
             {
                    stringKey += b.ToString("X2");
             } 

             return stringKey;
       }
}

[VB.NET]

''' <summary>
''' Custom protected storage which uses temporary file.
''' Pay attentions, this is just an example which demonstrates how the
''' custom protected storage can be implemented. The temp folder isn't a good
''' and secure place to store licensing information.
''' </summary>
Public Class TempFileProtectedStorage
       Implements IProtectedStorage 

       Public Sub New()
       End Sub 

       ''' <summary>
       ''' Gets or sets path of the temporary file.
       ''' </summary>
       Private Property FilePath() As String
             Get
                    Return m_FilePath
             End Get
             Set(value As String)
                    m_FilePath = value
             End Set
       End Property
       Private m_FilePath As String 

       ''' <summary>
       ''' Gets or sets protected assembly.
       ''' </summary>
       Private Property ProtectedAssembly() As Assembly
             Get
                    Return m_ProtectedAssembly
             End Get
             Set(value As Assembly)
                    m_ProtectedAssembly = value
             End Set
       End Property
       Private m_ProtectedAssembly As Assembly 

       ''' <summary>
       ''' Dispose protected storage object
       ''' </summary>
       Public Sub Dispose() _
        Implements IProtectedStorage.Dispose
       End Sub 

       ''' <summary>
       ''' Gets stream to read license document from the protected storage
       ''' </summary>
       ''' <returns>Stream to read document from</returns>
       Public Function GetInputStream() As System.IO.Stream _
         Implements IProtectedStorage.GetInputStream
             Dim fileStream As FileStream = File.Open( _
              Me.FilePath, _
              FileMode.OpenOrCreate, _
              FileAccess.ReadWrite, _
              FileShare.None)
             If fileStream.Length > 0 Then
                    Dim reader As New StreamReader(fileStream)
                    reader.ReadLine() 
                    Dim lsEncrLicense As String = reader.ReadLine()
                    reader.Close()
                    fileStream.Close()
                    Dim encrypted As Byte() = Convert.FromBase64String(lsEncrLicense)
                    Dim stream As New MemoryStream(encrypted)
                    Return stream
             Else
                    fileStream.Close()
                    Return Nothing
             End If
       End Function 

       ''' <summary>
       ''' Initialize protected storage.
       ''' </summary>
       ''' <param name="licenseKeyProvider">License key provider.</param>
       Public Sub Initialize(licenseKeyProvider As ILicenseKeyProvider) _
        Implements IProtectedStorage.Initialize
             Me.FilePath = Nothing 

             ' In this example we use name of the product to create
             ' temporary folder.
             Me.ProtectedAssembly = licenseKeyProvider.[GetType]().Assembly
             Dim productAttribute As AssemblyProductAttribute = _
              DirectCast(Attribute.GetCustomAttribute(Me.ProtectedAssembly, _
                              GetType(AssemblyProductAttribute)), AssemblyProductAttribute)
             If productAttribute IsNot Nothing _
              AndAlso Not String.IsNullOrEmpty(productAttribute.Product) Then
                    Dim folderPath As String = System.IO.Path.Combine( _
                     System.IO.Path.GetTempPath(), productAttribute.Product) 

                    If Not Directory.Exists(folderPath) Then
                           Directory.CreateDirectory(folderPath)
                    End If 

                    ' Use public key as index to search license file.
                    Dim publicKey As String = Me.GetPublicKeyHexString( _
                     Me.ProtectedAssembly.GetName().GetPublicKey()) 

                    Dim files As String() = Directory.GetFiles(folderPath)
                    For Each fileName As String In files
                           Try
                                  Dim loReader As New StreamReader( _
                                   File.Open(fileName, _
                                         FileMode.Open, _
                                         FileAccess.ReadWrite, _
                                         FileShare.None))
                                  Dim textLine As String = loReader.ReadLine()
                                  loReader.Close() 

                                  If textLine = publicKey Then
                                        Me.FilePath = fileName
                                        Exit Try
                                  End If
                           Catch
                           End Try
                    Next 

                    If Me.FilePath Is Nothing Then
                           Me.FilePath = System.IO.Path.Combine( _
                            folderPath, System.IO.Path.GetRandomFileName())
                    End If
             Else
                    Throw New ArgumentException("Product name isn't set in the protected assembly!")
             End If
       End Sub

       ''' <summary>
       ''' Write byte array to the protected storage.
       ''' </summary>
       ''' <param name="toWrite">Byte array to write.</param>
       Public Sub WriteByteArray(toWrite As Byte()) _
        Implements IProtectedStorage.WriteByteArray
             If Not String.IsNullOrEmpty(Me.FilePath) Then
                    Dim fileStream As FileStream = File.Open( _
                     Me.FilePath, _
                     FileMode.Create, _
                     FileAccess.Write, _
                     FileShare.None)
                    Dim writer As New StreamWriter(fileStream)
                    Dim publicKey As String = Me.GetPublicKeyHexString( _
                     Me.ProtectedAssembly.GetName().GetPublicKey())
                    writer.WriteLine(publicKey) 

                    Dim lsEncrLicense As String = Convert.ToBase64String(toWrite)
                    writer.WriteLine(lsEncrLicense) 

                    writer.Close()
                    fileStream.Close()
             End If
       End Sub 

       Private Function GetPublicKeyHexString(publicKey As Byte()) As String
             Dim stringKey As String = String.Empty 

             For Each b As Byte In publicKey
                    stringKey += b.ToString("X2")
             Next 

             Return stringKey
       End Function
End Class

The final step you have to do is informing the protection library about class which implements custom protected storage:

[C#]
// Instantiate license object and assign assemblies for validation.
this.license = (Manco.Licensing.License)LicenseManager.Validate(
             typeof(MainWindow), this); 

// Set type which implements custom protected storage.
// It must be done before any other operations with license object.
this.license.CustomProtectedStorageType = typeof(TempFileProtectedStorage); 

this.license.LicensedAssembly = typeof(MainWindow).Assembly;
this.licenseProperties = this.license.GetLicenseProperties();
this.licenseState = this.license.GetLicenseState(true); 

[VB.NET]
' Instantiate license object and assign assemblies for validation.
Me.license = LicenseManager.Validate(GetType(MainWindow), Me)

' Set type which implements custom protected storage.
' It must be done before any other operations with license object.
Me.license.CustomProtectedStorageType = GetType(TempFileProtectedStorage)
Me.license.LicensedAssembly = GetType(MainWindow).Assembly
Me.licenseProperties = Me.license.GetLicenseProperties()
Me.licenseState = Me.license.GetLicenseState(True)

You can find sample solution which demonstrates creation of the custom protected storage at the http://www.mancosoftware.com/licensing/download.htm.

Комментариев нет:

Отправить комментарий