Package com.xk72.cocoafob

Source Code of com.xk72.cocoafob.LicenseGenerator

package com.xk72.cocoafob;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;

import org.apache.commons.codec.binary.Base32;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;

/**
* Generate and verify CocoaFob licenses. Based on the PHP implementation by Sandro Noel.
* @author karlvr
*
*/
public class LicenseGenerator {
 
  private DSAPrivateKey privateKey;
  private DSAPublicKey publicKey;
  private SecureRandom random;
 
  static {
    Security.addProvider(new BouncyCastleProvider());
  }
 
  protected LicenseGenerator() {
    random = new SecureRandom();
  }
 
  /**
   * Construct the LicenseGenerator with a URL that points to either the private key or public key.
   * Pass the private key for making and verifying licenses. Pass the public key for verifying only.
   * If you this code will go onto a user's machine you MUST NOT include the private key, only include
   * the public key in this case.
   * @param keyURL
   * @throws IOException
   */
  public LicenseGenerator(URL keyURL) throws IOException {
    this();
    initKeys(keyURL.openStream());
  }
 
  /**
   * Construct the LicenseGenerator with an InputStream of either the private key or public key.
   * Pass the private key for making and verifying licenses. Pass the public key for verifying only.
   * If you this code will go onto a user's machine you MUST NOT include the private key, only include
   * the public key in this case.
   * @param keyURL
   * @throws IOException
   */
  public LicenseGenerator(InputStream keyInputStream) throws IOException {
    this();
    initKeys(keyInputStream);
  }
 
  private void initKeys(InputStream keyInputStream) throws IOException {
    Object readKey = readKey(keyInputStream);
    if (readKey instanceof KeyPair) {
      KeyPair keyPair = (KeyPair) readKey;
      privateKey = (DSAPrivateKey) keyPair.getPrivate();
      publicKey = (DSAPublicKey) keyPair.getPublic();
    } else if (readKey instanceof DSAPublicKey) {
      publicKey = (DSAPublicKey) readKey;
    } else {
      throw new IllegalArgumentException("The supplied key stream didn't contain a public or private key: " + readKey.getClass());
    }
  }

  private Object readKey(InputStream privateKeyInputSteam) throws IOException {
    PEMReader pemReader = new PEMReader(new InputStreamReader(new BufferedInputStream(privateKeyInputSteam)));
    try {
      return pemReader.readObject();
    } finally {
      pemReader.close();
    }
  }

  /**
   * Make and return a license for the given {@link LicenseData}.
   * @param licenseData
   * @return
   * @throws LicenseGeneratorException If the generation encounters an error, usually due to invalid input.
   * @throws IllegalStateException If the generator is not setup correctly to make licenses.
   */
  public String makeLicense(LicenseData licenseData) throws LicenseGeneratorException, IllegalStateException {
    if (!isCanMakeLicenses()) {
      throw new IllegalStateException("The LicenseGenerator cannot make licenses as it was not configured with a private key");
    }
   
    final String stringData = licenseData.toLicenseStringData();
   
    try {
      final Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
      dsa.initSign(privateKey, random);
      dsa.update(stringData.getBytes("UTF-8"));
     
      final byte[] signed = dsa.sign();
     
      /* base 32 encode the signature */
      String result = new Base32().encodeAsString(signed);
     
      /* replace O with 8 and I with 9 */
      result = result.replace("O", "8").replace("I""9");
     
      /* remove padding if any. */
      result = result.replace("=", "");
     
      /* chunk with dashes */
      result = split(result, 5);
      return result;
    } catch (NoSuchAlgorithmException e) {
      throw new LicenseGeneratorException(e);
    } catch (NoSuchProviderException e) {
      throw new LicenseGeneratorException(e);
    } catch (InvalidKeyException e) {
      throw new LicenseGeneratorException(e);
    } catch (SignatureException e) {
      throw new LicenseGeneratorException(e);
    } catch (UnsupportedEncodingException e) {
      throw new LicenseGeneratorException(e);
    }
  }

  /**
   * Verify the given license for the given {@link LicenseData}.
   * @param licenseData
   * @param license
   * @return Whether the license verified successfully.
   * @throws LicenseGeneratorException If the verification encounters an error, usually due to invalid input. You MUST check the return value of this method if no exception is thrown.
   * @throws IllegalStateException If the generator is not setup correctly to verify licenses.
   */
  public boolean verifyLicense(LicenseData licenseData, String license) throws LicenseGeneratorException, IllegalStateException {
    if (!isCanVerifyLicenses()) {
      throw new IllegalStateException("The LicenseGenerator cannot verify licenses as it was not configured with a public key");
    }
   
    final String stringData = licenseData.toLicenseStringData();
   
    /* replace O with 8 and I with 9 */
    String licenseSignature = license.replace("8", "O").replace("9", "I");
   
    /* remove dashes */
    licenseSignature = licenseSignature.replace("-", "");
   
    /* Pad the output length to a multiple of 8 with '=' characters */
    while (licenseSignature.length() % 8 != 0) {
      licenseSignature += "=";
    }
   
    byte[] decoded = new Base32().decode(licenseSignature);
    try {
      Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
      dsa.initVerify(publicKey);
      dsa.update(stringData.getBytes("UTF-8"));
      return dsa.verify(decoded);
    } catch (NoSuchAlgorithmException e) {
      throw new LicenseGeneratorException(e);
    } catch (NoSuchProviderException e) {
      throw new LicenseGeneratorException(e);
    } catch (InvalidKeyException e) {
      throw new LicenseGeneratorException(e);
    } catch (SignatureException e) {
      throw new LicenseGeneratorException(e);
    } catch (UnsupportedEncodingException e) {
      throw new LicenseGeneratorException(e);
    }
  }

  private String split(String str, int chunkSize) {
    StringBuilder result = new StringBuilder();
    int i = 0;
    while (i < str.length()) {
      if (i > 0) {
        result.append('-');
      }
      int next = Math.min(i + chunkSize, str.length());
      result.append(str.substring(i, next));
      i = next;
    }
    return result.toString();
  }
 
  public boolean isCanMakeLicenses() {
    return privateKey != null;
  }
 
  public boolean isCanVerifyLicenses() {
    return publicKey != null;
  }
 
}
TOP

Related Classes of com.xk72.cocoafob.LicenseGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.