Skip to content

Commit

Permalink
Add CryptoServiceKeyStoreProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
ar committed Sep 3, 2019
1 parent e0b4854 commit f5a9f74
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 19 deletions.
11 changes: 10 additions & 1 deletion doc/src/asciidoc/module_cryptoservice.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ The crypto service can be configured using a QBean descriptor like this:
<property name="duration" value="86400000" /> <6>
<property name="ttl" value="3600000" /> <7>
<property name="max-random-operations" value="1000000" /> <8>
<ks-provider
class="org.jpos.crypto.SysConfigCryptoServiceKeyStoreProvider" /> <9>
</crypto-service>
------------
<1> custodian PGP id, there can be many `custodian` entries.
Expand All @@ -75,7 +77,14 @@ The crypto service can be configured using a QBean descriptor like this:
<5> key length defaults to 256. Can be reduced if AES-256 is not supported by the JVM due to export restrictions.
<6> key duration
<7> internal key cache time-to-live (in millis).
<8> after max-random-operations (default to 100000), SecureRandom object gets discarded
<8> after max-random-operations (default to 100000), SecureRandom object gets discarded.
<9> CryptoServiceKeyStoreProvider class configuration.

[TIP]
=====
We currently support two CryptoServiceKeyStoreProvider classes:
`SysConfigCryptoServiceKeyStoreProvider` and `JESpaceCryptoServiceKeyStoreProvider`
=====

This allows jPOS nodes to encrypt data securely without storing the encryption key to disk.

Expand Down
1 change: 1 addition & 0 deletions modules/cryptoserver/src/dist/deploy/25_crypto_service.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
<property name="keylength" value="256" />
<property name="duration" value="86400000" />
<property name="unlock-password" value="demo" />
<ks-provider class="org.jpos.crypto.SysConfigCryptoServiceKeyStoreProvider" />
</crypto-service>
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
package org.jpos.crypto;

import org.bouncycastle.openpgp.PGPException;
import org.jdom2.Element;
import org.jpos.core.Configuration;
import org.jpos.core.ConfigurationException;
import org.jpos.ee.DB;
import org.jpos.ee.SysConfigManager;
import org.jpos.core.XmlConfigurable;
import org.jpos.q2.QBeanSupport;
import org.jpos.q2.QFactory;
import org.jpos.space.Space;
import org.jpos.space.TSpace;
import org.jpos.util.*;
Expand All @@ -39,7 +40,6 @@
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;

