KeyPairGeneratorDefault.java

package org.linkedopenactors.rdfpub.adapter.driven;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
class KeyPairGeneratorDefault implements org.linkedopenactors.rdfpub.app.actor.KeyPairGenerator {

	private String keypairHomeDir;
	private static final String algorithm = "RSA";
	
	public KeyPairGeneratorDefault(@Value("${app.keypairHome}") String keypairHomeDir) {
		this.keypairHomeDir = keypairHomeDir;
		File dir = new File(keypairHomeDir);
		if(!dir.exists()) {
			dir.mkdirs();
		}
	}
	
	
	@Override
	public PublicKey generate(String identifier) {
		try {
			KeyPairGenerator kpg = KeyPairGenerator.getInstance(algorithm);
			kpg.initialize(512);
			KeyPair kp = kpg.generateKeyPair();
			savePrivateKey(identifier, kp.getPrivate());
			savePublicKey(identifier, kp.getPublic());
			return getPublicKey(identifier);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalStateException("unable to generate keypair", e);
		}
	}

	@Override
	public PrivateKey getPrivateKey(String identifierParam) {
		String identifier = encode(identifierParam);
		try {
			byte[] bytes = FileUtils.readFileToByteArray(new File(getPrivateKeyFileName(identifier)));
			PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(bytes);
			KeyFactory kf = KeyFactory.getInstance(algorithm);
			return kf.generatePrivate(ks);
		} catch (Exception e) {
			String message = "unable to load private key file";
			log.error(message, e);
			throw new IllegalStateException(message, e);
		}
	}
	
	@Override
	public PublicKey getPublicKey(String identifier) {
		try {
			byte[] bytes = FileUtils.readFileToByteArray(new File(getPublicKeyFileName(identifier)));
			X509EncodedKeySpec ks = new X509EncodedKeySpec(bytes);
			KeyFactory kf = KeyFactory.getInstance(algorithm);
			return kf.generatePublic(ks);
		} catch (Exception e) {			
			String message = "unable to load public key file";
			log.error(message, e);
			throw new IllegalStateException(message, e);
		}
	}
	
	@Override
	public String getPublicKeyBase64Encoded(String identifierParam) {
		String identifier = encode(identifierParam);
		Base64.Encoder encoder = Base64.getEncoder();
		String result = "-----BEGIN RSA PUBLIC KEY-----\n";
		result += encoder.encodeToString(getPublicKey(identifier).getEncoded());
		result += "\n-----END RSA PUBLIC KEY-----";
		return result;
	}
	
	private String encode(String storeName) {
		try {
			String encoded = URLEncoder.encode(storeName, StandardCharsets.UTF_8.toString());
			log.debug("encoded: " + encoded);
			return encoded;
		} catch (UnsupportedEncodingException e) {
			throw new IllegalStateException("Unable to encode storeName: " + storeName, e);
		}
	}

	private String savePublicKey(String identifier, Key publicKey) {
		try {
			String outFile = getPublicKeyFileName(identifier);
			OutputStream out = new FileOutputStream(new File(outFile));
			out.write(publicKey.getEncoded());
			out.close();
			return outFile;
		} catch (Exception e) {
			log.error("unable to save private key", e);
			throw new IllegalStateException("unable to save private key", e);
		}
	}

	private String savePrivateKey(String identifier, Key pvt) {
		try {
			String outFile = getPrivateKeyFileName(identifier);
			FileOutputStream out = new FileOutputStream(outFile);
			out.write(pvt.getEncoded());
			out.close();
			return outFile;
		} catch (Exception e) {
			String message = "unable to save private key";
			log.error(message, e);			
			throw new IllegalStateException(message, e);
		}
	}

	public String getPrivateKeyFileName(String identifier) {
		String outFile = keypairHomeDir + "/" + identifier + ".private.key";
		return outFile;
	}
	
	private String getPublicKeyFileName(String identifier) {
		String outFile = keypairHomeDir + "/" + identifier + ".public.key";
		return outFile;
	}
	
}