सी#: एक साधारण लाइसेंस कुंजी/कॉल चेकलाइसेंस को कैसे कार्यान्वित करें()


क्या स्थिर वर्ग की प्रत्येक विधि में चेकलाइसेंस() विधि को स्वचालित रूप से कॉल करने का कोई तरीका है?

मेरे पास सैकड़ों विधियों वाली कई स्थिर कक्षाएं हैं।
इसलिए वैश्विक लाइसेंस जांच प्रत्येक क्लास विधि में चेकलाइसेंस() विधि को कॉल करने से अधिक आरामदायक होगी।

उदाहरण की व्याख्या:
लाइसेंसकी स्टार्टअप पर एप्लिकेशन द्वारा सेट की जाती है।
तो लाइसेंस पूरे जीवन भर के लिए ठीक है.

मैं AddMethod() में CheckLicence() कॉल से छुटकारा पाना चाहता हूं।

पृष्ठभूमि:
मेरे पास एक बड़ी टूल लाइब्रेरी है जिसका उपयोग कई परियोजनाओं में किया जाता है। लाइब्रेरी मेरी परियोजनाओं (वेबसाइटों, डेस्कटॉप एप्लिकेशन) में तैनात है। मैं बुनियादी सुरक्षा चाहता हूं ताकि ग्राहक सीधे अपनी आंतरिक परियोजनाओं में डीएलएल का उपयोग न कर सकें।

मैंने क्या प्रयास किया है:

public static class LicensedClass
{
    public static string licenceKey = "";

    public static bool IsLicensed
    {
        get { return (licenceKey == "ABC123"); }
    }

    public static void CheckLicence()
    {
        if (!IsLicensed) 
                throw new System.ArgumentException("Wrong licence key.", licenceKey);
    }

    public static double AddMethod(double number1, double number2)
    {
        CheckLicence();

        return number1 + number2;
    }
}

समाधान 1

नहीं।

C# आपके लिए स्वचालित रूप से कुछ भी कॉल नहीं करेगा – आपको इसे स्पष्ट रूप से बताना होगा कि आप क्या कॉल करना चाहते हैं, और कब।

आप हमेशा एक द्वितीयक थ्रेड कार्य जोड़ सकते हैं जो इसे समय-समय पर जांचता है, और मुख्य थ्रेड पर “विफल” संकेतक के साथ प्रतिक्रिया करता है कि यह इसके बजाय प्रक्रिया कर सकता है?

समाधान 2

आप देख सकते हैं एओपी (पहलू आधारित प्रोग्रामिंग): GitHub – Virtuoze/NCConcern: NConcern .NET AOP फ्रेमवर्क[^]

लेकिन आपको लग सकता है कि आप जो चाहते हैं उसके लिए यह बहुत जटिल है…

एक अन्य विकल्प प्रसिद्ध का उपयोग करना है पोस्टशार्प विस्तार: पोस्टशार्प – विजुअल स्टूडियो मार्केटप्लेस[^]

समाधान 3

स्टैटिक क्लास कंस्ट्रक्टर में लाइसेंस जांच के साथ हल किया गया।
यह मेरे डीएलएल को कंपनी में अन्य लोगों द्वारा पुन: उपयोग किए जाने से बचाने के लिए एक बहुत ही बुनियादी समाधान है।
यदि कुछ तरीके काम करते हैं और अन्य नहीं करते हैं तो लोगों को यह बहुत कष्टप्रद लग सकता है यदि यह “लाइसेंस प्राप्त” नहीं है, तो यह पर्याप्त है।
यदि विधि इतनी महत्वपूर्ण है कि मूल कोड को डीएलएल से आसानी से बहाल किया जा सकता है, तो .net में तीसरे पक्ष के टूल के बिना कोई कोड सुरक्षा नहीं है…

उपयोग:

2सी#”
DllClassLibrary.License.SetLicense("ABC123");
var result = DllClassLibrary.Foo.DoSomething();

