Skip to content

Commit 4f1bcc5

Browse files
authored
feat: adding encryption and serialization through input/output stream (#5734)
* feat: wip to add streamed snapshot encryption and serilization Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * feat: added apis to encrypt/decrypt and marshal/unmarshal with streams Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: copyright header Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: missing copyright header Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: fixed some comments Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: fixed test and adding suggestions Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: copyright header Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: wrong since in javadoc Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * feat: added suggestions Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: missing copyrights Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: copyrights check failure Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * feat: added suggestions Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: added charset to getBytes Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: test missing dependency Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: fixed javadoc for CryptoService class * feat: improved json marshalling Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * fix: copyrights Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> * feat: updated payload to support streams only Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com> --------- Signed-off-by: SimoneFiorani <simone.fiorani@abinsula.com>
1 parent 3bc9b89 commit 4f1bcc5

37 files changed

Lines changed: 1059 additions & 402 deletions

File tree

.github/copyright-config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,4 @@ template_xml: |2
2929
# Ignore specific files and paths. The syntax and semantics are the same as in the .gitignore file.
3030
ignore:
3131
- target-platform/
32+
- kura/test/org.eclipse.kura.core.configuration.test/src/test/resources/

kura/org.eclipse.kura.api/META-INF/MANIFEST.MF

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ Export-Package: org.eclipse.kura;version="1.7.0",
3636
org.eclipse.kura.container.orchestration;version="1.3.0",
3737
org.eclipse.kura.container.orchestration.listener;version="1.0.0",
3838
org.eclipse.kura.container.signature;version="1.0.0",
39-
org.eclipse.kura.crypto;version="1.3.0",
39+
org.eclipse.kura.crypto;version="1.4.0",
4040
org.eclipse.kura.data;version="1.1.2",
4141
org.eclipse.kura.data.listener;version="1.0.1",
4242
org.eclipse.kura.data.transport.listener;version="1.0.1",
@@ -52,7 +52,7 @@ Export-Package: org.eclipse.kura;version="1.7.0",
5252
org.eclipse.kura.linux.udev;version="1.0.1",
5353
org.eclipse.kura.log;version="1.1.0",
5454
org.eclipse.kura.log.listener;version="1.0.0",
55-
org.eclipse.kura.marshalling;version="1.0.0",
55+
org.eclipse.kura.marshalling;version="1.1.0",
5656
org.eclipse.kura.message;version="1.5.0",
5757
org.eclipse.kura.message.store;version="1.0.0",
5858
org.eclipse.kura.message.store.provider;version="1.0.0",

kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/crypto/CryptoService.java

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
/*******************************************************************************
2-
* Copyright (c) 2011, 2020 Eurotech and/or its affiliates and others
3-
*
2+
* Copyright (c) 2011, 2025 Eurotech and/or its affiliates and others
3+
*
44
* This program and the accompanying materials are made
55
* available under the terms of the Eclipse Public License 2.0
66
* which is available at https://www.eclipse.org/legal/epl-2.0/
7-
*
7+
*
88
* SPDX-License-Identifier: EPL-2.0
9-
*
9+
*
1010
* Contributors:
1111
* Eurotech
1212
******************************************************************************/
1313
package org.eclipse.kura.crypto;
1414

1515
import java.io.IOException;
16+
import java.io.InputStream;
17+
import java.io.OutputStream;
1618
import java.io.UnsupportedEncodingException;
1719
import java.security.InvalidKeyException;
1820
import java.security.NoSuchAlgorithmException;
@@ -43,6 +45,30 @@ public interface CryptoService {
4345
*/
4446
public char[] encryptAes(char[] value) throws KuraException;
4547

48+
/**
49+
* Returns an OutputStream that encrypts provided data using AES in the same way as the encryptAes(char[]) method,
50+
* and then writes it to the supplied OutputStream lazily. *
51+
*
52+
* @param streamToEncrypt
53+
* The OutputStream on which the encrypted data will be written.
54+
* @return The OutputStream able to encrypt data.
55+
* @throws KuraException
56+
* @since 3.0
57+
*/
58+
public OutputStream aesEncryptingStream(OutputStream destination) throws KuraException;
59+
60+
/**
61+
* Returns an InputStream that decrypts data obtained from the supplied stream using AES in the same way as the
62+
* decryptAes(char[]) method.
63+
*
64+
* @param streamToDecrypt
65+
* The InputStream to read the encrypted data from.
66+
* @return InputStream able to decrypt data.
67+
* @throws KuraException
68+
* @since 3.0
69+
*/
70+
public InputStream aesDecryptingStream(InputStream source) throws KuraException;
71+
4672
/**
4773
* Returns a char array based on the provided encrypted value.
4874
*

kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/Marshaller.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others
3-
*
2+
* Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others
3+
*
44
* This program and the accompanying materials are made
55
* available under the terms of the Eclipse Public License 2.0
66
* which is available at https://www.eclipse.org/legal/epl-2.0/
7-
*
7+
*
88
* SPDX-License-Identifier: EPL-2.0
9-
*
9+
*
1010
* Contributors:
1111
* Eurotech
1212
******************************************************************************/
1313
package org.eclipse.kura.marshalling;
1414

15+
import java.io.OutputStream;
16+
1517
import org.eclipse.kura.KuraException;
1618
import org.osgi.annotation.versioning.ProviderType;
1719

@@ -34,4 +36,16 @@ public interface Marshaller {
3436
* when the marshalling operation fails.
3537
*/
3638
public String marshal(Object object) throws KuraException;
39+
40+
/**
41+
* Serialises the provided {@link Object} and writes the result to the supplied {@link OutputStream}
42+
*
43+
* @param out
44+
* the {@link OutputStream} on which the data will be written
45+
* @param object
46+
* the {@link Object} that will be marshalled.
47+
* @throws KuraException
48+
* @since 3.0
49+
*/
50+
public void marshal(final OutputStream out, Object object) throws KuraException;
3751
}

kura/org.eclipse.kura.api/src/main/java/org/eclipse/kura/marshalling/Unmarshaller.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017, 2020 Eurotech and/or its affiliates and others
3-
*
2+
* Copyright (c) 2017, 2025 Eurotech and/or its affiliates and others
3+
*
44
* This program and the accompanying materials are made
55
* available under the terms of the Eclipse Public License 2.0
66
* which is available at https://www.eclipse.org/legal/epl-2.0/
7-
*
7+
*
88
* SPDX-License-Identifier: EPL-2.0
9-
*
9+
*
1010
* Contributors:
1111
* Eurotech
1212
******************************************************************************/
1313
package org.eclipse.kura.marshalling;
1414

15+
import java.io.InputStream;
16+
1517
import org.eclipse.kura.KuraException;
1618
import org.osgi.annotation.versioning.ProviderType;
1719

@@ -36,4 +38,18 @@ public interface Unmarshaller {
3638
* when the unmarshaling operation fails.
3739
*/
3840
public <T> T unmarshal(String string, Class<T> clazz) throws KuraException;
41+
42+
/**
43+
* Deserialises an object of the specified type from the provided {@link InputStream}
44+
*
45+
* @param in
46+
* the input stream
47+
* @param clazz
48+
* the class representing the type of object expected for the result
49+
* @return an object that is constructed from the passed string
50+
* @throws KuraException
51+
* when the unmarshaling operation fails.
52+
* @since 3.0
53+
*/
54+
public <T> T unmarshal(InputStream in, Class<T> clazz) throws KuraException;
3955
}

kura/org.eclipse.kura.core.configuration/META-INF/MANIFEST.MF

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ Import-Package: javax.crypto,
2323
org.eclipse.kura.configuration;version="[1.2,1.3)",
2424
org.eclipse.kura.configuration.metatype;version="[1.1,2.0)",
2525
org.eclipse.kura.core.util;version="[2.0,3.0)",
26-
org.eclipse.kura.crypto;version="[1.0,2.0)",
27-
org.eclipse.kura.marshalling;version="[1.0,2.0)",
26+
org.eclipse.kura.crypto;version="[1.4,2.0)",
27+
org.eclipse.kura.marshalling;version="[1.1,2.0)",
2828
org.eclipse.kura.message;version="[1.0,2.0)",
2929
org.eclipse.kura.system;version="[1.0,2.0)",
3030
org.eclipse.kura.util.service;version="[1.0,2.0)",
@@ -35,8 +35,8 @@ Import-Package: javax.crypto,
3535
org.osgi.service.component;version="1.2.0",
3636
org.osgi.service.component.runtime;version="1.3.0",
3737
org.osgi.service.component.runtime.dto;version="1.3.0",
38-
org.osgi.service.metatype;version="1.2.0",
3938
org.osgi.service.event;version="1.3.0",
39+
org.osgi.service.metatype;version="1.2.0",
4040
org.osgi.util.tracker;version="[1.5.0,2.0.0)",
4141
org.slf4j;version="1.6.4",
4242
org.w3c.dom,

kura/org.eclipse.kura.core.configuration/src/main/java/org/eclipse/kura/core/configuration/ConfigurationServiceImpl.java

Lines changed: 43 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717
import static java.util.Objects.requireNonNull;
1818

1919
import java.io.File;
20+
import java.io.FileInputStream;
21+
import java.io.FileNotFoundException;
2022
import java.io.FileOutputStream;
2123
import java.io.FileReader;
2224
import java.io.IOException;
23-
import java.io.OutputStreamWriter;
24-
import java.nio.charset.StandardCharsets;
25+
import java.io.InputStream;
26+
import java.io.OutputStream;
2527
import java.nio.file.Files;
2628
import java.nio.file.Path;
29+
import java.nio.file.StandardCopyOption;
2730
import java.util.ArrayList;
2831
import java.util.Arrays;
2932
import java.util.Collection;
@@ -261,7 +264,7 @@ protected void removeSelfConfiguringComponent(final ServiceReference<SelfConfigu
261264

262265
}
263266

264-
protected void deactivate(ComponentContext componentContext) {
267+
protected void deactivate() {
265268
logger.info("deactivate...");
266269

267270
if (this.bundleTracker != null) {
@@ -959,7 +962,7 @@ private void encryptPlainSnapshots() throws KuraException, IOException {
959962
throw new KuraException(KuraErrorCode.CONFIGURATION_ERROR, snapshot);
960963
}
961964

962-
final XmlComponentConfigurations xmlConfigs = unmarshal(readFully(fSnapshot),
965+
final XmlComponentConfigurations xmlConfigs = unmarshal(new FileInputStream(fSnapshot),
963966
XmlComponentConfigurations.class);
964967

965968
ComponentUtil.encryptConfigs(xmlConfigs.getConfigurations(), this.cryptoService);
@@ -1006,28 +1009,44 @@ private void writeSnapshot(long sid, XmlComponentConfigurations conf) throws Kur
10061009
throw new KuraException(KuraErrorCode.CONFIGURATION_SNAPSHOT_NOT_FOUND);
10071010
}
10081011

1009-
// Marshall the configuration into an XML
1010-
String xmlResult;
1011-
xmlResult = marshal(conf);
1012-
if (xmlResult == null || xmlResult.trim().isEmpty()) {
1013-
throw new KuraException(KuraErrorCode.INVALID_PARAMETER, conf);
1012+
File tempSnapshotFile;
1013+
try {
1014+
tempSnapshotFile = File.createTempFile(fSnapshot.getName(), null, new File(fSnapshot.getParent()));
1015+
tempSnapshotFile.deleteOnExit();
1016+
} catch (IOException ex) {
1017+
throw new KuraIOException(ex);
10141018
}
10151019

1016-
// Encrypt the XML
1017-
char[] encryptedXML = this.cryptoService.encryptAes(xmlResult.toCharArray());
1020+
// Write the temporary snapshot
1021+
try (FileOutputStream fos = new FileOutputStream(tempSnapshotFile);
1022+
OutputStream encryptedStream = this.cryptoService.aesEncryptingStream(fos)) {
10181023

1019-
// Write the snapshot
1020-
try (FileOutputStream fos = new FileOutputStream(fSnapshot);
1021-
OutputStreamWriter osw = new OutputStreamWriter(fos, StandardCharsets.UTF_8);) {
10221024
logger.info("Writing snapshot - Saving {}...", fSnapshot.getAbsolutePath());
1023-
osw.append(new String(encryptedXML));
1024-
osw.flush();
1025+
1026+
marshal(encryptedStream, conf);
1027+
encryptedStream.flush();
10251028
fos.flush();
10261029
fos.getFD().sync();
1030+
10271031
logger.info("Writing snapshot - Saving {}... Done.", fSnapshot.getAbsolutePath());
10281032
} catch (IOException e) {
10291033
throw new KuraIOException(e);
10301034
}
1035+
1036+
try {
1037+
// Consolidate snapshot writing
1038+
Files.move(tempSnapshotFile.toPath(), fSnapshot.toPath(), StandardCopyOption.REPLACE_EXISTING,
1039+
StandardCopyOption.ATOMIC_MOVE);
1040+
1041+
} catch (IOException e) {
1042+
try {
1043+
Files.delete(tempSnapshotFile.toPath());
1044+
} catch (IOException e1) {
1045+
throw new KuraIOException(e1);
1046+
}
1047+
throw new KuraIOException(e);
1048+
}
1049+
10311050
}
10321051

10331052
private ComponentConfiguration getConfigurableComponentConfiguration(String pid) {
@@ -1309,25 +1328,18 @@ XmlComponentConfigurations loadEncryptedSnapshotFileContent(long snapshotID) thr
13091328
fSnapshot != null ? fSnapshot.getAbsolutePath() : "null");
13101329
}
13111330

1312-
final String rawSnapshot;
1331+
InputStream decryptedStream = null;
13131332
try {
1314-
rawSnapshot = readFully(fSnapshot);
1315-
} catch (IOException e) {
1333+
decryptedStream = this.cryptoService.aesDecryptingStream(new FileInputStream(fSnapshot));
1334+
} catch (FileNotFoundException e) {
13161335
logger.error("Error loading file from disk", e);
13171336
return null;
13181337
}
13191338

1320-
// File loaded, try to decrypt and unmarshall
1321-
char[] decryptAes = this.cryptoService.decryptAes(rawSnapshot.toCharArray());
1322-
if (decryptAes == null) {
1323-
throw new KuraException(KuraErrorCode.DECODER_ERROR, "snapshot");
1324-
}
1325-
String decryptedContent = new String(decryptAes);
1326-
13271339
XmlComponentConfigurations xmlConfigs = null;
13281340

13291341
try {
1330-
xmlConfigs = unmarshal(decryptedContent, XmlComponentConfigurations.class);
1342+
xmlConfigs = unmarshal(decryptedStream, XmlComponentConfigurations.class);
13311343
} catch (KuraException e) {
13321344
logger.warn("Error parsing xml", e);
13331345
}
@@ -1647,17 +1659,17 @@ public List<ComponentConfiguration> getServiceProviderOCDs(Class<?>... classes)
16471659
return getServiceProviderOCDs(classNames);
16481660
}
16491661

1650-
protected <T> T unmarshal(final String string, final Class<T> clazz) throws KuraException {
1662+
protected <T> T unmarshal(final InputStream input, final Class<T> clazz) throws KuraException {
16511663
try {
1652-
return requireNonNull(this.xmlUnmarshaller.unmarshal(string, clazz));
1664+
return requireNonNull(this.xmlUnmarshaller.unmarshal(input, clazz));
16531665
} catch (final Exception e) {
16541666
throw new KuraException(KuraErrorCode.DECODER_ERROR, "configuration", e);
16551667
}
16561668
}
16571669

1658-
protected String marshal(final Object object) throws KuraException {
1670+
protected void marshal(final OutputStream out, final Object object) throws KuraException {
16591671
try {
1660-
return requireNonNull(this.xmlMarshaller.marshal(object));
1672+
this.xmlMarshaller.marshal(out, object);
16611673
} catch (Exception e) {
16621674
throw new KuraException(KuraErrorCode.ENCODE_ERROR, "configuration", e);
16631675
}

kura/org.eclipse.kura.core.crypto/META-INF/MANIFEST.MF

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=17))"
88
Import-Package: javax.crypto,
99
javax.crypto.spec,
1010
org.eclipse.kura;version="[1.0,2.0)",
11-
org.eclipse.kura.crypto;version="[1.3,1.4)",
11+
org.eclipse.kura.crypto;version="[1.4,1.5)",
1212
org.eclipse.kura.security.keystore;version="[1.0,2.0)",
1313
org.eclipse.kura.system;version="[1.1,2.0)",
1414
org.slf4j;version="1.6.0"

0 commit comments

Comments
 (0)