All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.weweave.commerce.LicenseKeyEncoder Maven / Gradle / Ivy

package net.weweave.commerce;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

import javax.json.*;
import java.io.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;

/**
 * A {@link LicenseKeyEncoder} object generates and parses signed license
 * keys.
 * 

* License keys generated by this class are signed using an RSA private- * public-key-pair in PEM format. *

* See the documentation of weweave Commerce for more details at: * weweave.net * * @author weweave GbR * @see LicenseKeyEncoder */ public class LicenseKeyEncoder { public static final String TYPE_TRIAL = "trial"; public static final String TYPE_LIMITED = "limited"; public static final String TYPE_LIFETIME = "lifetime"; private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; private static final String RSA = "RSA"; private String product = ""; private String description = ""; private Date issueDate = null; private Date expiryDate = null; private String owner = ""; private String subject; private String type = ""; private String uuid = ""; private boolean onlineVerification = false; public String getProduct() { return product; } public void setProduct(String product) { this.product = product; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public Date getIssueDate() { return issueDate; } public void setIssueDate(Date issueDate) { this.issueDate = issueDate; } public Date getExpiryDate() { return expiryDate; } public void setExpiryDate(Date expiryDate) { this.expiryDate = expiryDate; } public String getOwner() { return owner; } public void setOwner(String owner) { this.owner = owner; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public Integer getVersion() { return 2; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public boolean getOnlineVerification() { return onlineVerification; } public void setOnlineVerification(boolean onlineVerification) { this.onlineVerification = onlineVerification; } /** * Creates a Base64 encoded license key signed with an RSA private key. * * @param privateKey the private key for signing the license key (PEM) * @return a Base64 encoded, signed license key string * @throws IOException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws InvalidKeyException * @throws SignatureException */ public String getLicenseString(File privateKey) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { InputStream is = new FileInputStream(privateKey); return getLicenseString(is); } /** * Creates a Base64 encoded license key signed with an RSA private key. * * @param privateKey the private key for signing the license key (PEM) * @return a Base64 encoded, signed license key string * @throws InvalidKeySpecException * @throws SignatureException * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws IOException */ public String getLicenseString(InputStream privateKey) throws InvalidKeySpecException, SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException { JsonObject details = createDetailsObject(); JsonObjectBuilder result = Json.createObjectBuilder(); String detailsBase64 = bytesToBase64(getJsonString(details).getBytes()); String signature = LicenseKeyEncoder.createSignature(detailsBase64, privateKey); result.add("signature", signature); result.add("details", detailsBase64); return bytesToBase64(getJsonString(result.build()).getBytes()); } private JsonObject createDetailsObject() { SimpleDateFormat sdf = getDateFormatter(); JsonObjectBuilder details = Json.createObjectBuilder(); details.add("version", getVersion()); details.add("description", getDescription()); details.add("type", getType()); details.add("uuid", getUuid()); details.add("onlineVerification", getOnlineVerification()); details.add("product", getProduct()); details.add("issueDate", sdf.format(getIssueDate())); details.add("expiryDate", sdf.format(getExpiryDate())); details.add("subject", getSubject()); details.add("owner", getOwner()); return details.build(); } /** * Checks whether a signature for a given string is valid according to a * specified RSA public key. * * @param s the string to check the signature for * @param signature the signature to check * @param publicKey the public key for calculating the signature (PEM) * @return true if the specified signature is valid for this string * @throws FileNotFoundException */ public static boolean isSignatureValid(String s, String signature, File publicKey) throws FileNotFoundException { InputStream is = new FileInputStream(publicKey); return isSignatureValid(s, signature, is); } /** * * Checks whether a signature for a given string is valid according to a * specified RSA public key. * * @param s the string to check the signature for * @param signature the signature to check * @param publicKey the public key for calculating the signature (PEM) * @return true if the specified signature is valid for this string */ public static boolean isSignatureValid(String s, String signature, InputStream publicKey) { try { Signature signatureToVerify = Signature.getInstance(SIGNATURE_ALGORITHM); signatureToVerify.initVerify(readPublicKey(publicKey)); signatureToVerify.update(s.getBytes()); return signatureToVerify.verify(base64ToBytes(signature)); } catch (Exception e) { e.printStackTrace(); return false; } } /** * Constructs a new {@link LicenseKeyEncoder} instance for a given license * key. * * @param licenseKey a Base64 encoded, signed license key * @param publicKey the public key for checking the signature (PEM) * @return an instance of {@link LicenseKeyEncoder} containing the data * parsed from the license key. * @throws SignatureException * @throws ParseException * @throws FileNotFoundException */ public static LicenseKeyEncoder factory(String licenseKey, File publicKey) throws SignatureException, ParseException, FileNotFoundException { InputStream is = new FileInputStream(publicKey); return factory(licenseKey, is); } /** * Constructs a new {@link LicenseKeyEncoder} instance for a given license * key. * * @param licenseKey a Base64 encoded, signed license key * @param publicKey the public key for checking the signature (PEM) * @return an instance of {@link LicenseKeyEncoder} containing the data * parsed from the license key. * @throws SignatureException * @throws ParseException * @throws FileNotFoundException */ public static LicenseKeyEncoder factory(String licenseKey, InputStream publicKey) throws SignatureException, ParseException { JsonObject o; String decodedLicenseKey = LicenseKeyEncoder.base64ToString(licenseKey); try (JsonReader jr = Json.createReader(new StringReader(decodedLicenseKey))) { o = jr.readObject(); } catch (Exception e) { throw new ParseException("licenseKey is invalid JSON", 0); } String signature = o.getString("signature"); String detailsBase64 = o.getString("details"); if (!isSignatureValid(detailsBase64, signature, publicKey)) { throw new SignatureException("Invalid signature"); } JsonObject details; try (JsonReader jr = Json.createReader(new StringReader(new String(base64ToBytes(detailsBase64))))) { details = jr.readObject(); } catch (Exception e) { throw new ParseException("details is invalid JSON", 0); } if (!details.containsKey("version") || details.getInt("version") != 2) { throw new IllegalArgumentException("Only version 2 is supported"); } return createLicenseKeyEncoderFromJson(details); } private static LicenseKeyEncoder createLicenseKeyEncoderFromJson(JsonObject details) throws ParseException { LicenseKeyEncoder result = new LicenseKeyEncoder(); result.setDescription(details.getString("description", "")); result.setType(details.getString("type", "")); result.setUuid(details.getString("uuid", "")); result.setOnlineVerification(details.getBoolean("onlineVerification", false)); result.setProduct(details.getString("product", "")); result.setSubject(details.getString("subject", "")); result.setOwner(details.getString("owner", "")); SimpleDateFormat sdf = getDateFormatter(); if (details.containsKey("issueDate")) { result.setIssueDate(sdf.parse(details.getString("issueDate"))); } if (details.containsKey("expiryDate")) { result.setExpiryDate(sdf.parse(details.getString("expiryDate"))); } return result; } protected static SimpleDateFormat getDateFormatter() { return new SimpleDateFormat("yyyy-MM-dd"); } /** * Calculates the signature for a given string. * * @param s the string to calculate the signature for * @param privateKey the private key (PEM) * @return the Base64 encoded signature for the string * @throws IOException * @throws InvalidKeySpecException * @throws SignatureException * @throws NoSuchAlgorithmException * @throws InvalidKeyException */ public static String createSignature(String s, File privateKey) throws IOException, InvalidKeySpecException, SignatureException, NoSuchAlgorithmException, InvalidKeyException { InputStream is = new FileInputStream(privateKey); return createSignature(s, is); } /** * * Calculates the signature for a given string. * * @param s the string to calculate the signature for * @param privateKey the private key (PEM) * @return the Base64 encoded signature for the string * @throws NoSuchAlgorithmException * @throws IOException * @throws InvalidKeySpecException * @throws InvalidKeyException * @throws SignatureException */ public static String createSignature(String s, InputStream privateKey) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, InvalidKeyException, SignatureException { PrivateKey pk = LicenseKeyEncoder.readPrivateKey(privateKey); Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); signature.initSign(pk, new SecureRandom()); signature.update(s.getBytes()); byte[] signatureBytes = signature.sign(); return bytesToBase64(signatureBytes); } private static PrivateKey readPrivateKey(InputStream keyFile) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PemReader pemReader = new PemReader(new InputStreamReader(keyFile)); PemObject pemObject = pemReader.readPemObject(); KeyFactory factory = KeyFactory.getInstance(RSA, new BouncyCastleProvider()); KeySpec keySpec = new PKCS8EncodedKeySpec(pemObject.getContent()); return factory.generatePrivate(keySpec); } private static PublicKey readPublicKey(InputStream keyFile) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException { PemReader pemReader = new PemReader(new InputStreamReader(keyFile)); PemObject pemObject = pemReader.readPemObject(); KeyFactory factory = KeyFactory.getInstance(RSA, new BouncyCastleProvider()); KeySpec keySpec = new X509EncodedKeySpec(pemObject.getContent()); return factory.generatePublic(keySpec); } private static String getJsonString(JsonObject o) { StringWriter sw = new StringWriter(); try (JsonWriter jw = Json.createWriter(sw)) { jw.writeObject(o); } return sw.toString(); } private static String bytesToBase64(byte[] b) { return Base64.getEncoder().encodeToString(b); } private static byte[] base64ToBytes(String s) { byte[] result = Base64.getDecoder().decode(s.getBytes()); return result; } private static String base64ToString(String s) { byte[] result = Base64.getDecoder().decode(s.getBytes()); try { return new String(result, "UTF-8"); } catch (UnsupportedEncodingException e) { return ""; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy