软件的关键

时间:2012-04-06 11:39:57

标签: rsa licensing license-key

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

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

我有一对钥匙 例如

公钥是: MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQG…

私钥是: MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ…

我创建了这样的产品密钥:
(开始使用eaxmple的私钥)MIICWwIBAAKBgQDRh

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

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

1 个答案:

答案 0 :(得分:9)

这不是您应该如何使用公钥/私钥来生成产品密钥。

更好的实施

您可以创建描述已启用功能的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. 使用新密钥加密salt +产品代码
  5. 从加密结果中构建人类可读密钥。
  6. 看起来像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;
    }