使用TrueLicense来保护我们的JAVA软件产品

[转载]使用TrueLicense来保护我们的JAVA软件产品

我们的JAVA软件产品有时需要限制非法用户,只有购买了LICENSE的用户才能使用,因此,我们可以通过TrueLicense来实现。

首先要用KeyTool工具来生成私匙库:

keytool -genkey -alias privatekey -keystore privateKeys.store

然后把私匙库内的公匙导出到一个文件当中:

keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store

然后再把这个证书文件导入到公匙库:

keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store
服务器端利用私匙库来创建license的代码例子:
package com.sourceware.license ;

import de.schlichtherle.license.*
;
import java.io.* ;
import java.util.* ;
import javax.security.auth.x500.X500Principal ;
import java.util.prefs.Preferences ;

/**
 * <p>Title: CMVP通用媒体增值业务平台</p>
 *
 * <p>Description: CMVP通用媒体增值业务平台</p>
 *
 * <p>Copyright: Copyright (c) 
2005 </p>
 *
 * <p>Company: source-ware.com inc.</p>
 *
 * @author 黑山
 * @version 
2.0
 */
public class SWLicenseManager {
  public SWLicenseManager() {
  }

  LicenseContent verifyLicenseKey(LicenseParam parameter) {
    // Create a configured license manager.
    LicenseManager manager 
=  new LicenseManager(parameter) ;
    try {
      // Verify the previously installed current license certificate.
      return manager.verify()
;
    }
    catch (Exception exc) {
      System.err.println(
" Could not verify license key " ) ;
      exc.printStackTrace() ;
      return null ;
    }
  }

  void installLicenseKey(LicenseParam parameter
,  File keyFile) {
    // Create a configured license manager.
    LicenseManager manager 
=  new LicenseManager(parameter) ;
    try {
      // Load the license key
,  verify and install it as the current license key.
      manager.install(keyFile)
;
    }
    catch (Exception exc) {
      System.err.println(
" Could not install license certificate " ) ;
      exc.printStackTrace() ;
    }
  }

  void createLicenseKey(LicenseParam parameter
,  LicenseContent content) {
    // Create a configured license manager.
    LicenseManager manager 
=  new LicenseManager(parameter) ;
    try {
      // Create the license key from the license content and save it to a file.
      manager.store(content
,  new File( " license.lic " )) ;
    }
    catch (Exception exc) {
      System.err.println(
" Could not save license key " ) ;
      exc.printStackTrace() ;
    }
  }

  //
  // Customizable global properties.
  //

  /** The product id of your software */
  public static final String PRODUCT_ID 
=   " cmvp20 " ;  // CUSTOMIZE

  /**
   * The subject for the license manager and also the alias of the private
   * key entry in the keystore.
   */
  public static final String SUBJECT 
=   " 别名 " ;  // CUSTOMIZE

  /** The resource name of your private keystore file. */
  public static final String KEYSTORE_RESOURCE 
=   " 私匙库文件名 " ;  // CUSTOMIZE

  /** The password for the keystore. */
  public static final String KEYSTORE_STORE_PWD 
=   " 私匙库密码 " ;  // CUSTOMIZE

  /* The password for the private key entry in the keystore. */
  public static final String KEYSTORE_KEY_PWD 
=   " 私匙库主键密码 " ;  // CUSTOMIZE

  /** The password to encrypt the generated license key file. */
  public static final String CIPHER_KEY_PWD 
=   " 即将生成的license密码 " ;  // CUSTOMIZE

  /**
   * The filename to be displayed for the generated binary key file when
   * delivered. Please note that this is not used to write to a file of
   * this name.
   */
  public static final String DISPLAY_FILENAME 
=   " license.lic " ;  // CUSTOMIZE

  //
  // The rest of this key generator does not need to get customized.
  //

  /** The MIME type of the generated binary key file. */
  public static final String MIME_TYPE 
=   " application/octet-stream " ;

  //
  // Possible key generator exit codes
  //

  /**
   * Return <code>ERC_SUCCESS</code> on succesful creation of a textual key.
   * Note that this example creates a binary key and thus this constant is not
   * used here
   */
  //public static final int ERC_SUCCESS 
=   00 ;

  /**
   * Return <code>ERC_SUCCESS_BIN</code> on succesful creation of a binary
   * key. (Which could contain text as well
,  if the content type is specified
   * as <code>text/plain</code>)
   */
  public static final int ERC_SUCCESS_BIN 
=   01 ;

  /**
   * Return <code>ERC_ERROR</code> for general errors.
   */
  public static final int ERC_ERROR 
=   10 ;