सरल लाइसेंस जांच के साथ डीएलएल-क्लास-लाइब्रेरी:

सी#
namespace DllClassLibrary
{
    public static class License
    {
        private static bool isLicensed = false;
        public static bool SetLicense(string licenseKey)
        {
            isLicensed = (licenseKey == "ABC123");
            return isLicensed;
        }
        public static void CheckLicense()
        {
            if (!isLicensed)
                throw new Exception("License not set.");
        }
    }
    public static class Foo
    {
        static Foo()
        {
            License.CheckLicense();
        }
        public static string DoSomething()
        {
            return $"[{DateTime.Now.ToString()}] DoFoo()";
        }
    }
}

समाधान 4

सक्रियण कुंजी

यहां सक्रियण कुंजी की एक सरल संरचना दी गई है:

<code>class ActivationKey
{
    public byte[] Data { get; set; } // Encrypted part.
    public byte[] Hash { get; set; } // Hashed part.
    public byte[] Tail { get; set; } // Initialization vector.
}
</code>
<p>This tool will use cryptographic transformations to generate the key.</p>
<h2>Generating</h2>
<p>The algorithm for obtaining a unique activation key for a data set consists of several steps:</p>
<ul>
<li>data collection,</li>
<li>getting the hash and data encryption,</li>
<li>converting activation key to string.</li>
</ul>
<h3>Data collection</h3>
<p>At this step, you need to get an array of data such as serial number, device ID, expiration date, etc. This purpose can be achieved using the following method:</p>
<pre class="lang-cs prettyprint-override"><code>unsafe byte[] Serialize(params object[] objects)
{
  using (MemoryStream memory = new MemoryStream())
  using (BinaryWriter writer = new BinaryWriter(memory))
  {
    foreach (object obj in objects)
    {
      if (obj == null) continue;
      switch (obj)
      {
        case string str:
          if (str.Length > 0)
            writer.Write(str.ToCharArray());
          continue;
        case DateTime date:
          writer.Write(date.Ticks);
          continue;
        case bool @bool:
          writer.Write(@bool);
          continue;
        case short @short:
          writer.Write(@short);
          continue;
        case ushort @ushort:
          writer.Write(@ushort);
          continue;
        case int @int:
          writer.Write(@int);
          continue;
        case uint @uint:
          writer.Write(@uint);
          continue;
        case long @long:
          writer.Write(@long);
          continue;
        case ulong @ulong:
          writer.Write(@ulong);
          continue;
        case float @float:
          writer.Write(@float);
          continue;
        case double @double:
          writer.Write(@double);
          continue;
        case decimal @decimal:
          writer.Write(@decimal);
          continue;
        case byte[] buffer:
          if (buffer.Length > 0)
            writer.Write(buffer);
          continue;
        case Array array:
          if (array.Length > 0)
            foreach (var a in array) writer.Write(Serialize(a));
          continue;
        case IConvertible conv:
          writer.Write(conv.ToString(CultureInfo.InvariantCulture));
          continue;
        case IFormattable frm:
          writer.Write(frm.ToString(null, CultureInfo.InvariantCulture));
          continue;
        case Stream stream:
          stream.CopyTo(stream);
          continue;
        default:
          try
          {
            int rawsize = Marshal.SizeOf(obj);
            byte[] rawdata = new byte[rawsize];
            GCHandle handle = GCHandle.Alloc(rawdata, GCHandleType.Pinned);
            Marshal.StructureToPtr(obj, handle.AddrOfPinnedObject(), false);
            writer.Write(rawdata);
            handle.Free();
          }
          catch(Exception e)
          {
            // Place debugging tools here.
          }
          continue;
      }
    }
    writer.Flush();
    byte[] bytes = memory.ToArray();
    return bytes;
  }
}
</code>

हैश और डेटा एन्क्रिप्शन प्राप्त करना

