/*******************************************************************************
* Copyright (c) 2005-2011, G. Weirich and Elexis
* 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:
* G. Weirich - initial implementation
*
*******************************************************************************/
package ch.rgw.crypt;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.x509.X509V1CertificateGenerator;
import ch.rgw.io.FileTool;
import ch.rgw.tools.ExHandler;
import ch.rgw.tools.StringTool;
import ch.rgw.tools.TimeTool;
/**
* Vereinfachtes API für die Java Kryptographie-Klassen KeyManager stellt die Verbindung zu einem
* keystore her und lässt auf die darin befindlichen Schlüssel zugreifen.
*/
public class JCEKeyManager {
// private static final String CERTIFICATE_SIGNATURE_ALGO =
// "SHA256WithRSAEncryption";
private static final String CERTIFICATE_SIGNATURE_ALGO = "SHA256withRSA";
public static String Version(){
return "0.1.6";
}
protected KeyStore ks;
private static SecureRandom _srnd;
protected static Logger log;
@SuppressWarnings("unused")
private JCEKeyManager(){}
protected char[] storePwd = null;
protected String ksType;
private String ksFile;
static {
log = Logger.getLogger("KeyManager");
// Security.addProvider(new
// org.bouncycastle.jce.provider.BouncyCastleProvider());
// _srnd = SecureRandom.getInstance("SHA1PRNG"); // Create random
// number generator.
_srnd = new SecureRandom();
}
/**
* The Constructor does not actually create or access a keystore but only defines the access
* rules The keystore ist valid after a successful call to create() or load()
*
* @param keystoreFile
* path and name of the keystore to use if null: {user.home}/.keystore is used.
* @param type
* type of the keystore. If NULL: jks
* @param keystorePwd
* password for the keystore must not be null.
*/
public JCEKeyManager(String keystoreFile, String type, char[] keystorePwd){
this(type, keystorePwd);
if (StringTool.isNothing(keystoreFile)) {
ksFile = System.getProperty("user.home") + "/.keystore";
} else {
ksFile = FileTool.resolveFile(keystoreFile).getAbsolutePath();
}
log.log(Level.FINE, "ksPathName: " + ksFile);
File fks = new File(ksFile);
if (!fks.exists()) {
File fksPath = fks.getParentFile();
if (!fksPath.exists()) {
fksPath.mkdirs();
}
}
}
public JCEKeyManager(String type, char[] storepwd){
try {
_srnd = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
ExHandler.handle(e);
_srnd = new SecureRandom();
} // Create random
if (StringTool.isNothing(type)) {
ksType = "jks";
} else {
ksType = type;
}
storePwd = storepwd;
}
/**
* Keystore laden
*/
public boolean load(boolean bCreateIfNotExists){
try {
File ksf = new File(ksFile);
if (!ksf.exists()) {
return create(false);
}
ks = KeyStore.getInstance(ksType);
ks.load(new FileInputStream(ksFile), storePwd);
} catch (Exception ex) {
ExHandler.handle(ex);
log.log(Level.SEVERE,
"No Keystore found or could not open Keystore: " + ex.getMessage());
return false;
}
return true;
}
public boolean create(boolean bDeleteIfExists){
File ksF = new File(ksFile);
if (ksF.exists()) {
if (bDeleteIfExists) {
if (!ksF.delete()) {
return false;
}
} else {
return false;
}
}
if (ks == null) {
try {
ks = KeyStore.getInstance(ksType);
ks.load(null, null);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
return save();
}
public boolean save(){
try {
ks.store(new FileOutputStream(ksFile), storePwd);
return true;
} catch (Exception e) {
ExHandler.handle(e);
}
return false;
}
public boolean isKeystoreLoaded(){
return (ks == null) ? false : true;
}
/**
* Public key mit dem Alias alias holen. Es wird auf Gültigkeit des Zertifiktats getestet
*
* @param alias
* Name des gesuchten Schlüssels
* @return den gesuchten Schlüssel oder null - nicht gefunden
*/
public PublicKey getPublicKey(String alias){
if (alias == null) {
return null;
}
if (ks == null) {
log.log(Level.WARNING, "Keystore nicht geladen");
if (!load(true)) {
return null;
}
}
try {
java.security.cert.Certificate cert = ks.getCertificate(alias);
if (cert == null) {
log.log(Level.WARNING, "No certificate \"" + alias + "\"found");
return null;
} else {
return cert.getPublicKey();
}
} catch (Exception ex) {
ExHandler.handle(ex);
return null;
}
}
public X509Certificate getCertificate(String alias){
if (ks == null) {
log.log(Level.WARNING, "Keystore nicht geladen");
if (!load(true)) {
return null;
}
}
try {
java.security.cert.Certificate cert = ks.getCertificate(alias);
if (cert == null) {
log.log(Level.WARNING, "No certificate \"" + alias + "\"found");
return null;
} else {
return (X509Certificate) cert;
}
} catch (Exception ex) {
ExHandler.handle(ex);
return null;
}
}
/** Public key aus einem Input Stream lesen */
public PublicKey getPublicKey(InputStream is){
try {
java.security.cert.CertificateFactory cf =
java.security.cert.CertificateFactory.getInstance("X.509");
java.security.cert.Certificate cert = cf.generateCertificate(is);
return cert.getPublicKey();
} catch (Exception ex) {
ExHandler.handle(ex);
return null;
}
}
/**
* Private key mit dem Alias alias holen
*
* @param alias
* Zu holender Schlüssel
* @param pwd
* Schlüssel-Passwort
* @return den Schlüssel oder null
*/
public PrivateKey getPrivateKey(String alias, char[] pwd){
try {
if (StringTool.isNothing(alias) || (!ks.isKeyEntry(alias))) {
log.log(Level.WARNING, "Alias falsch oder fehlend");
return null;
}
return (PrivateKey) ks.getKey(alias, pwd);
} catch (Exception ex) {
ExHandler.handle(ex);
log.log(Level.SEVERE, "Kann Key nicht laden");
return null;
}
}
/**
* Zertifikat dem keystore zufügen
*
* @param cert
* Ein X.509 Zertifikat
* @return true bei Erfolg
*/
public boolean addCertificate(X509Certificate cert){
try {
String[] n = cert.getSubjectX500Principal().getName().split(",");
for (String sub : n) {
if (sub.startsWith("CN")) {
String[] fx = sub.split("\\s*=\\s*");
if (fx.length > 1) {
ks.setCertificateEntry(fx[1].trim(), cert);
return true;
}
}
}
return false;
} catch (KeyStoreException e) {
ExHandler.handle(e);
return false;
}
}
/*
* public Certificate createCertificate(PublicKey pk, PrivateKey signingKey){ CertificateFactory
* cf=CertificateFactory.getInstance("X.509"); } throws InvalidKeyException,
* NoSuchProviderException, SignatureException {
*/
/**
* Generate a certificate from a public key and a signing private key.
*
* @param pk
* the key to make a certficate from
* @param signingKey
* the signer's private key
* @param name
* of the issuer
* @param name
* of the certificate holder
* @return the signed certificate.
* @throws KeyStoreException
*
*/
public X509Certificate generateCertificate(PublicKey pk, PrivateKey signingKey, String issuer,
String subject, TimeTool ttFrom, TimeTool ttUntil) throws InvalidKeyException,
NoSuchProviderException, SignatureException, CertificateEncodingException,
IllegalStateException, NoSuchAlgorithmException, KeyStoreException{
// generate the certificate
X509V1CertificateGenerator certGen = new X509V1CertificateGenerator();
certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
certGen.setIssuerDN(new X500Principal("CN=" + issuer));
if (ttFrom == null) {
ttFrom = new TimeTool();
}
if (ttUntil == null) {
ttUntil = new TimeTool(ttFrom);
ttUntil.add(TimeTool.YEAR, 2);
}
certGen.setNotBefore(ttFrom.getTime());
certGen.setNotAfter(ttUntil.getTime());
certGen.setSubjectDN(new X500Principal("CN=" + subject));
certGen.setPublicKey(pk);
certGen.setSignatureAlgorithm(CERTIFICATE_SIGNATURE_ALGO);
// X509Certificate cert = certGen.generate(signingKey, "BC");
X509Certificate cert = certGen.generate(signingKey);
ks.setCertificateEntry(subject, cert);
return cert;
}
public boolean addKeyPair(PrivateKey kpriv, X509Certificate cert, char[] keyPwd)
throws Exception{
String alias = getName(cert);
ks.setKeyEntry(alias, kpriv, keyPwd, new Certificate[] {
cert
});
return true;
}
String getName(X509Certificate cert){
String cn = cert.getSubjectDN().getName();
int s = cn.indexOf('=');
if (s != -1) {
return cn.substring(s + 1);
}
return cn;
}
public boolean existsPrivate(String alias){
try {
return ks.isKeyEntry(alias);
} catch (KeyStoreException e) {
e.printStackTrace();
return false;
}
}
public boolean existsCertificate(String alias){
try {
return ks.isCertificateEntry(alias);
} catch (Exception ex) {
ExHandler.handle(ex);
return false;
}
}
public KeyPair generateKeys(){
try {
KeyPairGenerator kp = KeyPairGenerator.getInstance("RSA");
kp.initialize(1024, _srnd);
return kp.generateKeyPair();
} catch (Exception e) {
ExHandler.handle(e);
}
return null;
}
/*
* public DHParameterSpec createParams() throws Exception{ AlgorithmParameterGenerator paramGen
* = AlgorithmParameterGenerator.getInstance("DH"); paramGen.init(512); AlgorithmParameters
* params = paramGen.generateParameters(); DHParameterSpec dhps = (DHParameterSpec)
* params.getParameterSpec(DHParameterSpec.class); return dhps; }
*
* public KeyPair createKeyPair(DHParameterSpec params){ try { KeyPairGenerator kpg =
* KeyPairGenerator.getInstance("DiffieHellman"); if (params != null) { kpg.initialize(params);
* } KeyPair kp = kpg.generateKeyPair();
*
* return kp; } catch (Exception ex) { ExHandler.handle(ex); return null; } }
*/
public SecureRandom getRandom(){
return _srnd;
}
public boolean removeKey(String alias){
try {
ks.deleteEntry(alias);
return save();
} catch (KeyStoreException e) {
ExHandler.handle(e);
return false;
}
}
}