Skip to content

Commit a3a1a17

Browse files
committed
make in memo keystore persistent. We really need a real keystore .. anyway, good for testing anyway.
1 parent 574c180 commit a3a1a17

File tree

5 files changed

+147
-19
lines changed

5 files changed

+147
-19
lines changed

src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java

Lines changed: 102 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
package net.sharksystem.asap.crypto;
22

3+
import net.sharksystem.SharkException;
4+
import net.sharksystem.asap.ASAPException;
35
import net.sharksystem.asap.ASAPSecurityException;
6+
import net.sharksystem.asap.utils.ASAPSerialization;
7+
import net.sharksystem.fs.ExtraData;
48
import net.sharksystem.utils.Log;
59

610
import javax.crypto.SecretKey;
711
import java.io.*;
812
import java.security.*;
913
import java.security.spec.InvalidKeySpecException;
14+
import java.security.spec.PKCS8EncodedKeySpec;
1015
import java.security.spec.X509EncodedKeySpec;
1116
import java.util.HashMap;
1217

1318
public class InMemoASAPKeyStore implements ASAPKeyStore {
19+
private PrivateKey privateKey;
20+
private PublicKey publicKey;
1421
private KeyPair keyPair;
15-
private final CharSequence ownerID;
22+
private CharSequence ownerID;
1623
private long keyPairCreationTime = 0;
1724

1825
// for debugging only - we don't have private key in real apps
@@ -35,10 +42,16 @@ public InMemoASAPKeyStore(CharSequence ownerID) throws ASAPSecurityException {
3542
* Setup key store with a key pair
3643
* @param ownerID
3744
* @param ownerKeyPair
45+
* @deprecated
3846
*/
3947
public InMemoASAPKeyStore(CharSequence ownerID, KeyPair ownerKeyPair, long keyPairCreationTime) {
4048
this.ownerID = ownerID;
4149
this.keyPair = ownerKeyPair;
50+
if(ownerKeyPair != null) {
51+
this.privateKey = ownerKeyPair.getPrivate();
52+
this.publicKey = ownerKeyPair.getPublic();
53+
}
54+
4255
this.keyPairCreationTime = keyPairCreationTime;
4356
}
4457

@@ -73,13 +86,12 @@ public int getSymmetricKeyLen() {
7386
return ASAPKeyStore.DEFAULT_SYMMETRIC_KEY_SIZE;
7487
}
7588

76-
private String getLogStart() {
77-
return this.getClass().getSimpleName() + ": ";
78-
}
79-
8089
public void generateKeyPair() throws ASAPSecurityException {
8190
this.setKeyPair(this.generateNewKeyPair());
91+
this.privateKey = this.keyPair.getPrivate();
92+
this.publicKey = this.keyPair.getPublic();
8293
this.keyPairCreationTime = System.currentTimeMillis();
94+
this.save();
8395
}
8496

8597
private KeyPair generateNewKeyPair() throws ASAPSecurityException {
@@ -107,15 +119,22 @@ public KeyPair createTestPeer(String id) throws ASAPSecurityException {
107119
return keyPair;
108120
}
109121

122+
private void checkKeyPairExistence() throws ASAPSecurityException {
123+
if(this.keyPair == null) {
124+
Log.writeLog(this, "create new keypair since requested but missing");
125+
this.generateKeyPair();
126+
}
127+
}
128+
110129
@Override
111130
public PrivateKey getPrivateKey() throws ASAPSecurityException {
112-
if(this.keyPair == null) throw new ASAPSecurityException("private key does not exist");
131+
this.checkKeyPairExistence();
113132
return this.keyPair.getPrivate();
114133
}
115134

116135
@Override
117136
public PublicKey getPublicKey() throws ASAPSecurityException {
118-
if(this.keyPair == null) throw new ASAPSecurityException("private key does not exist");
137+
this.checkKeyPairExistence();
119138
return this.keyPair.getPublic();
120139
}
121140

@@ -184,7 +203,6 @@ public String getAsymmetricSigningAlgorithm() {
184203
}
185204

186205
public void addKeyPair(String peerID, KeyPair keyPair) {
187-
188206
this.peerKeyPairs.put(peerID, keyPair);
189207
}
190208

@@ -242,4 +260,80 @@ public void readPublicKey(CharSequence peer, InputStream is) throws ASAPSecurity
242260
// store it
243261
this.putPublicKey(peer, publicKey);
244262
}
263+
264+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
265+
// persist //
266+
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
267+
268+
private ExtraData mementoExtraData;
269+
private CharSequence mementoKey;
270+
271+
public void setMementoTarget(ExtraData extraData, CharSequence key) {
272+
this.mementoExtraData = extraData;
273+
this.mementoKey = key;
274+
}
275+
276+
private void save() {
277+
if(this.mementoExtraData != null && this.mementoKey != null) {
278+
try {
279+
this.mementoExtraData.putExtra(this.mementoKey, this.createMemento());
280+
} catch (IOException | SharkException e) {
281+
Log.writeLogErr(this, "cannot write memento: " + e.getLocalizedMessage());
282+
}
283+
} else {
284+
Log.writeLog(this, "cannot write data - no persistent storage");
285+
}
286+
}
287+
288+
byte[] createMemento() throws ASAPSecurityException, IOException {
289+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
290+
291+
// encoded private key
292+
ASAPSerialization.writeByteArray(this.getPrivateKey().getEncoded(), baos);
293+
// private key algorithm
294+
ASAPSerialization.writeCharSequenceParameter(this.getPrivateKey().getAlgorithm(), baos);
295+
// private key format
296+
ASAPSerialization.writeCharSequenceParameter(this.getPrivateKey().getFormat(), baos);
297+
298+
// public key encoded
299+
ASAPSerialization.writeByteArray(this.getPublicKey().getEncoded(), baos);
300+
// public key algorithm
301+
ASAPSerialization.writeCharSequenceParameter(this.getPublicKey().getAlgorithm(), baos);
302+
// public key format
303+
ASAPSerialization.writeCharSequenceParameter(this.getPublicKey().getFormat(), baos);
304+
305+
// creation time
306+
ASAPSerialization.writeLongParameter(this.keyPairCreationTime, baos);
307+
308+
// ownerID
309+
ASAPSerialization.writeCharSequenceParameter(this.ownerID, baos);
310+
311+
return baos.toByteArray();
312+
}
313+
314+
public void restoreFromMemento(byte[] mementoData) throws IOException, ASAPException {
315+
ByteArrayInputStream bais = new ByteArrayInputStream(mementoData);
316+
317+
byte[] privateKeyBytes = ASAPSerialization.readByteArray(bais);
318+
String privateKeyAlgorithm = ASAPSerialization.readCharSequenceParameter(bais);
319+
String privateKeyFormat = ASAPSerialization.readCharSequenceParameter(bais);
320+
321+
byte[] publicKeyBytes = ASAPSerialization.readByteArray(bais);
322+
String publicKeyAlgorithm = ASAPSerialization.readCharSequenceParameter(bais);
323+
String publicKeyFormat = ASAPSerialization.readCharSequenceParameter(bais);
324+
325+
// reproduce private key
326+
// as to be seen, pretty limited alg/format support yet :/
327+
try {
328+
KeyFactory kf = KeyFactory.getInstance("RSA");
329+
this.privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
330+
this.publicKey = kf.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
331+
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
332+
throw new ASAPException("cannot restore keystore form memento: " + e.getLocalizedMessage());
333+
}
334+
335+
// reset those simple data after that critical stuff.
336+
this.keyPairCreationTime = ASAPSerialization.readLongParameter(bais);
337+
this.ownerID = ASAPSerialization.readCharSequenceParameter(bais);
338+
}
245339
}

src/main/java/net/sharksystem/asap/engine/ASAPInternalPeerFS.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -702,7 +702,7 @@ public ASAPKeyStore getASAPKeyStore() throws ASAPSecurityException {
702702

703703
public ExtraData getExtraData() throws SharkException, IOException {
704704
if(this.extraData == null) {
705-
this.extraData = new ExtraDataFS(this.rootFolderName);
705+
this.extraData = new ExtraDataFS(this.rootFolderName, "asapPeerExtraData");
706706
}
707707

708708
return this.extraData;
@@ -718,7 +718,7 @@ public void putExtra(CharSequence key, Integer value) throws IOException, SharkE
718718
}
719719

720720
@Override
721-
public void putExtra(CharSequence key, String value) throws IOException, SharkException {
721+
public void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException {
722722
this.getExtraData().putExtra(key, value);
723723
}
724724

src/main/java/net/sharksystem/fs/ExtraData.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ public interface ExtraData {
1111

1212
void putExtra(CharSequence key, Integer value) throws IOException, SharkException;
1313

14-
void putExtra(CharSequence key, String value) throws IOException, SharkException;
14+
void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException;
1515

1616
void putExtra(CharSequence key, Set<CharSequence> value) throws IOException, SharkException;
1717

18-
// get a parameter by a key
18+
/** get a parameter by a key
19+
*
20+
* @param key
21+
* @return
22+
* @throws IOException
23+
* @throws SharkException if no such key exists
24+
*/
1925
byte[] getExtra(CharSequence key) throws IOException, SharkException;
2026

2127
int getExtraInteger(CharSequence key) throws IOException, SharkException;

src/main/java/net/sharksystem/fs/ExtraDataFS.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,21 @@
1010
import java.util.Set;
1111

1212
public class ExtraDataFS implements ExtraData {
13-
public static final String EXTRA_FILE_EXTENSION = ".extraData";
14-
private final CharSequence fileExtension;
13+
public static final String DEFAULT_FILE_NAME = ".extraData";
14+
private final CharSequence fileName;
1515
private final CharSequence rootFolderName;
1616

1717
private Map<CharSequence, byte[]> extraData = new HashMap<>();
1818

1919
public ExtraDataFS(CharSequence rootFolderName) throws SharkException, IOException {
20-
this(rootFolderName, EXTRA_FILE_EXTENSION);
20+
this(rootFolderName, DEFAULT_FILE_NAME);
2121
}
2222

2323
public ExtraDataFS(CharSequence rootFolder, CharSequence fileName) throws IOException, SharkException {
2424
this.rootFolderName = rootFolder;
25-
this.fileExtension = fileName;
25+
// hide file in any case
26+
if(fileName.charAt(0) != '.') this.fileName = "." + fileName;
27+
else this.fileName = fileName;
2628
File rootFolderFile = new File(rootFolder.toString());
2729
if(!rootFolderFile.exists()) {
2830
// create
@@ -32,7 +34,7 @@ public ExtraDataFS(CharSequence rootFolder, CharSequence fileName) throws IOExce
3234
}
3335

3436
private File getExtraFile() {
35-
String extraFileName = this.rootFolderName + "/" + EXTRA_FILE_EXTENSION;
37+
String extraFileName = this.rootFolderName + "/" + fileName;
3638
return new File(extraFileName);
3739
}
3840

@@ -146,7 +148,7 @@ public void putExtra(CharSequence key, Integer value) throws IOException, SharkE
146148
}
147149

148150
@Override
149-
public void putExtra(CharSequence key, String value) throws IOException, SharkException {
151+
public void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException {
150152
ByteArrayOutputStream baos = new ByteArrayOutputStream();
151153
ASAPSerialization.writeCharSequenceParameter(value, baos);
152154
this.putExtra(key, baos.toByteArray());
@@ -165,7 +167,9 @@ public void putExtra(CharSequence key, Set<CharSequence> value) throws IOExcepti
165167
*/
166168
public byte[] getExtra(CharSequence key) throws IOException, SharkException {
167169
this.restoreExtraData();
168-
return this.extraData.get(key);
170+
byte[] value = this.extraData.get(key);
171+
if(value == null) throw new SharkException("no value for key" + key);
172+
return value;
169173
}
170174

171175
@Override
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package net.sharksystem.asap.crypto;
2+
3+
import net.sharksystem.asap.ASAPException;
4+
import net.sharksystem.asap.ASAPSecurityException;
5+
import org.junit.Test;
6+
7+
import java.io.IOException;
8+
9+
import static net.sharksystem.utils.testsupport.TestConstants.ALICE_ID;
10+
11+
public class PersistInMemoKeystore {
12+
/**
13+
* It is not really a good idea to implement a serialization like this. It is extremely
14+
* vulnerable... But is makes testing a bit easier.
15+
*/
16+
@Test
17+
public void writeAndRestore() throws ASAPException, IOException {
18+
InMemoASAPKeyStore imKeystore = new InMemoASAPKeyStore("TestPeer");
19+
imKeystore.generateKeyPair();
20+
21+
byte[] memento = imKeystore.createMemento();
22+
imKeystore.restoreFromMemento(memento);
23+
}
24+
}

0 commit comments

Comments
 (0)