इस चरण में निम्नलिखित उपचरण शामिल हैं:

  • पासवर्ड का उपयोग करके एक एन्क्रिप्शन इंजन बनाएं और इनिशियलाइज़ेशन वेक्टर को इसमें संग्रहीत करें पूँछ संपत्ति।
  • अगले चरण में, समाप्ति तिथि और विकल्प एन्क्रिप्ट किए जाते हैं और एन्क्रिप्टेड डेटा को इसमें सहेजा जाता है डेटा संपत्ति।
  • अंत में, हैशिंग इंजन समाप्ति तिथि, पासवर्ड, विकल्प और वातावरण के आधार पर हैश की गणना करता है और इसे इसमें डालता है हैश संपत्ति।

ActivationKey Create<TAlg, THash>(DateTime expirationDate, 
                                  object password, 
                                  object options = null, 
                                  params object[] environment)
    where TAlg : SymmetricAlgorithm
    where THash : HashAlgorithm
{
    ActivationKey activationKey = new ActivationKey();
    using (SymmetricAlgorithm cryptoAlg = Activator.CreateInstance<TAlg>())
    {
        if (password == null)
        {
            password = new byte[0];
        }
        activationKey.Tail = cryptoAlg.IV;
        using (DeriveBytes deriveBytes = 
        new PasswordDeriveBytes(Serialize(password), activationKey.Tail))
        {
            cryptoAlg.Key = deriveBytes.GetBytes(cryptoAlg.KeySize / 8);
        }
        expirationDate = expirationDate.Date;
        long expirationDateStamp = expirationDate.ToBinary();
        using (ICryptoTransform transform = cryptoAlg.CreateEncryptor())
        {
            byte[] data2 = Serialize(expirationDateStamp, options);
            activationKey.Data = transform.TransformFinalBlock(data2, 0, data2.Length);
        }
        using (HashAlgorithm hashAlg = Activator.CreateInstance<THash>())
        {
            byte[] data = Serialize(expirationDateStamp, 
                                    cryptoAlg.Key, 
                                    options, 
                                    environment, 
                                    activationKey.Tail);
            activationKey.Hash = hashAlg.ComputeHash(data);
        }
    }
    return activationKey;
}

स्ट्रिंग में कनवर्ट करना

मुख्य पाठ वाली एक स्ट्रिंग प्राप्त करने के लिए ToString विधि का उपयोग करें, जो अंतिम उपयोगकर्ता को स्थानांतरित करने के लिए तैयार है।

एन-आधारित एन्कोडिंग (जहां एन संख्या प्रणाली का आधार है) का उपयोग अक्सर बाइनरी डेटा को मानव-पठनीय पाठ में परिवर्तित करने के लिए किया जाता था। सक्रियण कुंजी में सबसे अधिक उपयोग की जाने वाली कुंजी बेस32 है। इस एन्कोडिंग का लाभ एक बड़ी वर्णमाला है जिसमें संख्याएं और अक्षर शामिल होते हैं जो केस असंवेदनशील होते हैं। नकारात्मक पक्ष यह है कि यह एन्कोडिंग .NET मानक लाइब्रेरी में लागू नहीं है और आपको इसे स्वयं लागू करना चाहिए। इस साइट पर बेस32 कार्यान्वयन के कई उदाहरण हैं। आप mscorlib में निर्मित हेक्स एन्कोडिंग और बेस64 का भी उपयोग कर सकते हैं। मेरे उदाहरण में बेस32 प्रयोग किया जाता है।

string ToString(ActivationKey activationKey)
{
    if (activationKey.Data == null 
       || activationKey.Hash == null 
       || activationKey.Tail == null)
    {
        return string.Empty;
    }
    using (Base32 base32 = new Base32())
    {
        return base32.Encode(Data) + "-" + base32.Encode(Hash) + "-" +
        base32.Encode(Tail);
    }
}

चेकिंग

