Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.POLIS.licensing.common.license; import com.POLIS.licensing.common.exception.BadLicenseException; import com.POLIS.licensing.common.exception.OperationException; import com.POLIS.licensing.common.exception.SystemStateException; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; import java.security.KeyPairGenerator; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.KeyGenerator; import javax.crypto.NoSuchPaddingException; import org.apache.commons.codec.binary.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; /** * * @author Martin */ public abstract class AbstractSerializationBasedLicense implements License, Serializable { public static final String signatureEncoding = "SHA512withRSA"; public static final String symmetricEncoding = "AES/ECB/withCTS"; public static final String symmetricKeyType = "AES"; public static final String asymmetricEncoding = "RSA/NONE/PKCS1Padding"; public static final String provider = "BC"; private byte[] signature; protected abstract String getFieldsAsString(); public AbstractSerializationBasedLicense() { } @Override public void signLicense(PrivateKey privateSignatureKey) throws BadLicenseException, SystemStateException, OperationException { try { Signature instance = Signature.getInstance(signatureEncoding, provider); instance.initSign(privateSignatureKey); instance.update(getFieldsAsString().getBytes()); signature = instance.sign(); } catch (NoSuchAlgorithmException | NoSuchProviderException ex) { throw new SystemStateException("Could not sign the license. Algorithm not found", ex); } catch (InvalidKeyException | SignatureException ex) { throw new OperationException("Could not sign the license.", ex); } } @Override public boolean verifyLicense(PublicKey senderSignatureKey) throws BadLicenseException, SystemStateException, OperationException { if (signature == null) { throw new OperationException("Could not vertify signature. License was never signed"); } try { Signature instance = Signature.getInstance(signatureEncoding, provider); instance.initVerify(senderSignatureKey); instance.update(getFieldsAsString().getBytes()); return instance.verify(signature); } catch (NoSuchAlgorithmException | NoSuchProviderException ex) { throw new SystemStateException("Could not verify the license. Algorithm not found", ex); } catch (InvalidKeyException | SignatureException ex) { throw new OperationException("Could not verify the license.", ex); } } @Override public String getEncryptedLicense(PublicKey targetKey) throws SystemStateException, OperationException { byte[] licenseAsBytes; try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)) { out.writeObject(this); licenseAsBytes = bos.toByteArray(); } catch (IOException ex) { throw new OperationException("An error occured while serializing the license", ex); } SecureRandom random = new SecureRandom(); Cipher aescipher; Cipher rsacipher; KeyGenerator aesgenerator; Key symkey; try { aesgenerator = KeyGenerator.getInstance(symmetricKeyType, provider); aesgenerator.init(128, random); symkey = aesgenerator.generateKey(); } catch (NoSuchAlgorithmException | NoSuchProviderException ex) { throw new SystemStateException("The specified symkey could not be generated.", ex); } try { aescipher = Cipher.getInstance(symmetricEncoding, provider); rsacipher = Cipher.getInstance(asymmetricEncoding, provider); aescipher.init(Cipher.ENCRYPT_MODE, symkey); rsacipher.init(Cipher.ENCRYPT_MODE, targetKey); } catch (NoSuchAlgorithmException | NoSuchProviderException | /*InvalidKeySpecException |*/ NoSuchPaddingException | InvalidKeyException ex) { throw new SystemStateException("The specified encryption provider or algorithm was not found", ex); } String encryptedLicense; try { byte[] encryptedsymkey = rsacipher.doFinal(symkey.getEncoded()); byte[] encryptedlicense = aescipher.doFinal(licenseAsBytes); byte[] licenseWithKey = new byte[encryptedsymkey.length + encryptedlicense.length]; System.arraycopy(encryptedsymkey, 0, licenseWithKey, 0, encryptedsymkey.length); System.arraycopy(encryptedlicense, 0, licenseWithKey, encryptedsymkey.length, encryptedlicense.length); encryptedLicense = Base64.encodeBase64String(licenseWithKey); } catch (IllegalBlockSizeException | BadPaddingException ex) { throw new OperationException("Could not encode to base64", ex); } return encryptedLicense; } protected byte[] getSignature() { return signature; } }