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