कुंजी सत्यापन GetOptions और Verify विधियों का उपयोग करके किया जाता है।

  • विकल्प प्राप्त करें कुंजी की जांच करता है और यदि कुंजी मान्य नहीं है तो एंबेडेड डेटा को बाइट सरणी या शून्य के रूप में पुनर्स्थापित करता है।
  • सत्यापित करें बस कुंजी की जांच करता है.

byte[] GetOptions<TAlg, THash>(object password = null, params object[] environment)
    where TAlg : SymmetricAlgorithm
    where THash : HashAlgorithm
{
    if (Data == null || Hash == null || Tail == null)
    {
        return null;
    }
    try
    {
        using (SymmetricAlgorithm cryptoAlg = Activator.CreateInstance<TAlg>())
        {
            cryptoAlg.IV = Tail;
            using (DeriveBytes deriveBytes = 
            new PasswordDeriveBytes(Serialize(password), Tail))
            {
                cryptoAlg.Key = deriveBytes.GetBytes(cryptoAlg.KeySize / 8);
            }
            using (ICryptoTransform transform = cryptoAlg.CreateDecryptor())
            {
                byte[] data = transform.TransformFinalBlock(Data, 0, Data.Length);
                int optionsLength = data.Length - 8;
                if (optionsLength < 0)
                {
                    return null;
                }
                byte[] options;
                if (optionsLength > 0)
                {
                    options = new byte[optionsLength];
                    Buffer.BlockCopy(data, 8, options, 0, optionsLength);
                }
                else
                {
                    options = new byte[0];
                }
                long expirationDateStamp = BitConverter.ToInt64(data, 0);
                DateTime expirationDate = DateTime.FromBinary(expirationDateStamp);
                if (expirationDate < DateTime.Today)
                {
                    return null;
                }
                using (HashAlgorithm hashAlg = 
                Activator.CreateInstance<THash>())
                {
                    byte[] hash = 
                    hashAlg.ComputeHash(
                         Serialize(expirationDateStamp, 
                                   cryptoAlg.Key, 
                                   options, 
                                   environment, 
                                   Tail));
                    return ByteArrayEquals(Hash, hash) ? options : null;
                }
            }
        }
    }
    catch
    {
        return null;
    }
}

bool Verify<TAlg, THash>(object password = null, params object[] environment)
    where TAlg : SymmetricAlgorithm
    where THash : HashAlgorithm
{
    try
    {
        byte[] key = Serialize(password);
        return Verify<TAlg, THash>(key, environment);
    }
    catch
    {
        return false;
    }
}

उदाहरण

यहाँ किसी भी मात्रा में डेटा – टेक्स्ट, स्ट्रिंग्स, संख्याएं, बाइट्स इत्यादि के अपने संयोजन का उपयोग करके सक्रियण कुंजी उत्पन्न करने का एक पूर्ण उदाहरण है।

उपयोग का उदाहरण:

string serialNumber = "0123456789"; // The serial number.
const string appName = "myAppName"; // The application name.

// Generating the key. All the parameters passed to the costructor can be omitted.
ActivationKey activationKey = new ActivationKey(
//expirationDate:
DateTime.Now.AddMonths(1),  // Expiration date 1 month later.
                            // Pass DateTime.Max for unlimited use.
//password:
null,                       // Password protection;
                            // this parameter can be null.
//options:
null                       // Pass here numbers, flags, text or other
                           // that you want to restore 
                           // or null if no necessary.
//environment:
appName, serialNumber      // Application name and serial number.
);
// Thus, a simple check of the key for validity is carried out.
bool checkKey = activationKey.Verify((byte[])null, appName, serialNumber);
if (!checkKey)
{
  MessageBox.Show("Your copy is not activated! Please get a valid activation key.");
  Application.Exit();
}

GitHub – ng256/सक्रियण-कुंजी: आपके C# एप्लिकेशन की सुरक्षा के लिए उपयोग की जाने वाली सक्रियण कुंजी का प्रतिनिधित्व करता है।[^]

コメント

タイトルとURLをコピーしました