  /**
   * Return <code>ERC_MEMORY</code> if memory allocation fails.
   */
  public static final int ERC_MEMORY 
=   11 ;

  /**
   * Return <code>ERC_FILE_IO</code> on IOException
   */
  public static final int ERC_FILE_IO 
=   12 ;

  /**
   * Return <code>ERC_BAD_ARGS</code> if the command line parameters are
   * bad.
   */
  public static final int ERC_BAD_ARGS 
=   13 ;

  /**
   * Return <code>ERC_BAD_INPUT</code> if a particular input value is
   * missing or has a bad value. Don't forget to supply a meaningful error
   * message naming the exact cause of the error.
   */
  public static final int ERC_BAD_INPUT 
=   14 ;

  /**
   * Return <code>ERC_EXPIRED</code> if this generator is expired. This can
   * be used to limit the lifetime of this generator.
   */
  //public static final int ERC_EXPIRED 
=   15 ;

  /**
   * Return <code>ERC_INTERNAL</code> if an unhandled exception occurs.
   *
   * @see java.lang.Exception
   */
  //public static final int ERC_INTERNAL 
=   16 ;

  /** Encoding keys in properties. */
  public static final String ENCODING_KEY 
=   " ENCODING " ;
  public static final String PRODUCT_ID_KEY  =   " PRODUCT_ID " ;
  public static final String PURCHASE_ID_KEY  =   " PURCHASE_ID " ;
  public static final String RUNNING_NO_KEY  =   " RUNNING_NO " ;
  public static final String PURCHASE_DATE_KEY  =   " PURCHASE_DATE " ;
  public static final String LANGUAGE_ID_KEY  =   " LANGUAGE_ID " ;
  public static final String QUANTITY_KEY  =   " QUANTITY " ;
  public static final String REG_NAME_KEY  =   " REG_NAME " ;
  public static final String ADDITIONAL1_KEY  =   " ADDITIONAL1 " ;
  public static final String ADDITIONAL2_KEY  =   " ADDITIONAL2 " ;
  public static final String RESELLER_KEY  =   " RESELLER " ;
  public static final String LASTNAME_KEY  =   " LASTNAME " ;
  public static final String FIRSTNAME_KEY  =   " FIRSTNAME " ;
  public static final String COMPANY_KEY  =   " COMPANY " ;
  public static final String EMAIL_KEY  =   " EMAIL " ;
  public static final String PHONE_KEY  =   " PHONE " ;
  public static final String FAX_KEY  =   " FAX " ;
  public static final String STREET_KEY  =   " STREET " ;
  public static final String ZIP_KEY  =   " ZIP " ;
  public static final String CITY_KEY  =   " CITY " ;
  public static final String STATE_KEY  =   " STATE " ;
  public static final String COUNTRY_KEY  =   " COUNTRY " ;

  /** Default encoding for properties. */
  public static final String ENCODING_PROPERTIES 
=   " ISO-8859-1 " ;

  /** Default share-it encoding if key not present in properties. */
  public static final String ENCODING_DEFAULT 
=  ENCODING_PROPERTIES ;

  protected static final LicenseManager manager 
=  new LicenseManager(
      new DefaultLicenseParam(
          SUBJECT
,
          Preferences.userRoot()
,
          new DefaultKeyStoreParam(
              SWLicenseManager.class
,  // CUSTOMIZE
              KEYSTORE_RESOURCE
,
              SUBJECT
,
              KEYSTORE_STORE_PWD
,
              KEYSTORE_KEY_PWD)
,
          new DefaultCipherParam(CIPHER_KEY_PWD)))
;

