From 4f72f373a6f54179024dd3fc567a0fd38340179f Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sat, 10 Oct 2026 22:28:23 +0200
Subject: [PATCH 1/7] write javadoc: KeyStore and ExtraData
---
.../sharksystem/asap/crypto/ASAPKeyStore.java | 27 ++++--
.../asap/crypto/InMemoASAPKeyStore.java | 90 +++++++++++++------
.../asap/utils/ASAPSerialization.java | 7 ++
.../java/net/sharksystem/fs/ExtraData.java | 70 +++++++++++++--
.../java/net/sharksystem/fs/ExtraDataFS.java | 31 +++----
5 files changed, 170 insertions(+), 55 deletions(-)
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java b/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java
index 4607641..da5f5ad 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java
@@ -8,29 +8,40 @@
import java.security.PublicKey;
/**
- * Basic requirement to encrypt / decrypt and sign/verify messages.
+ * A key store provides access to local key pairs as well as utilities for managing
+ * the key pair of the store's owner.
+ *
+ * Key stores are required for encryption/ decryption as well as creating
+ * and verifying signatures, see e.g. {@link ASAPCryptoAlgorithms}.
*/
public interface ASAPKeyStore extends ASAPCryptoParameterStorage {
/**
- * @param subjectID
- * @return public key of recipient - to encrypt
- * @throws ASAPSecurityException if key cannot be found
+ * Returns the public key of the specified peer.
+ * @param subjectID ID of the peer
+ * @return public key of the peer whose ID matches the given ID
+ * @throws ASAPSecurityException if the requested key is not present in the key store
*/
PublicKey getPublicKey(CharSequence subjectID) throws ASAPSecurityException;
/**
- *
- * @param peerID
- * @return true if peerID is owners' id.
+ * Determines if a peer is the owner of this key store.
+ * @param peerID ID of the peer to test
+ * @return true if and only if the specified ID matches this key store's owner's ID
*/
boolean isOwner(CharSequence peerID);
CharSequence getOwner();
/**
- * A new key pair is created
+ * Generates a new key pair for this key store's owner and stores it.
+ * @throws ASAPSecurityException if key generation fails, e.g. this key store's cryptographic algorithm
+ * is not available in the current environment or an invalid key size is used
*/
void generateKeyPair() throws ASAPSecurityException;
+ /**
+ * Updates the persistence backend for this key store.
+ * @param extraData the persistence interface to use
+ */
void setMementoTarget(ExtraData extraData);
}
diff --git a/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java b/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java
index 03139a7..8165cdc 100644
--- a/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java
+++ b/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java
@@ -15,6 +15,10 @@
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
+/**
+ * A key store that lives entirely in memory.
+ * Key pair generation for the owner is currently limited to RSA.
+ */
public class InMemoASAPKeyStore implements ASAPKeyStore {
private static final CharSequence ASAP_KEYSTORE_MEMENTO_KEY = "asapKeyStoreMemento";
private PrivateKey privateKey;
@@ -29,20 +33,19 @@ public class InMemoASAPKeyStore implements ASAPKeyStore {
private HashMap peerPublicKeys = new HashMap();
/**
- * Setup key store, A key pair will be generated
- * @param ownerID
- * @throws ASAPSecurityException
+ * Constructs a new key store for the given owner.
+ * @param ownerID ID of this key store's owner
*/
- public InMemoASAPKeyStore(CharSequence ownerID) throws ASAPSecurityException {
- // generate owners key pair;
+ public InMemoASAPKeyStore(CharSequence ownerID) {
this.ownerID = ownerID;
- //this.generateKeyPair();
}
/**
- * Setup key store with a key pair
- * @param ownerID
- * @param ownerKeyPair
+ * Constructs a new key store for the given owner with the specified key pair.
+ * @param ownerID ID of this key store's owner
+ * @param ownerKeyPair key pair of the owner
+ * @param keyPairCreationTime a timestamp representing the date the given key pair was created on, in milliseconds
+ * since epoch (January 1, 1970 UTC).
* @deprecated
*/
public InMemoASAPKeyStore(CharSequence ownerID, KeyPair ownerKeyPair, long keyPairCreationTime) {
@@ -60,6 +63,12 @@ protected void setKeyPair(KeyPair keyPair) {
this.keyPair = keyPair;
}
+ /**
+ * Returns the key pair of this store's owner.
+ * If this pair does not exist yet, the store attempts to generate and store one.
+ * @return the key pair. null if no pair exists and generation fails.
+ * @see ASAPKeyStore#generateKeyPair()
+ */
public KeyPair getKeyPair() {
if(this.keyPair == null) {
Log.writeLog(this, "key pair not yet generated - do it now");
@@ -74,19 +83,23 @@ public KeyPair getKeyPair() {
return this.keyPair;
}
+ @Override
public SecretKey generateSymmetricKey() throws ASAPSecurityException {
return ASAPCryptoAlgorithms.generateSymmetricKey(
DEFAULT_SYMMETRIC_KEY_TYPE, DEFAULT_SYMMETRIC_KEY_SIZE);
}
+ @Override
public long getKeysCreationTime() throws ASAPSecurityException {
return this.keyPairCreationTime;
}
+ @Override
public int getSymmetricKeyLen() {
return ASAPKeyStore.DEFAULT_SYMMETRIC_KEY_SIZE;
}
+ @Override
public void generateKeyPair() throws ASAPSecurityException {
this.setKeyPair(this.generateNewKeyPair());
this.privateKey = this.keyPair.getPrivate();
@@ -97,7 +110,7 @@ public void generateKeyPair() throws ASAPSecurityException {
private KeyPair generateNewKeyPair() throws ASAPSecurityException {
Log.writeLog(this, "create key pair");
- KeyPairGenerator keyGen = null;
+ KeyPairGenerator keyGen;
try {
keyGen = KeyPairGenerator.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
@@ -214,8 +227,14 @@ public void addKeyPair(String peerID, KeyPair keyPair) {
}
/**
- * Write storage owners' public key to stream
- * @param os
+ * Writes this store's owner's public key to the given output stream.
+ * If no key exists yet, the store attempts to generate it.
+ * The key's metadata is written as well to enable the reader to reconstruct it.
+ * @param os the stream to write to
+ * @throws ASAPSecurityException if no key exists and key generation fails
+ * @throws IOException if an I/O error occurs
+ * @see ASAPKeyStore#generateKeyPair()
+ * @see InMemoASAPKeyStore#readPublicKey(CharSequence, InputStream)
*/
public void writePublicKey(OutputStream os) throws ASAPSecurityException, IOException {
PublicKey publicKey = this.getPublicKey();
@@ -223,7 +242,6 @@ public void writePublicKey(OutputStream os) throws ASAPSecurityException, IOExce
String format = publicKey.getFormat();
String algorithm = publicKey.getAlgorithm();
byte[] byteEncodedPublicKey = publicKey.getEncoded();
- int length = byteEncodedPublicKey.length;
// makes it much easier to serialize simple data
DataOutputStream dos = new DataOutputStream(os);
@@ -238,11 +256,14 @@ public void writePublicKey(OutputStream os) throws ASAPSecurityException, IOExce
}
/**
- * Read public key from another peer from an extern source (input stream)
- * @param peer
- * @param is
+ * Reads a public key from the given input stream and adds it to this store.
+ * @param peer ID of the public key's owner
+ * @param is the stream to read from
+ * @throws IOException if an I/O error occurs
+ * @throws NoSuchAlgorithmException
+ * @throws InvalidKeySpecException
*/
- public void readPublicKey(CharSequence peer, InputStream is) throws ASAPSecurityException, IOException, NoSuchAlgorithmException, InvalidKeySpecException {
+ public void readPublicKey(CharSequence peer, InputStream is) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
DataInputStream dis = new DataInputStream(is);
// read in same order as written
@@ -253,7 +274,7 @@ public void readPublicKey(CharSequence peer, InputStream is) throws ASAPSecurity
// allocate memory
byte[] byteEncodedPublicKey = new byte[len];
- // read encoded key directly from stream
+ // FIXME: Method currently doesn't store the received key as per the specification.
is.read(byteEncodedPublicKey);
// create key object
@@ -297,22 +318,33 @@ private void save() {
}
}
+ /**
+ * Returns a byte representation of this store's owner's key pair and related metadata.
+ * If no key pair exists yet, the store attempts to create one.
+ * @return a byte array holding the owner's key pair
+ * @throws ASAPException if no key pair exists and key generation fails
+ * @throws IOException if an I/O error occurs
+ * @see ASAPKeyStore#generateKeyPair()
+ * @see InMemoASAPKeyStore#restoreMemento(byte[])
+ */
public byte[] getMemento() throws ASAPException, IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ PrivateKey privateKey = this.getPrivateKey();
// encoded private key
- ASAPSerialization.writeByteArray(this.getPrivateKey().getEncoded(), baos);
+ ASAPSerialization.writeByteArray(privateKey.getEncoded(), baos);
// private key algorithm
- ASAPSerialization.writeCharSequenceParameter(this.getPrivateKey().getAlgorithm(), baos);
+ ASAPSerialization.writeCharSequenceParameter(privateKey.getAlgorithm(), baos);
// private key format
- ASAPSerialization.writeCharSequenceParameter(this.getPrivateKey().getFormat(), baos);
+ ASAPSerialization.writeCharSequenceParameter(privateKey.getFormat(), baos);
+ PublicKey publicKey = this.getPublicKey();
// public key encoded
- ASAPSerialization.writeByteArray(this.getPublicKey().getEncoded(), baos);
+ ASAPSerialization.writeByteArray(publicKey.getEncoded(), baos);
// public key algorithm
- ASAPSerialization.writeCharSequenceParameter(this.getPublicKey().getAlgorithm(), baos);
+ ASAPSerialization.writeCharSequenceParameter(publicKey.getAlgorithm(), baos);
// public key format
- ASAPSerialization.writeCharSequenceParameter(this.getPublicKey().getFormat(), baos);
+ ASAPSerialization.writeCharSequenceParameter(publicKey.getFormat(), baos);
// creation time
ASAPSerialization.writeLongParameter(this.keyPairCreationTime, baos);
@@ -323,6 +355,14 @@ public byte[] getMemento() throws ASAPException, IOException {
return baos.toByteArray();
}
+ /**
+ * Constructs a key pair from the given byte array and stores it as this key store's owner's.
+ * Currently, only the RSA cryptosystem is supported.
+ * @param mementoData the byte representation of the key pair
+ * @throws IOException if an I/O error occurs
+ * @throws ASAPException if the array's end is reached or constructing the key pair fails
+ * @see InMemoASAPKeyStore#getMemento()
+ */
public void restoreMemento(byte[] mementoData) throws IOException, ASAPException {
ByteArrayInputStream bais = new ByteArrayInputStream(mementoData);
@@ -341,7 +381,7 @@ public void restoreMemento(byte[] mementoData) throws IOException, ASAPException
this.privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));
this.publicKey = kf.generatePublic(new X509EncodedKeySpec(publicKeyBytes));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new ASAPException("cannot restore keystore form memento: " + e.getLocalizedMessage());
+ throw new ASAPException("cannot restore keystore from memento: " + e.getLocalizedMessage());
}
// reset those simple data after that critical stuff.
diff --git a/src/main/java/net/sharksystem/asap/utils/ASAPSerialization.java b/src/main/java/net/sharksystem/asap/utils/ASAPSerialization.java
index 76c95de..8bb201b 100644
--- a/src/main/java/net/sharksystem/asap/utils/ASAPSerialization.java
+++ b/src/main/java/net/sharksystem/asap/utils/ASAPSerialization.java
@@ -225,6 +225,13 @@ public static byte readByteParameter(InputStream is) throws IOException, ASAPExc
return readByte(is);
}
+ /**
+ * Reads a byte from the given stream.
+ * @param is the stream to read from
+ * @return the next byte
+ * @throws IOException if an I/O error occurs
+ * @throws ASAPException if the end of the stream is reached
+ */
public static byte readByte(InputStream is) throws IOException, ASAPException {
try {
int value = is.read();
diff --git a/src/main/java/net/sharksystem/fs/ExtraData.java b/src/main/java/net/sharksystem/fs/ExtraData.java
index 695964c..181da32 100644
--- a/src/main/java/net/sharksystem/fs/ExtraData.java
+++ b/src/main/java/net/sharksystem/fs/ExtraData.java
@@ -5,30 +5,86 @@
import java.io.IOException;
import java.util.Set;
+/**
+ * ExtraData provides utilities for writing to and reading from persistent storage using key-value pairs.
+ */
public interface ExtraData {
- // remember a parameter with a key
+ /**
+ * Stores the given byte array and associates it with the given key.
+ * @param key the key of the datum
+ * @param value the byte array to store
+ * @throws IOException if the datum cannot be written
+ * @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
+ */
void putExtra(CharSequence key, byte[] value) throws IOException, SharkException;
+ /**
+ * Stores the given integer value and associates it with the given key.
+ * @param key the key of the datum
+ * @param value the integer value to store
+ * @throws IOException if the datum cannot be written
+ * @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
+ */
void putExtra(CharSequence key, Integer value) throws IOException, SharkException;
+ /**
+ * Stores the given char sequence and associates it with the given key.
+ * @param key the key of the datum
+ * @param value the char sequence to store
+ * @throws IOException if the datum cannot be written
+ * @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
+ */
void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException;
+ /**
+ * Stores the given set f char sequences and associates it with the given key.
+ * @param key the key of the datum
+ * @param value the set to store
+ * @throws IOException if the datum cannot be written
+ * @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
+ */
void putExtra(CharSequence key, Set value) throws IOException, SharkException;
- /** get a parameter by a key
- *
- * @param key
- * @return
- * @throws IOException
+ /**
+ * Returns the byte array associated with the given key.
+ * @param key the key whose value is to be retrieved
+ * @return the value associated with the key. A value of null indicates that the key had been mapped onto null.
+ * @throws IOException if an I/O error occurs
* @throws SharkException if no such key exists
*/
byte[] getExtra(CharSequence key) throws IOException, SharkException;
+ /**
+ * Returns the integer value associated with the given key.
+ * @param key the key whose value is to be retrieved
+ * @return the value associated with the key.
+ * @throws IOException if an I/O error occurs
+ * @throws SharkException if no such key exists
+ */
int getExtraInteger(CharSequence key) throws IOException, SharkException;
+ /**
+ * Returns the set of char sequences associated with the given key.
+ * @param key the key whose value is to be retrieved
+ * @return the value associated with the key.
+ * @throws IOException if an I/O error occurs
+ * @throws SharkException if no such key exists
+ */
Set getExtraCharSequenceSetParameter(CharSequence key) throws IOException, SharkException;
+ /**
+ * Returns the string value associated with the given key.
+ * @param key the key whose value is to be retrieved
+ * @return the value associated with the key.
+ * @throws IOException if an I/O error occurs
+ * @throws SharkException if no such key exists
+ */
String getExtraString(CharSequence key) throws IOException, SharkException;
- // remove all data
+
+ /**
+ * Deletes all data from storage.
+ * @throws IOException if an I/O error occurs
+ * @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
+ */
void removeAll() throws IOException, SharkException;
}
diff --git a/src/main/java/net/sharksystem/fs/ExtraDataFS.java b/src/main/java/net/sharksystem/fs/ExtraDataFS.java
index 442ef49..373bc62 100644
--- a/src/main/java/net/sharksystem/fs/ExtraDataFS.java
+++ b/src/main/java/net/sharksystem/fs/ExtraDataFS.java
@@ -9,6 +9,9 @@
import java.util.Map;
import java.util.Set;
+/**
+ * An ExtraData implementation backed by the filesystem.
+ */
public class ExtraDataFS implements ExtraData {
public static final String DEFAULT_FILE_NAME = ".extraData";
private final CharSequence fileName;
@@ -23,8 +26,12 @@ public ExtraDataFS(CharSequence rootFolderName) throws SharkException, IOExcepti
public ExtraDataFS(CharSequence rootFolder, CharSequence fileName) throws IOException, SharkException {
this.rootFolderName = rootFolder;
// hide file in any case
- if(fileName.charAt(0) != '.') this.fileName = "." + fileName;
- else this.fileName = fileName;
+ if(fileName.charAt(0) != '.') {
+ this.fileName = "." + fileName;
+ }
+ else {
+ this.fileName = fileName;
+ }
File rootFolderFile = new File(rootFolder.toString());
if(!rootFolderFile.exists()) {
// create
@@ -50,7 +57,7 @@ private File getExtraFile() {
private long timeStampSyncExtraData = -1; // never saved anything
private void extraDataSync() throws IOException, SharkException {
- InputStream is = null;
+ InputStream is;
try {
is = new FileInputStream(this.getExtraFile());
}
@@ -96,7 +103,7 @@ public void saveExtraData() throws IOException {
* @throws ASAPException
*/
public void restoreExtraData() throws IOException, SharkException {
- InputStream is = null;
+ InputStream is;
try {
is = new FileInputStream(this.getExtraFile());
}
@@ -129,11 +136,7 @@ public void restoreExtraData() throws IOException, SharkException {
is.close();
}
- /**
- * Make a value persistent with key
- * @param key
- * @param value
- */
+ @Override
public void putExtra(CharSequence key, byte[] value) throws IOException, SharkException {
this.extraDataSync();
this.extraData.put(key, value);
@@ -160,15 +163,12 @@ public void putExtra(CharSequence key, Set value) throws IOExcepti
this.putExtra(key, baos.toByteArray());
}
- /**
- * Return a value - can be null if null was set as value.
- * @param key
- * @throws ASAPException key never used in putExtra
- */
public byte[] getExtra(CharSequence key) throws IOException, SharkException {
this.restoreExtraData();
byte[] value = this.extraData.get(key);
- if(value == null) throw new SharkException("no value for key" + key);
+ if (value == null) {
+ throw new SharkException("no value for key " + key);
+ }
return value;
}
@@ -184,6 +184,7 @@ public String getExtraString(CharSequence key) throws IOException, SharkExceptio
return ASAPSerialization.readCharSequenceParameter(bais);
}
+ @Override
public Set getExtraCharSequenceSetParameter(CharSequence key) throws IOException, SharkException {
ByteArrayInputStream bais = new ByteArrayInputStream(this.getExtra(key));
return ASAPSerialization.readCharSequenceSetParameter(bais);
From 5c8c699d39f3e326b3e8368f71729613392d02a9 Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sun, 11 Oct 2026 11:12:21 +0200
Subject: [PATCH 2/7] Some docs, default implementations for ExtraData
---
.../asap/engine/ASAPInternalPeerFS.java | 31 +----------
.../java/net/sharksystem/fs/ExtraData.java | 39 +++++++++++--
.../java/net/sharksystem/fs/ExtraDataFS.java | 55 ++-----------------
3 files changed, 41 insertions(+), 84 deletions(-)
diff --git a/src/main/java/net/sharksystem/asap/engine/ASAPInternalPeerFS.java b/src/main/java/net/sharksystem/asap/engine/ASAPInternalPeerFS.java
index e191caf..2e891fd 100644
--- a/src/main/java/net/sharksystem/asap/engine/ASAPInternalPeerFS.java
+++ b/src/main/java/net/sharksystem/asap/engine/ASAPInternalPeerFS.java
@@ -704,6 +704,7 @@ public ASAPKeyStore getAsapKeyStore() throws ASAPSecurityException {
///////////////////////////////////////////////////////////////////////////////////////////////////////////
private ExtraData extraData = null;
+ @Override
public ExtraData getExtraData() throws SharkException, IOException {
if(this.extraData == null) {
this.extraData = new ExtraDataFS(this.rootFolderName, "asapPeerExtraData");
@@ -712,44 +713,16 @@ public ExtraData getExtraData() throws SharkException, IOException {
return this.extraData;
}
- public void putExtra(CharSequence key, byte[] value) throws IOException, SharkException {
- this.getExtraData().putExtra(key, value);
- }
-
@Override
- public void putExtra(CharSequence key, Integer value) throws IOException, SharkException {
- this.getExtraData().putExtra(key, value);
- }
-
- @Override
- public void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException {
+ public void putExtra(CharSequence key, byte[] value) throws IOException, SharkException {
this.getExtraData().putExtra(key, value);
}
@Override
- public void putExtra(CharSequence key, Set value) throws IOException, SharkException {
- this.getExtraData().putExtra(key, value);
- }
-
public byte[] getExtra(CharSequence key) throws IOException, SharkException {
return this.getExtraData().getExtra(key);
}
- @Override
- public int getExtraInteger(CharSequence key) throws IOException, SharkException {
- return this.getExtraData().getExtraInteger(key);
- }
-
- @Override
- public Set getExtraCharSequenceSetParameter(CharSequence key) throws IOException, SharkException {
- return this.getExtraData().getExtraCharSequenceSetParameter(key);
- }
-
- @Override
- public String getExtraString(CharSequence key) throws IOException, SharkException {
- return this.getExtraData().getExtraString(key);
- }
-
@Override
public void removeAll() throws IOException, SharkException {
this.getExtraData().removeAll();
diff --git a/src/main/java/net/sharksystem/fs/ExtraData.java b/src/main/java/net/sharksystem/fs/ExtraData.java
index 181da32..976a952 100644
--- a/src/main/java/net/sharksystem/fs/ExtraData.java
+++ b/src/main/java/net/sharksystem/fs/ExtraData.java
@@ -1,7 +1,10 @@
package net.sharksystem.fs;
import net.sharksystem.SharkException;
+import net.sharksystem.asap.utils.ASAPSerialization;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Set;
@@ -25,7 +28,11 @@ public interface ExtraData {
* @throws IOException if the datum cannot be written
* @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
*/
- void putExtra(CharSequence key, Integer value) throws IOException, SharkException;
+ default void putExtra(CharSequence key, Integer value) throws IOException, SharkException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ASAPSerialization.writeIntegerParameter(value, baos);
+ putExtra(key, baos.toByteArray());
+ }
/**
* Stores the given char sequence and associates it with the given key.
@@ -34,7 +41,11 @@ public interface ExtraData {
* @throws IOException if the datum cannot be written
* @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
*/
- void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException;
+ default void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ASAPSerialization.writeCharSequenceParameter(value, baos);
+ putExtra(key, baos.toByteArray());
+ }
/**
* Stores the given set f char sequences and associates it with the given key.
@@ -43,7 +54,11 @@ public interface ExtraData {
* @throws IOException if the datum cannot be written
* @throws SharkException if a (de-)serialization error occurs, e.g. the underlying data is corrupted
*/
- void putExtra(CharSequence key, Set value) throws IOException, SharkException;
+ default void putExtra(CharSequence key, Set value) throws IOException, SharkException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ASAPSerialization.writeCharSequenceSetParameter(value, baos);
+ putExtra(key, baos.toByteArray());
+ }
/**
* Returns the byte array associated with the given key.
@@ -61,7 +76,11 @@ public interface ExtraData {
* @throws IOException if an I/O error occurs
* @throws SharkException if no such key exists
*/
- int getExtraInteger(CharSequence key) throws IOException, SharkException;
+ default int getExtraInteger(CharSequence key) throws IOException, SharkException {
+ byte[] value = getExtra(key);
+ ByteArrayInputStream bais = new ByteArrayInputStream(value);
+ return ASAPSerialization.readIntegerParameter(bais);
+ }
/**
* Returns the set of char sequences associated with the given key.
@@ -70,7 +89,11 @@ public interface ExtraData {
* @throws IOException if an I/O error occurs
* @throws SharkException if no such key exists
*/
- Set getExtraCharSequenceSetParameter(CharSequence key) throws IOException, SharkException;
+ default Set getExtraCharSequenceSetParameter(CharSequence key) throws IOException, SharkException {
+ byte[] value = getExtra(key);
+ ByteArrayInputStream bais = new ByteArrayInputStream(value);
+ return ASAPSerialization.readCharSequenceSetParameter(bais);
+ }
/**
* Returns the string value associated with the given key.
@@ -79,7 +102,11 @@ public interface ExtraData {
* @throws IOException if an I/O error occurs
* @throws SharkException if no such key exists
*/
- String getExtraString(CharSequence key) throws IOException, SharkException;
+ default String getExtraString(CharSequence key) throws IOException, SharkException {
+ byte[] value = getExtra(key);
+ ByteArrayInputStream bais = new ByteArrayInputStream(value);
+ return ASAPSerialization.readCharSequenceParameter(bais);
+ }
/**
* Deletes all data from storage.
diff --git a/src/main/java/net/sharksystem/fs/ExtraDataFS.java b/src/main/java/net/sharksystem/fs/ExtraDataFS.java
index 373bc62..fedfaa3 100644
--- a/src/main/java/net/sharksystem/fs/ExtraDataFS.java
+++ b/src/main/java/net/sharksystem/fs/ExtraDataFS.java
@@ -67,13 +67,6 @@ private void extraDataSync() throws IOException, SharkException {
return;
}
- // read time stamp
- long timeStampSaved = ASAPSerialization.readLongParameter(is);
-
- if(this.timeStampSyncExtraData < timeStampSaved) {
- // there is an external copy that was created after our last sync
- }
-
// discard local changes and read from file
this.restoreExtraData();
}
@@ -98,9 +91,9 @@ public void saveExtraData() throws IOException {
}
/**
- * Always restore. If there is no such file - write it.
- * @throws IOException
- * @throws ASAPException
+ * Ensures that this ExtraData holds the most recent data from the file system.
+ * @throws IOException if an I/O error occurs
+ * @throws SharkException if EOF is reached
*/
public void restoreExtraData() throws IOException, SharkException {
InputStream is;
@@ -113,18 +106,19 @@ public void restoreExtraData() throws IOException, SharkException {
}
long timeStampSaved = ASAPSerialization.readLongParameter(is);
+ // false if the data file contains more recent data than this ExtraData,
+ // true if this ExtraData is up-to-date
if(timeStampSaved == this.timeStampSyncExtraData) {
is.close();
return;
}
- // something changed - get a fresh copy
this.timeStampSyncExtraData = timeStampSaved;
this.extraData = new HashMap<>();
int counter = ASAPSerialization.readIntegerParameter(is);
- while(counter-- > 0) {
+ for (int i = 0; i < counter; i++) {
// read key
CharSequence key = ASAPSerialization.readCharSequenceParameter(is);
// value
@@ -144,25 +138,6 @@ public void putExtra(CharSequence key, byte[] value) throws IOException, SharkEx
}
@Override
- public void putExtra(CharSequence key, Integer value) throws IOException, SharkException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ASAPSerialization.writeIntegerParameter(value, baos);
- this.putExtra(key, baos.toByteArray());
- }
-
- @Override
- public void putExtra(CharSequence key, CharSequence value) throws IOException, SharkException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ASAPSerialization.writeCharSequenceParameter(value, baos);
- this.putExtra(key, baos.toByteArray());
- }
-
- public void putExtra(CharSequence key, Set value) throws IOException, SharkException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ASAPSerialization.writeCharSequenceSetParameter(value, baos);
- this.putExtra(key, baos.toByteArray());
- }
-
public byte[] getExtra(CharSequence key) throws IOException, SharkException {
this.restoreExtraData();
byte[] value = this.extraData.get(key);
@@ -172,24 +147,6 @@ public byte[] getExtra(CharSequence key) throws IOException, SharkException {
return value;
}
- @Override
- public int getExtraInteger(CharSequence key) throws IOException, SharkException {
- ByteArrayInputStream bais = new ByteArrayInputStream(this.getExtra(key));
- return ASAPSerialization.readIntegerParameter(bais);
- }
-
- @Override
- public String getExtraString(CharSequence key) throws IOException, SharkException {
- ByteArrayInputStream bais = new ByteArrayInputStream(this.getExtra(key));
- return ASAPSerialization.readCharSequenceParameter(bais);
- }
-
- @Override
- public Set getExtraCharSequenceSetParameter(CharSequence key) throws IOException, SharkException {
- ByteArrayInputStream bais = new ByteArrayInputStream(this.getExtra(key));
- return ASAPSerialization.readCharSequenceSetParameter(bais);
- }
-
@Override
public void removeAll() {
this.getExtraFile().delete();
From 2fd64609ed5443a80c7d83ea8c889d30880e9e36 Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sun, 11 Oct 2026 11:47:59 +0200
Subject: [PATCH 3/7] write javadoc and fixme for ExtraDataFS
---
.../asap/crypto/InMemoASAPKeyStore.java | 2 +-
.../java/net/sharksystem/fs/ExtraDataFS.java | 31 +++++++++++--------
2 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java b/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java
index 8165cdc..1769a20 100644
--- a/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java
+++ b/src/main/java/net/sharksystem/asap/crypto/InMemoASAPKeyStore.java
@@ -17,7 +17,7 @@
/**
* A key store that lives entirely in memory.
- * Key pair generation for the owner is currently limited to RSA.
+ * Key pair generation for the owner is performed lazily and currently limited to RSA with a key size of 2048 bits.
*/
public class InMemoASAPKeyStore implements ASAPKeyStore {
private static final CharSequence ASAP_KEYSTORE_MEMENTO_KEY = "asapKeyStoreMemento";
diff --git a/src/main/java/net/sharksystem/fs/ExtraDataFS.java b/src/main/java/net/sharksystem/fs/ExtraDataFS.java
index fedfaa3..4d2c0ba 100644
--- a/src/main/java/net/sharksystem/fs/ExtraDataFS.java
+++ b/src/main/java/net/sharksystem/fs/ExtraDataFS.java
@@ -1,13 +1,11 @@
package net.sharksystem.fs;
import net.sharksystem.SharkException;
-import net.sharksystem.asap.ASAPException;
import net.sharksystem.asap.utils.ASAPSerialization;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
/**
* An ExtraData implementation backed by the filesystem.
@@ -19,10 +17,23 @@ public class ExtraDataFS implements ExtraData {
private Map extraData = new HashMap<>();
+ /**
+ * Constructs a new ExtraDataFS object, configured to use the default file name and given folder.
+ * @param rootFolderName the folder that will contain the data file
+ * @throws SharkException if the data file already exists and EOF is reached while reading from it
+ * @throws IOException if the data file already exists and an I/O error occurs while reading from it
+ */
public ExtraDataFS(CharSequence rootFolderName) throws SharkException, IOException {
this(rootFolderName, DEFAULT_FILE_NAME);
}
+ /**
+ * Constructs a new ExtraDataFS object, configured to use the given file name and folder.
+ * @param rootFolder the folder that will contain the data file
+ * @param fileName the name of the data file. If not already done, a period will be appended to hide the file.
+ * @throws IOException if the data file already exists and an I/O error occurs while reading from it
+ * @throws SharkException if the data file already exists and EOF is reached while reading from it
+ */
public ExtraDataFS(CharSequence rootFolder, CharSequence fileName) throws IOException, SharkException {
this.rootFolderName = rootFolder;
// hide file in any case
@@ -57,24 +68,18 @@ private File getExtraFile() {
private long timeStampSyncExtraData = -1; // never saved anything
private void extraDataSync() throws IOException, SharkException {
- InputStream is;
- try {
- is = new FileInputStream(this.getExtraFile());
- }
- catch(IOException ioEx) {
- // no such file - save it instead - there is no conflict
+ if (!this.getExtraFile().exists()) {
this.saveExtraData();
- return;
+ } else {
+ this.restoreExtraData();
}
-
- // discard local changes and read from file
- this.restoreExtraData();
}
+ // FIXME: This probably shouldn't be public? It doesn't perform syncing, which might result in data races.
public void saveExtraData() throws IOException {
OutputStream os = new FileOutputStream(this.getExtraFile());
- // write time stamp
+ // write metadata
this.timeStampSyncExtraData = System.currentTimeMillis();
ASAPSerialization.writeLongParameter(this.timeStampSyncExtraData, os);
ASAPSerialization.writeNonNegativeIntegerParameter(this.extraData.size(), os);
From 6e342930d0d6b3b436812bdb724ed046f83c1792 Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sun, 11 Oct 2026 13:38:03 +0200
Subject: [PATCH 4/7] write javadoc for ASAPCryptoAlgorithms,
ASAPCryptoParameterStorage and package-info
---
.../asap/crypto/ASAPCryptoAlgorithms.java | 113 ++++++++++++------
.../crypto/ASAPCryptoParameterStorage.java | 20 +++-
.../sharksystem/asap/crypto/package-info.java | 4 +
3 files changed, 96 insertions(+), 41 deletions(-)
create mode 100644 src/main/java/net/sharksystem/asap/crypto/package-info.java
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
index a22736e..e050f4e 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
@@ -10,19 +10,24 @@
import java.security.*;
import java.util.Base64;
+/**
+ * Provides utilities for encryption, decryption and signatures.
+ */
public class ASAPCryptoAlgorithms {
/**
- * Produces a byte array that consists of:
- * RecipientID | asymmetrically encrypted symmetric key | symmetrically encrypted text
- * @param unencryptedBytes text to be encrypted
- * @param recipient
- * @param ASAPKeyStore
- * @return
- * @throws ASAPSecurityException
+ * Encrypts the given byte array using a symmetric key and writes it to the given output stream. More specifically,
+ * the triple (unencrypted recipient ID, encrypted symmetric key, encrypted byte array) is written. The byte array is encrypted
+ * using the symmetric key, which in turn is encrypted using the recipient's public key from the key store.
+ * The symmetric key is generated by the key store, see {@link ASAPCryptoParameterStorage#generateSymmetricKey()}
+ * @param unencryptedBytes the data to encrypt and write to the stream
+ * @param recipient ID of the recipient
+ * @param ASAPKeyStore this device's key store
+ * @param os the stream to write to
+ * @throws ASAPSecurityException if the peer's public key is not available in the key store or encryption fails,
+ * e.g. the key store's (a-)symmetric algorithm is not available in the environment
*/
public static void writeEncryptedMessagePackage(byte[] unencryptedBytes, CharSequence recipient,
ASAPKeyStore ASAPKeyStore, OutputStream os) throws ASAPSecurityException {
-
PublicKey publicKey = ASAPKeyStore.getPublicKey(recipient);
// there should be an exception - but better safe than sorry
if(publicKey == null) {
@@ -56,12 +61,19 @@ public static void writeEncryptedMessagePackage(byte[] unencryptedBytes, CharSeq
}
}
+ /**
+ * Encrypts the given byte array and returns a message package. For the package's format, see
+ * {@link ASAPCryptoAlgorithms#writeEncryptedMessagePackage(byte[], CharSequence, ASAPKeyStore, OutputStream)}.
+ * @param unencryptedBytes the data to encrypt
+ * @param recipient ID of the recipient
+ * @param ASAPKeyStore this device's key store
+ * @throws ASAPSecurityException if the peer's public key is not available in the key store or encryption fails,
+ * e.g. the key store's (a-)symmetric algorithm is not available in the environment
+ */
public static byte[] produceEncryptedMessagePackage(byte[] unencryptedBytes, CharSequence recipient,
ASAPKeyStore ASAPKeyStore) throws ASAPSecurityException {
-
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeEncryptedMessagePackage(unencryptedBytes, recipient, ASAPKeyStore, baos);
- // return whole block of bytes
return baos.toByteArray();
}
@@ -71,27 +83,34 @@ public static SecretKey createSymmetricKey(byte[] encodedSymmetricKey,
}
/**
- * Decrypt content from an encrypted message package
- * @param encryptedMessagePackage package (most likely received from another peer)
- * @param asapKeyStore peers' key store
- * @return decrypted message
- * @throws ASAPSecurityException cannot decrypt - most likely: this peer is not receiver.
+ * Decrypts an encrypted message package.
+ * @param encryptedMessagePackage the package to decrypt
+ * @param asapKeyStore this device's key store
+ * @return the decrypted data
+ * @throws ASAPSecurityException if decryption fails, e.g. the key store's algorithm is not available in the current
+ * environment or the data was not encrypted with the key store owner's public key
*/
public static byte[] decryptPackage(EncryptedMessagePackage encryptedMessagePackage,
ASAPKeyStore asapKeyStore) throws ASAPSecurityException {
+ byte[] encryptedSymmetricKey = encryptedMessagePackage.getEncryptedSymmetricKey();
+ byte[] encodedSymmetricKey = decryptAsymmetric(encryptedSymmetricKey, asapKeyStore);
- byte[] encodedSymmetricKey = decryptAsymmetric(
- encryptedMessagePackage.getEncryptedSymmetricKey(),
- asapKeyStore);
-
- // create symmetric key object
SecretKey symmetricKey = createSymmetricKey(encodedSymmetricKey, asapKeyStore);
-
- // decrypt content
- return decryptSymmetric(encryptedMessagePackage.getEncryptedContent(), symmetricKey, asapKeyStore);
+ byte[] encryptedContent = encryptedMessagePackage.getEncryptedContent();
+ return decryptSymmetric(encryptedContent, symmetricKey, asapKeyStore);
}
+ /**
+ * Generates a symmetric key for the given algorithm and key size.
+ * @param keyType the name of the algorithm to use.
+ * See
+ * Java Security Standard Algorithm Names
+ * for more.
+ * @param size the size of the key, in bits
+ * @return the symmetric key
+ * @throws ASAPSecurityException if the requested algorithm is not available in the current environment
+ */
public static SecretKey generateSymmetricKey(String keyType, int size) throws ASAPSecurityException {
try {
KeyGenerator gen = KeyGenerator.getInstance(keyType);
@@ -111,6 +130,10 @@ public static boolean sameID(CharSequence peerA, CharSequence peerB) {
return peerAString.equalsIgnoreCase(peerBString);
}
+ /**
+ * A triple with the components recipient (unencrypted), symmetric key (asymmetrically encrypted) and
+ * content (symmetrically encrypted).
+ */
public interface EncryptedMessagePackage {
CharSequence getReceiver();
byte[] getEncryptedSymmetricKey();
@@ -119,7 +142,6 @@ public interface EncryptedMessagePackage {
public static EncryptedMessagePackage parseEncryptedMessagePackage(byte[] encryptedPackage)
throws IOException, ASAPException {
-
ByteArrayInputStream bais = new ByteArrayInputStream(encryptedPackage);
return ASAPCryptoAlgorithms.parseEncryptedMessagePackage(bais);
}
@@ -155,17 +177,21 @@ public static byte[] getEncryptedMessagePackageAsBytes(EncryptedMessagePackage e
}
/**
- *
- * @param unencryptedBytes
- * @param encryptionKey
- * @return
+ * Encrypts the given data using the given symmetric key
+ * @param unencryptedBytes the data to encrypt
+ * @param encryptionKey the symmetric key for encryption. The key's algorithm must match the key store's symmetric
+ * encryption algorithm.
+ * @param keyStore the key store whose symmetric encryption algorithm is used
+ * @return the encrypted data
+ * @throws ASAPSecurityException if encryption fails, e.g. the algorithm is not available in the environment or the key
+ * is not suitable for the store's symmetric algorithm
*/
public static byte[] encryptSymmetric(byte[] unencryptedBytes, SecretKey encryptionKey,
- ASAPKeyStore ASAPKeyStore) throws ASAPSecurityException {
+ ASAPKeyStore keyStore) throws ASAPSecurityException {
try {
// encrypt message with symmetric key
- Cipher symmetricCipher = Cipher.getInstance(ASAPKeyStore.getSymmetricEncryptionAlgorithm());
+ Cipher symmetricCipher = Cipher.getInstance(keyStore.getSymmetricEncryptionAlgorithm());
symmetricCipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
/*
@@ -188,25 +214,42 @@ public static byte[] encryptSymmetric(byte[] unencryptedBytes, SecretKey encrypt
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
throw new ASAPSecurityException("symmetric encryption failed: "
- + ASAPKeyStore.getSymmetricEncryptionAlgorithm(), e);
+ + keyStore.getSymmetricEncryptionAlgorithm(), e);
}
}
+ /**
+ * Decrypts the given encrypted data symmetrically using the given key.
+ * @param encryptedContent data to decrypt
+ * @param symmetricKey key to use for decryption. The key's algorithm must match the key store's symmetric encryption
+ * algorithm.
+ * @param keyStore the key store whose symmetric algorithm is used for decryption
+ * @return the decrypted data
+ * @throws ASAPSecurityException if decryption fails, e.g. the algorithm is not available in the environment or the key
+ * is not suitable for the store's symmetric algorithm
+ */
public static byte[] decryptSymmetric(byte[] encryptedContent, SecretKey symmetricKey,
- ASAPKeyStore ASAPKeyStore) throws ASAPSecurityException {
-
+ ASAPKeyStore keyStore) throws ASAPSecurityException {
try {
- Cipher symmetricCipher = Cipher.getInstance(ASAPKeyStore.getSymmetricEncryptionAlgorithm());
+ Cipher symmetricCipher = Cipher.getInstance(keyStore.getSymmetricEncryptionAlgorithm());
symmetricCipher.init(Cipher.DECRYPT_MODE, symmetricKey);
return symmetricCipher.doFinal(encryptedContent);
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
throw new ASAPSecurityException("symmetric decryption failed: "
- + ASAPKeyStore.getSymmetricEncryptionAlgorithm(), e);
+ + keyStore.getSymmetricEncryptionAlgorithm(), e);
}
}
+ /**
+ * Decrypts the given data asymmetrically using the private key of the given store's owner.
+ * @param encryptedBytes the data to encrypt
+ * @param ASAPKeyStore this device's key store
+ * @return the decrypted data
+ * @throws ASAPSecurityException if decryption fails, e.g. the key store's algorithm is not available in the current
+ * environment or the data was not encrypted with the key store owner's public key
+ */
public static byte[] decryptAsymmetric(byte[] encryptedBytes, ASAPKeyStore ASAPKeyStore)
throws ASAPSecurityException {
try {
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java
index 3301e7c..4e0079b 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java
@@ -7,7 +7,7 @@
import java.security.PublicKey;
/**
- * Defines basic methods we need to implement signing and verification and to get information how to encrypt
+ * Defines basic methods and constants necessary for encryption/ decryption and signing/ verification.
*/
public interface ASAPCryptoParameterStorage {
String DEFAULT_ASYMMETRIC_ENCRYPTION_ALGORITHM = "RSA/ECB/PKCS1Padding";
@@ -18,9 +18,10 @@ public interface ASAPCryptoParameterStorage {
String DEFAULT_ASYMMETRIC_SIGNATURE_ALGORITHM = "SHA256withRSA";
/**
- *
- * @return private key of local device - for signing
- * @throws ASAPSecurityException
+ * Returns this device's private key, generating a key pair if none is available yet.
+ * @return the private key
+ * @throws ASAPSecurityException if no key is available and key generation fails
+ * @see ASAPKeyStore#generateKeyPair()
*/
PrivateKey getPrivateKey() throws ASAPSecurityException;
@@ -28,8 +29,10 @@ public interface ASAPCryptoParameterStorage {
// PrivateKey getPrivateKey(CharSequence subjectID) throws ASAPSecurityException;
/**
- * @return public key of local device - for signing
- * @throws ASAPSecurityException
+ * Returns this device's public key, generating a key pair if none is available yet.
+ * @return the public key
+ * @throws ASAPSecurityException if no key is available and key generation fails
+ * @see ASAPKeyStore#generateKeyPair()
*/
PublicKey getPublicKey() throws ASAPSecurityException;
@@ -39,6 +42,11 @@ public interface ASAPCryptoParameterStorage {
String getAsymmetricSigningAlgorithm();
+ /**
+ * Generates a symmetric key using this store's default symmetric encryption algorithm
+ * @return the symmetric key
+ * @throws ASAPSecurityException if the default encryption algorithm is not available in the current environment
+ */
SecretKey generateSymmetricKey() throws ASAPSecurityException;
String getSymmetricEncryptionAlgorithm();
diff --git a/src/main/java/net/sharksystem/asap/crypto/package-info.java b/src/main/java/net/sharksystem/asap/crypto/package-info.java
new file mode 100644
index 0000000..9ca4ded
--- /dev/null
+++ b/src/main/java/net/sharksystem/asap/crypto/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Interfaces and classes for managing and using cryptographic keys
+ */
+package net.sharksystem.asap.crypto;
\ No newline at end of file
From fbbdb87b9df18eabd45a277f9a5c6cad783b97ec Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sun, 11 Oct 2026 15:37:00 +0200
Subject: [PATCH 5/7] Complete javadoc for ASAPCryptoAlgorithms
---
.../asap/crypto/ASAPCryptoAlgorithms.java | 102 +++++++++++++-----
1 file changed, 76 insertions(+), 26 deletions(-)
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
index e050f4e..57cbe40 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
@@ -77,6 +77,12 @@ public static byte[] produceEncryptedMessagePackage(byte[] unencryptedBytes, Cha
return baos.toByteArray();
}
+ /**
+ * Constructs a SecretKey from the given encoded key with the given store's symmetric encryption algorithm.
+ * @param encodedSymmetricKey key material
+ * @param ASAPKeyStore key store to use
+ * @return the symmetric key
+ */
public static SecretKey createSymmetricKey(byte[] encodedSymmetricKey,
ASAPKeyStore ASAPKeyStore) {
return new SecretKeySpec(encodedSymmetricKey, ASAPKeyStore.getSymmetricKeyType());
@@ -140,12 +146,26 @@ public interface EncryptedMessagePackage {
byte[] getEncryptedContent();
}
+ /**
+ * Constructs an EncryptedMessagePackage from the given data.
+ * @param encryptedPackage the data representing the package
+ * @return the parsed package
+ * @throws IOException if an I/O error occurs
+ * @throws ASAPException if the end of the stream is reached
+ */
public static EncryptedMessagePackage parseEncryptedMessagePackage(byte[] encryptedPackage)
throws IOException, ASAPException {
ByteArrayInputStream bais = new ByteArrayInputStream(encryptedPackage);
return ASAPCryptoAlgorithms.parseEncryptedMessagePackage(bais);
}
+ /**
+ * Constructs an EncryptedMessagePackage by reading data from the given input stream.
+ * @param is the stream to read from
+ * @return the parsed package
+ * @throws IOException if an I/O error occurs
+ * @throws ASAPException if the end of the stream is reached
+ */
public static EncryptedMessagePackage parseEncryptedMessagePackage(InputStream is) throws IOException, ASAPException {
String recipient = ASAPSerialization.readCharSequenceParameter(is);
byte[] encryptedSymmetricKey = ASAPSerialization.readByteArray(is);
@@ -161,15 +181,27 @@ public static EncryptedMessagePackage parseEncryptedMessagePackage(InputStream i
};
}
+ /**
+ * Writes the given EncryptedMessagePackage to the given output stream.
+ * @param encryptedPackage the package to write
+ * @param os the stream to write to
+ * @throws IOException if an I/O error occurs
+ */
public static void writeEncryptedMessagePackage(EncryptedMessagePackage encryptedPackage, OutputStream os)
- throws IOException, ASAPException {
+ throws IOException {
ASAPSerialization.writeCharSequenceParameter(encryptedPackage.getReceiver(), os);
ASAPSerialization.writeByteArray(encryptedPackage.getEncryptedSymmetricKey(), os);
ASAPSerialization.writeByteArray(encryptedPackage.getEncryptedContent(), os);
}
+ /**
+ * Returns a byte representation of the given EncryptedMessagePackage.
+ * @param encryptedPackage the package to serialize
+ * @return the serialized package
+ * @throws IOException if an I/O error occurs
+ */
public static byte[] getEncryptedMessagePackageAsBytes(EncryptedMessagePackage encryptedPackage)
- throws IOException, ASAPException {
+ throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeEncryptedMessagePackage(encryptedPackage, baos);
@@ -245,62 +277,80 @@ public static byte[] decryptSymmetric(byte[] encryptedContent, SecretKey symmetr
/**
* Decrypts the given data asymmetrically using the private key of the given store's owner.
* @param encryptedBytes the data to encrypt
- * @param ASAPKeyStore this device's key store
+ * @param keyStore this device's key store
* @return the decrypted data
* @throws ASAPSecurityException if decryption fails, e.g. the key store's algorithm is not available in the current
* environment or the data was not encrypted with the key store owner's public key
*/
- public static byte[] decryptAsymmetric(byte[] encryptedBytes, ASAPKeyStore ASAPKeyStore)
+ public static byte[] decryptAsymmetric(byte[] encryptedBytes, ASAPKeyStore keyStore)
throws ASAPSecurityException {
try {
- Cipher cipher = Cipher.getInstance(ASAPKeyStore.getAsymmetricEncryptionAlgorithm());
- cipher.init(Cipher.DECRYPT_MODE, ASAPKeyStore.getPrivateKey());
+ Cipher cipher = Cipher.getInstance(keyStore.getAsymmetricEncryptionAlgorithm());
+ cipher.init(Cipher.DECRYPT_MODE, keyStore.getPrivateKey());
return cipher.doFinal(encryptedBytes);
} catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException
| IllegalBlockSizeException | BadPaddingException e) {
e.printStackTrace();
throw new ASAPSecurityException("asymmetric decryption failed: "
- + ASAPKeyStore.getAsymmetricEncryptionAlgorithm(), e);
+ + keyStore.getAsymmetricEncryptionAlgorithm(), e);
}
}
- public static byte[] sign(byte[] bytes2Sign, ASAPKeyStore ASAPKeyStore)
+ /**
+ * Creates and returns a signature for the given byte data. The given key store's default hashing and encryption
+ * algorithms are used.
+ * @param bytes2Sign data to sign
+ * @param keyStore key store of this device, providing algorithms and the owner's private key
+ * @return the signature
+ * @throws ASAPSecurityException if signing fails, e.g. due to the key store's algorithm not being available in the
+ * environment or an invalid private key
+ */
+ public static byte[] sign(byte[] bytes2Sign, ASAPKeyStore keyStore)
throws ASAPSecurityException {
-
try {
- Signature signature = Signature.getInstance(ASAPKeyStore.getAsymmetricSigningAlgorithm());
- signature.initSign(ASAPKeyStore.getPrivateKey());
+ Signature signature = Signature.getInstance(keyStore.getAsymmetricSigningAlgorithm());
+ signature.initSign(keyStore.getPrivateKey());
signature.update(bytes2Sign);
return signature.sign();
} catch (InvalidKeyException | SignatureException | NoSuchAlgorithmException e) {
e.printStackTrace();
- throw new ASAPSecurityException("signing failed: " + ASAPKeyStore.getAsymmetricSigningAlgorithm(), e);
+ throw new ASAPSecurityException("signing failed: " + keyStore.getAsymmetricSigningAlgorithm(), e);
}
}
+ /**
+ * Verifies the given signature against the given message, using the sender's public key from the key store.
+ * @param signedData the message
+ * @param signatureBytes the signature
+ * @param sender the ID of the message's sender
+ * @param keyStore the key store of this device
+ * @return true if and only if the sender's public key is available and the signature is valid
+ * @throws ASAPSecurityException if verification fails, e.g. due to the key store's algorithm not being available in the
+ * environment or an invalid public key
+ */
public static boolean verify(byte[] signedData, byte[] signatureBytes, String sender,
- ASAPKeyStore ASAPKeyStore) throws ASAPSecurityException {
-
- PublicKey publicKey = ASAPKeyStore.getPublicKey(sender);
- if(publicKey == null) return false;
+ ASAPKeyStore keyStore) throws ASAPSecurityException {
+ PublicKey publicKey = keyStore.getPublicKey(sender);
+ if(publicKey == null) {
+ return false;
+ }
try {
- Signature signature = Signature.getInstance(ASAPKeyStore.getAsymmetricSigningAlgorithm());
- signature.initVerify(publicKey); // init with private key
- signature.update(signedData); // feed with signed data
- return signature.verify(signatureBytes); // check against signature
+ Signature signature = Signature.getInstance(keyStore.getAsymmetricSigningAlgorithm());
+ signature.initVerify(publicKey);
+ signature.update(signedData);
+ return signature.verify(signatureBytes);
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
e.printStackTrace();
- throw new ASAPSecurityException("verifying failed: " + ASAPKeyStore.getAsymmetricSigningAlgorithm(), e);
+ throw new ASAPSecurityException("verifying failed: " + keyStore.getAsymmetricSigningAlgorithm(), e);
}
}
/**
- * Produces a Base 64 fingerprint with SHA256.
- * This fingerprint is not necessarily identical to others.
- * It an ASAP standard, though.
- * @param publicKey
- * @return
+ * Computes a Base64 encoded SHA256 fingerprint of the given public key.
+ * @param publicKey the public key to encode
+ * @return the key's fingerprint
+ * @throws NoSuchAlgorithmException if SHA256 is not available
*/
public static String getFingerprint(PublicKey publicKey) throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
From 034f2f7519d8d49fc14617c1bff8dc320e8d1e60 Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sun, 11 Oct 2026 15:53:54 +0200
Subject: [PATCH 6/7] Add TODO
---
.../java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java | 2 ++
.../net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java | 2 +-
src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java | 2 --
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
index 57cbe40..d75620a 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoAlgorithms.java
@@ -133,6 +133,8 @@ public static boolean sameID(CharSequence peerA, CharSequence peerB) {
String peerAString = peerA.toString();
String peerBString = peerB.toString();
+ /* TODO: Equality seems to be case insensitive in this method, but not in other contexts,
+ such as getPublicKey(CharSequence subjectID) in InMemoASAPKeyStore, where the casing of a peerID does indeed matter. */
return peerAString.equalsIgnoreCase(peerBString);
}
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java
index 4e0079b..aabdaa2 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPCryptoParameterStorage.java
@@ -7,7 +7,7 @@
import java.security.PublicKey;
/**
- * Defines basic methods and constants necessary for encryption/ decryption and signing/ verification.
+ * Basic methods and constants necessary for encryption/ decryption and signing/ verification.
*/
public interface ASAPCryptoParameterStorage {
String DEFAULT_ASYMMETRIC_ENCRYPTION_ALGORITHM = "RSA/ECB/PKCS1Padding";
diff --git a/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java b/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java
index da5f5ad..7f025d9 100644
--- a/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java
+++ b/src/main/java/net/sharksystem/asap/crypto/ASAPKeyStore.java
@@ -1,10 +1,8 @@
package net.sharksystem.asap.crypto;
-import net.sharksystem.asap.ASAPException;
import net.sharksystem.asap.ASAPSecurityException;
import net.sharksystem.fs.ExtraData;
-import java.io.IOException;
import java.security.PublicKey;
/**
From c4e1e3fee9e175c019d48a6e3f47dd2b375ac3dd Mon Sep 17 00:00:00 2001
From: InimaJin <168074928+InimaJin@users.noreply.github.com>
Date: Sun, 11 Oct 2026 15:58:48 +0200
Subject: [PATCH 7/7] create fs package-info
---
src/main/java/net/sharksystem/fs/package-info.java | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 src/main/java/net/sharksystem/fs/package-info.java
diff --git a/src/main/java/net/sharksystem/fs/package-info.java b/src/main/java/net/sharksystem/fs/package-info.java
new file mode 100644
index 0000000..0397dd4
--- /dev/null
+++ b/src/main/java/net/sharksystem/fs/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Interfaces and classes for interacting with the file system.
+ */
+package net.sharksystem.fs;
\ No newline at end of file