【问题标题】:key for software软件钥匙
【发布时间】:2012-04-20 00:58:09
【问题描述】:

我想使用 RSA 密钥设计产品密钥,但我不知道我的想法是否安全。

我对设计产品密钥的想法:

我有一对密钥 例如

公钥是: MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQG…

私钥是: MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ…

我这样创建产品密钥:
(例如,私钥的开头)MIICWwIBAAKBgQDRh

并将其从软件中的私钥中删除

当用户没有产品密钥时无法解码密钥

【问题讨论】:

    标签: rsa licensing license-key


    【解决方案1】:

    这不是您应该将公钥/私钥用于产品密钥的方式。

    更好的实施

    您可以创建一个 XML 文档来描述启用的功能。或者只是简单的客户姓名和日期。

    <license>
        <name>Acme Co.</name>
        <expiration>20120304</expiration>
    </license>
    

    您使用私钥对 XML 文档进行签名,并将散列和签名与文档一起存储。然后,您可以使用之前生成的公钥验证产品中的 XML 文档。

    签署文件的结果:

    <license>
        <name>Acme Co.</name>
        <expiration>20120304</expiration>
        <signature>
            <hash>1230u4woeifhljksdkvh23p9</hash>
            <value>sdvrrvLJbmyscoVMg2pZZAtZJbBHsZFUCwE4Udv+u3TfiAms2HpLgN3cL
          NtRlxyQpvWt1FKAB/SCk1jr0IasdfeDOOHhTUTyiv2vMJgCRecC1PLcrmR9ABhqk
          itsjzrCt7V3eF5SpObdUFqcj+n9gasdfdQtlQeWcvKEcg=</value>
        </signature>
    </license>
    

    如果用户更改许可文件的内容,则签名将不再匹配。他们也将无法重新签署文档,因为他们无权访问您的私钥。这很重要,您将 PUBLIC 密钥与您的产品一起发送,而不是私钥。

    快捷键实现

    1. 选择产品代码(一些随机字符串来识别您的产品
    2. 在产品代码中添加已知盐
    3. 根据用户名创建一个加密密钥。检查以确保其有效。
    4. 用新密钥加密盐+产品代码
    5. 根据加密结果构建人类可读的密钥。

    它看起来像 1234-1234-1234-1234

    C#解决方案:

    /// <summary>
    /// Provides the ability to generate and validate license keys based
    /// on a product code.
    /// </summary>
    public class LicenseKeyManager
    {
        /// <summary>
        /// Construct a new LicenseKeyManager
        /// </summary>
        public LicenseKeyManager()
        {
            crypto = new DESCryptoServiceProvider ();
        }
    
        /// <summary>
        /// Set or get the product code. Once the product code
        /// is manually set it will no longer be automatically 
        /// generated for this instance. Suggested to not 
        /// set the product code unless generating keys.
        /// 
        /// In this instance the ProductCode is a string
        /// that identifies the machine that the license needs
        /// to be generated on. This prevents the distribution
        /// of keys among friends.
        /// </summary>
        public String ProductCode
        {
            set
            {
                productCode = value;
            }
            get
            {
                if (productCode == null)
                    productCode = Ethernet.MacAddress.Replace (":", "");
    
                return productCode;
            }
        }
    
        /// <summary>
        /// A salt that can be added to the product code to ensure that
        /// different keys are generated for different products or
        /// companies. 
        /// Once set the salt cannot be retrieved from this object.
        /// </summary>
        public String Salt
        {
            set
            {
                salt = value;
            }
        }
    
        /// <summary>
        /// Validate a license key
        /// </summary>
        /// <param name="name">Name associated with the license key</param>
        /// <param name="key">The license key</param>
        /// <returns>True if the license key is valid</returns>
        public bool IsValidKey (String name, String key)
        {
            if (name == null || key == null) return false;
            String license = CreateLicense (name);
            return license.CompareTo (key) == 0;
        }
    
        /// <summary>
        /// Create a new license key associated with the given name. The key
        /// will be the same if this method is reinvoked with the same name and
        /// product code.
        /// </summary>
        /// <param name="name">Name to associate with the license key</param>
        /// <returns>New License Key</returns>
        public String CreateLicense (String name)
        {
            String licenseSource = ProductCode;
    
            if (salt != null)
                licenseSource = salt + licenseSource;
    
            byte[] license = Encrypt(licenseSource, name);
    
            if (license.Length > 16)
            {
                byte[] tmp = new byte[16];
                Array.Copy (license, tmp, 16);
                license = tmp;
            }
            else if (license.Length < 16)
            {
                byte[] tmp = 
                    new byte[] {
                        36, 36, 36, 36, 36, 36, 36, 36,
                        36, 36, 36, 36, 36, 36, 36, 36};
                Array.Copy (license, tmp, license.Length);
                license = tmp;
            }
    
            StringBuilder sb = 
                new StringBuilder ();
    
            String base64License =          
                Convert.ToBase64String (license).ToUpper();
            base64License = base64License.Replace ('+', 'F');
            base64License = base64License.Replace ('/', 'A');
    
            // Format the license key in a human readable format.
            // We dont need all of the license key just enough
            // so that it isn't predictable. This key won't be
            // used in decrypting the license, only in comparision
            // similar to that when hasing passwords.
            sb.AppendFormat (
                "{0}{1}{2}{3}-{4}{5}{6}{7}-" +
                "{8}{9}{10}{11}-{12}{13}{14}{15}",
                base64License[0], base64License[1], 
                base64License[2], base64License[3], 
                base64License[4], base64License[5], 
                base64License[6], base64License[7], 
                base64License[8], base64License[9], 
                base64License[10],base64License[11], 
                base64License[12],base64License[13], 
                base64License[14],base64License[15]);
    
            return sb.ToString();
        }
    
        private byte[] GetLegalKey(string Key) 
        {
            string sTemp = Key;
            crypto.GenerateKey();
            byte[] bytTemp = crypto.Key;
            int KeyLength = bytTemp.Length;
            if (sTemp.Length > KeyLength)
                sTemp = sTemp.Substring(0, KeyLength);
            else if (sTemp.Length < KeyLength)
                sTemp = sTemp.PadRight(KeyLength, ' ');
    
            return ASCIIEncoding.ASCII.GetBytes(sTemp);
        }
    
        private byte[] Encrypt(string Source, string Key) 
        {
            // use UTF8 unicode conversion for two byte characters
            byte[] byteIn = UTF8Encoding.UTF8.GetBytes(Source);
    
            // set the private key
            crypto.Key = GetLegalKey(Key);
            crypto.IV = iv;
    
            // create an Encryptor from the Provider Service instance
            ICryptoTransform encryptor = crypto.CreateEncryptor();
    
            // convert into Base64 so that the result can be used in xml
            return encryptor.TransformFinalBlock (
                    byteIn, 0, byteIn.Length);
        }
    
        private static byte[] iv = new byte[] {63,63,63,63,63,63,63,63};
        private String productCode;
        private String salt;
        private SymmetricAlgorithm crypto;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-16
      相关资源
      最近更新 更多