/**
Expand All @@ -61,7 +61,7 @@
* and that requires the private key-ring's password.
*
*/
public final class CryptoService extends QBeanSupport implements Runnable {
public final class CryptoService extends QBeanSupport implements Runnable, XmlConfigurable {
private volatile UUID id;
private volatile SecretKey sk;
private volatile long timestamp;
Expand All @@ -79,6 +79,7 @@ public final class CryptoService extends QBeanSupport implements Runnable {
private Supplier<String> unlock;
private Recyclable<Random> rnd;
private int maxRandomOperations = 100000;
private CryptoServiceKeyStoreProvider ksProvider;

/**
* Encrypts data using the current key
Expand Down Expand Up @@ -199,7 +200,7 @@ public boolean isLocked () {
}

@Override
protected void initService() {
protected void initService() throws ConfigurationException {
rnd = new Recyclable<>(SecureRandom::new, maxRandomOperations);
if (!lazy.get())
new Thread(this, getName()).start();
Expand Down Expand Up @@ -265,11 +266,7 @@ private void renewKey () throws Exception {
}

private void registerKey(String k, String v) throws Exception {
DB.execWithTransaction(db -> {
SysConfigManager mgr = new SysConfigManager(db, "key.");
mgr.put(k, v, "security.read", "security.write");
return true;
});
ksProvider.put(k, v);
LogEvent evt = getLog().createLogEvent("security");
evt.addMessage("<id>" + k + "</id>");
evt.addMessage(System.lineSeparator() + v);
Expand All @@ -281,10 +278,7 @@ private SecretKey getKey (UUID keyId, char[] passPhrase) throws Exception {
throw new SecurityException("Passphrase not available");
passPhrase = passPhrase != null ? passPhrase : unlock.get().toCharArray();

String v = DB.execWithTransaction(db -> {
SysConfigManager mgr = new SysConfigManager(db, "key.");
return mgr.get(keyId.toString(), null);
});
String v = ksProvider.get(keyId.toString());
if (v == null) {
throw new SecurityException("Invalid key");
}
Expand Down Expand Up @@ -321,4 +315,22 @@ private UUID xor (UUID a, UUID b) {
a.getMostSignificantBits() ^ b.getMostSignificantBits(),
a.getLeastSignificantBits() ^ b.getLeastSignificantBits());
}


@Override
public void setConfiguration(Element e) throws ConfigurationException {
Element kse = e.getChild("ks-provider");
if (kse != null) {
QFactory factory = getFactory();
Object obj = factory.newInstance(kse.getAttributeValue("class"));
if (obj instanceof CryptoServiceKeyStoreProvider) {
factory.setLogger(obj, kse);
factory.setConfiguration(obj, kse);
ksProvider = (CryptoServiceKeyStoreProvider) obj;
}
}
if (ksProvider == null) {
throw new ConfigurationException ("Unconfigured ks-provider");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2019 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.crypto;

public class CryptoServiceKeyStoreException extends Exception {
private static final long serialVersionUID = -392344903153648787L;

public CryptoServiceKeyStoreException() {
}

public CryptoServiceKeyStoreException(String message) {
super(message);
}

public CryptoServiceKeyStoreException(String message, Throwable cause) {
super(message, cause);
}

public CryptoServiceKeyStoreException(Throwable cause) {
super(cause);
}

public CryptoServiceKeyStoreException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2019 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.crypto;

/**
* Key store
*/
public interface CryptoServiceKeyStoreProvider {
/**
* Places an encrypted key in the store.
*
* @param id key Id
* @param value key value
* @throws KeyAlreadyExistsException if id already exists in the store.
*/
void put(String id, String value) throws CryptoServiceKeyStoreException;

/**
* Get key value
* @param id key Id
* @return key's value or null
*/
String get (String id) throws CryptoServiceKeyStoreException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2019 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.crypto;

import org.jpos.core.Configurable;
import org.jpos.core.Configuration;
import org.jpos.core.ConfigurationException;
import org.jpos.space.Space;
import org.jpos.space.SpaceFactory;

public class JESpaceCryptoServiceKeyStoreProvider implements CryptoServiceKeyStoreProvider, Configurable {
private Space<String,String> sp;

@Override
public void put(String id, String value) throws CryptoServiceKeyStoreException {
if (sp.rdp(id) != null) {
throw new KeyAlreadyExistsException();
}
sp.put(id, value);
}

@Override
public String get(String id) throws CryptoServiceKeyStoreException {
return sp.rdp(id);
}

@Override
@SuppressWarnings("unchecked")
public void setConfiguration(Configuration cfg) throws ConfigurationException {
sp = (Space<String,String>) SpaceFactory.getSpace(cfg.get("space", "je:cryptoservice"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2019 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.crypto;

public class KeyAlreadyExistsException extends CryptoServiceKeyStoreException {

private static final long serialVersionUID = -7413606609749329477L;

/**
* Key already exists in keystore.
*/
public KeyAlreadyExistsException() {
super();
}

/**
* Key already exists in keystore (with detail).
*
* @param msg the detail message.
*/
public KeyAlreadyExistsException(String msg) {
super(msg);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* jPOS Project [http://jpos.org]
* Copyright (C) 2000-2019 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.jpos.crypto;

import org.jpos.ee.DB;
import org.jpos.ee.SysConfigManager;

public class SysConfigCryptoServiceKeyStoreProvider implements CryptoServiceKeyStoreProvider {
@Override
public void put(String id, String value) throws CryptoServiceKeyStoreException {
try {
DB.execWithTransaction(db -> {
SysConfigManager mgr = new SysConfigManager(db, "key.");
if (mgr.get(id, null) != null)
throw new KeyAlreadyExistsException();

mgr.put(id, value, "security.read", "security.write");
return true;
});
} catch (Exception e) {
throw new CryptoServiceKeyStoreException(e);
}
}

@Override
public String get(String id) throws CryptoServiceKeyStoreException {
try {
return DB.execWithTransaction(db -> {
SysConfigManager mgr = new SysConfigManager(db, "key.");
return mgr.get(id, null);
});
} catch (Exception e) {
throw new CryptoServiceKeyStoreException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ public void exec(CLIContext cli, String[] args) throws Exception {
cs = NameRegistrar.getIfExists("crypto-service");
if (args.length != 3) {
usage(cli);
if (cs == null)
cli.println ("'crypto-service' not registered");
return;
}
if (cs == null) {
cli.println("'crypto-service' not registered");
return;
}
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ public void exec(CLIContext cli, String[] args) throws Exception {
cs = NameRegistrar.getIfExists("crypto-service");
if (args.length != 2) {
usage(cli);
if (cs == null)
cli.println ("'crypto-service' not registered");
return;
}
if (cs == null) {
cli.println("'crypto-service' not registered");
return;
}
encrypt(cli, args[1]);
Expand Down
1 change: 1 addition & 0 deletions modules/testbed/src/dist/deploy/25_crypto_service.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
<property name="lazy" value="false" />
<property name="keylength" value="256" />
<property name="duration" value="86400000" />
<ks-provider class="org.jpos.crypto.SysConfigCryptoServiceKeyStoreProvider" />
</crypto-service>

0 comments on commit f5a9f74

Please sign in to comment.