  /**
   * Validates the properties and generates a license certificate file.
   */
  private static void generateLicense(Properties props
,  File certFile) throws
      Exception {
    // Check for supported product id.
    final String productId 
=  props.getProperty(PRODUCT_ID_KEY) ;
    if (!PRODUCT_ID.equals(productId)) {
      throw new BadInputException(
" Bad product ID:  "  + productId) ;
    }

    final StringBuffer dn 
=  new StringBuffer() ;
    addAttribute(dn ,   " CN " ,  props.getProperty(FIRSTNAME_KEY)
                 + ' ' + props.getProperty(LASTNAME_KEY))
;
    if (dn.length()  ==   0 ) {
      addAttribute(dn
,   " CN " ,  props ,  REG_NAME_KEY) ;
    }
    addAttribute(dn
,   " O " ,  props ,  COMPANY_KEY) ;
    addAttribute(dn ,   " STREET " ,  props ,  STREET_KEY) ;
    addAttribute(dn ,   " L " ,  props.getProperty(ZIP_KEY)
                 + ' ' + props.getProperty(CITY_KEY))
;
    addAttribute(dn ,   " ST " ,  props ,  STATE_KEY) ;
    addAttribute(dn ,   " C " ,  props ,  COUNTRY_KEY) ;
    final X500Principal holder  =  new X500Principal(dn.toString()) ;
    final X500Principal issuer  =  new X500Principal(
        
" OU=share-it!,O=element 5 AG,STREET=Vogelsanger Strasse 78,L=50823 K\u00F6ln,ST=Nordrhein-Westfalen,C=DE " ) ;

    final LicenseContent content 
=  new LicenseContent() ;
    content.setHolder(holder) ;
    content.setIssuer(issuer) ;
    content.setConsumerType( " User " ) ;
    content.setConsumerAmount( 1 ) ;
    content.setInfo(props.toString()) ;
    content.setSubject(SUBJECT) ;
    java.util.Calendar cal  = java.util.Calendar.getInstance() ;
    cal.set( 2006 , 1 , 1 ) ;
    content.setNotAfter(cal.getTime()) ;
    manager.store(content ,  certFile) ;
  }

  private static final void addAttribute(
      final StringBuffer dn
,
      final String oid
,
      final Properties props
,
      final String key) {
    addAttribute(dn
,  oid ,  props.getProperty(key)) ;
  }

