我们的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 licen;
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"; // PRODUCT_ID
/**
* The subject for the license manager and also the alias of the private
* key entry in the keystore.
*/
public static final String SUBJECT = "privatekey"; // CUSTOMIZE
/** The resource name of your private keystore file. */
public static final String KEYSTORE_RESOURCE = "privateKeys.store"; // 私匙库文件名
/** The password for the keystore. */
public static final String KEYSTORE_STORE_PWD = "a8a8a8"; // 私匙库密码
/* The password for the private key entry in the keystore. */
public static final String KEYSTORE_KEY_PWD = "a8a8a8"; //私匙库主键密码
/** The password to encrypt the generated license key file. */
public static final String CIPHER_KEY_PWD = "a8a8a8"; // 即将生成的license密码
/**
* 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"; // license.lic
//
// 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(2011,10,10);
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();
}
}
}