/******************************************************************************* * Copyright (c) 2015 Kaloyan Raev. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Kaloyan Raev - initial API and implementation *******************************************************************************/ package org.eclipse.licensing.base; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.Signature; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.Properties; import java.util.UUID; import org.apache.commons.codec.binary.Base64; import org.eclipse.licensing.core.ILicensedProduct; import org.osgi.framework.Version; import org.osgi.framework.VersionRange; public class LicenseKey { public final static String ID = "Id"; public final static String ISSUER = "Issuer"; public final static String TYPE = "Type"; public final static String EXPIRATION_DATE = "ExpirationDate"; public final static String PRODUCT_ID = "ProductId"; public final static String PRODUCT_NAME = "ProductName"; public final static String PRODUCT_VENDOR = "ProductVendor"; public final static String PRODUCT_VERSIONS = "ProductVersions"; public final static String CUSTOMER_ID = "CustomerId"; public final static String CUSTOMER_NAME = "CustomerName"; /** * Base64-encoded string representation of the license key signature. */ public final static String SIGNATURE = "Signature"; private Properties properties; private File file; public LicenseKey(Properties properties) { this.properties = properties; } public LicenseKey(File file) { this.file = file; properties = new Properties(); try { properties.load(new FileInputStream(file)); } catch (IOException e) { // TODO set in invalid status e.printStackTrace(); } } public LicenseKey(String fileName) { this(new File(fileName)); } public File getFile() { return file; } public String getProperty(String key) { return properties.getProperty(key); } public String getId() { return getProperty(ID); } public String getIssuer() { return getProperty(ISSUER); } public String getType() { return getProperty(TYPE); } public String getExpirationDate() { return getProperty(EXPIRATION_DATE); } public UUID getProductId() { String productId = getProperty(PRODUCT_ID); return (productId == null) ? null : UUID.fromString(productId); } public String getProductName() { return getProperty(PRODUCT_NAME); } public String getProductVendor() { return getProperty(PRODUCT_VENDOR); } public VersionRange getProductVersions() { String versions = getProperty(PRODUCT_VERSIONS); return (versions == null) ? null : VersionRange.valueOf(versions); } public String getCustomerId() { return getProperty(CUSTOMER_ID); } public String getCustomerName() { return getProperty(CUSTOMER_NAME); } public String getSignatureAsString() { return getProperty(SIGNATURE); } public byte[] getSignature() { return Base64.decodeBase64(getSignatureAsString()); } public boolean isValidFor(ILicensedProduct product) { return (product.getId().equals(getProductId()) && isAuthentic(product.getPublicKey()) && matchesProductVersion(product.getVersion()) && isWithinExpirationDate()); } public boolean isAuthentic(PublicKey publicKey) { try { Signature signature = Signature.getInstance("SHA1withDSA", "SUN"); signature.initVerify(publicKey); String[] propKeys = properties.keySet().toArray(new String[0]); Arrays.sort(propKeys); for (String propKey : propKeys) { if (!SIGNATURE.equals(propKey)) { String propValue = getProperty(propKey); signature.update(propValue.getBytes("UTF-8")); } } byte[] encodedSignature = getSignature(); if (encodedSignature == null) { return false; } return signature.verify(getSignature()); } catch (GeneralSecurityException | UnsupportedEncodingException e) { e.printStackTrace(); return false; } } public boolean matchesProductVersion(String version) { VersionRange versions = getProductVersions(); return (versions == null) ? true : versions .includes(new Version(version)); } public boolean isWithinExpirationDate() { String expirationDate = getExpirationDate(); if (expirationDate == null) { // no date restriction return true; } DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Date date = format.parse(getExpirationDate() + " 23:59:59"); return date.compareTo(new Date()) > 0; } catch (ParseException e) { e.printStackTrace(); return false; } } }