  private static void addAttribute(
      final StringBuffer dn
,
      final String oid
,
      String value) {
    if (value 
==  null) {
      return
;
    }

    final String trimmedValue 
=  value.trim() ;
    if ( "" .equals(trimmedValue)) {
      return
;
    }

    // See http://www.ietf.org/rfc/rfc2253.txt
    boolean quote 
=  false ;
    if (!value.equals(trimmedValue)) {
      quote 
=  true ;
    }
    else if (value.matches(
" .*[+,;<>\ " ].* " )) {
      ;
    }
    quote = true;

    if (dn.length() != 0) {
      dn.append(',');
    }
    dn.append(oid);
    dn.append('=');
    if (quote) {
      dn.append('
" ') ;
    }
    // Replace every single backslash with two backslashes
    // whereas both parameters are expressed as regular expressions.
    value 
=  value.replaceAll( " \\\\ " ,   " \\\\\\\\ " ) ;
    // Replace every single quote with an escaped quote
    // whereas both parameters are expressed as regular expressions.
    value 
=  value.replaceAll( " \ "" " \\\\\ "" ) ;
    dn.append(value) ;
    if (quote) {
      dn.append('
" ');
    }
  }

  private static Properties readInput(String pathname) throws IOException {
    Properties props = new EncodedProperties();
    InputStream in = new FileInputStream(pathname);
    try {
      props.load(in);
    }
    catch (IllegalArgumentException iae) {
      throw new BadInputException(iae);
    }
    finally {
      in.close();
    }

    return props;
  }

  /**
   * This is the main entry point for JAVA key generators. It processes the
   * command line arguments, loads and parses the input file, calls the key
   * generator and writes output files.
   *
   * JAVA Exceptions are handled and transformed into key generator error
   * codes. Exception messages will be written to <code>args[1]</code> and
   * display on the error console.
   */
  public static int KeyMain(String args[]) {
    args = new String[3];
    args[0] = 
" license.properties " ;
    args[1] = 
" license.status " ;
    args[2] = 
" license.lic " ;

    if (args.length != 3) {
      System.err.println(
" Usage: <input> <output1> <output2> " );

      return ERC_BAD_ARGS;
    }

    int errorCode = ERC_ERROR;
    PrintWriter out = new PrintWriter(System.err);
    try {
      try {
        // Read input and get encoding
        final Properties props = readInput(args[0]);
        final String encoding
            = props.getProperty(ENCODING_KEY, ENCODING_DEFAULT);

        // Setup real output with encoding read from input file.
        out = new PrintWriter(
            new OutputStreamWriter(
                new FileOutputStream(args[1]),
                encoding));

        // Validate input and generate key file.
        generateLicense(props, new File(args[2]));

        // Write status.
        out.write(MIME_TYPE + 
" : "  + DISPLAY_FILENAME);
      }
      catch (BadInputException bie) {
        errorCode = ERC_BAD_INPUT;
        throw bie;
      }
      catch (IOException ioe) {
        errorCode = ERC_FILE_IO;
        throw ioe;
      }
      catch (OutOfMemoryError oome) {
        errorCode = ERC_MEMORY;
        throw oome;
      }
    }
    catch (Throwable t) {
      out.println(
" Error # "  + errorCode);
      t.printStackTrace(out);

      return errorCode;
    }
    finally {
      out.close();
    }

    return ERC_SUCCESS_BIN;
  }

  /**
   * NOTE: This main() method is never called by the actual key server. It is
   * just useful for debugging the key generator.
   */
  public static final void main(String args[]) {
    KeyMain(args);
    /*try{
      manager.install(new java.io.File(
" swutil.log " ));
      System.out.println(
" subject = "  + manager.verify().getSubject());
      System.exit(0);
         }catch(Exception ex){
      ex.printStackTrace();
         }*/
  }

  public static class EncodedProperties
      extends Properties {
    public EncodedProperties() {
      this(new Properties());
    }

    /**
     * @throws NullPointerException if <tt>defaults</tt> is <tt>null</tt>.
     */
    public EncodedProperties(Properties defaults) {
      super(defaults);

      // Make sure we have a proper default for the encoding.
      defaults.setProperty(ENCODING_KEY, ENCODING_DEFAULT);
    }

    public void load(InputStream inStream) throws IOException {
      super.load(inStream);

      String encoding = super.getProperty(ENCODING_KEY);
      if (ENCODING_PROPERTIES.equals(encoding)) {
        return;
      }

      // Convert properties
      try {
        Map.Entry[] entries = new Map.Entry[entrySet().size()];
        entrySet().toArray(entries);
        for (int i = entries.length; --i >= 0; ) {
          Map.Entry entry = entries[i];
          String value = (String) entry.getValue();
          value = new String(value.getBytes(ENCODING_PROPERTIES),
                             encoding);
          setProperty( (String) entry.getKey(), value);
        }
      }
      catch (UnsupportedEncodingException ignored) {}
    }
  }

  public static class BadInputException
      extends IOException {
    public BadInputException(String message) {
      super(message);
    }

    public BadInputException(Throwable cause) {
      initCause(cause);
    }
  }

}

客户端程序安装license以及检验license合法性的代码:

安全警告
不要把私匙库拷贝到客户端,而只拷贝公匙库,要不然黑客就可以用你的私匙库来生成许许多多的license了

package com.sourceware.cmvp.license ;

import de.schlichtherle.license.*
;
import java.io.* ;
import java.util.* ;
import javax.security.auth.x500.X500Principal ;
import java.util.prefs.Preferences ;

/**
 * <p>Title: CMVP通用媒体增值业务平台</p>
 *
 * <p>Description: CMVP通用媒体增值业务平台</p>
 *
 * <p>Copyright: Copyright (c) 
2005 </p>
 *
 * <p>Company: source-ware.com inc.</p>
 *
 * @author 黑山
 * @version 
2.0
 */
public class CMVPLicenseManager {
  public CMVPLicenseManager() {
  }

  /** The product id of your software */
  public static final String PRODUCT_ID 
=   " cmvp20 " ;  // CUSTOMIZE

  /**
   * The subject for the license manager and also the alias of the private
   * key entry in the keystore.
   */
  public static final String SUBJECT 
=   " 别名 " ;  // CUSTOMIZE

  /** The resource name of your private keystore file. */
  public static final String KEYSTORE_RESOURCE 
=   " 公匙库文件名 " ;  // CUSTOMIZE

  /** The password for the keystore. */
  public static final String KEYSTORE_STORE_PWD 
=   " 公匙库密码 " ;  // CUSTOMIZE

  /** The password to encrypt the generated license key file. */
  public static final String CIPHER_KEY_PWD 
=   " license文件密码 " ;  // CUSTOMIZE



  protected static final LicenseManager manager 
=  new LicenseManager(
      new DefaultLicenseParam(
          SUBJECT
,
          Preferences.userNodeForPackage(CMVPLicenseManager.class)
,
          new DefaultKeyStoreParam(
              CMVPLicenseManager.class
,  // CUSTOMIZE
              KEYSTORE_RESOURCE
,
              SUBJECT
,
              KEYSTORE_STORE_PWD
,
              null)
, //这里一定要是null
          new DefaultCipherParam(CIPHER_KEY_PWD)))
;

  /**
   * NOTE: This main() method is never called by the actual key server. It is
   * just useful for debugging the key generator.
   */
  public static final void main(String args
[] ) {
    try {
      
      manager.install(new java.io.File(
" license.lic " )) ;
      String subject  =  manager.verify().getSubject() ;
      System.out.println( " subject======== " +subject) ;
    }
    catch (Exception ex) {
      ex.printStackTrace()
;
    }
  }

}
http://sms.i6688.com/pages/viewpage.action?pageId=25

你可能感兴趣的:(使用TrueLicense来保护我们的JAVA软件产品)