Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ecdh #234

Merged
merged 11 commits into from
May 28, 2024
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[![Build Status](https://travis-ci.com/adorsys/datasafe.svg?branch=develop)](https://travis-ci.com/adorsys/datasafe)
[![codecov](https://codecov.io/gh/adorsys/datasafe/branch/develop/graph/badge.svg)](https://codecov.io/gh/adorsys/datasafe)
[![Maintainability](https://api.codeclimate.com/v1/badges/06ae7d4cafc3012cee85/maintainability)](https://codeclimate.com/github/adorsys/datasafe/maintainability)
[![Maintainability](https://codeclimate.com/github/adorsys/datasafe.png)](https://codeclimate.com/github/adorsys/datasafe/maintainability)

# Secure, Encrypted and Versioned Data Storage Library

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import de.adorsys.datasafe.types.api.actions.ListRequest;
import de.adorsys.datasafe.types.api.actions.ReadRequest;
import de.adorsys.datasafe.types.api.actions.RemoveRequest;
import de.adorsys.datasafe.types.api.actions.WriteInboxRequest;
import de.adorsys.datasafe.types.api.actions.WriteRequest;
import de.adorsys.datasafe.types.api.resource.AbsoluteLocation;
import de.adorsys.datasafe.types.api.resource.BasePrivateResource;
Expand Down Expand Up @@ -117,9 +118,9 @@ protected void writeDataToPrivate(UserIDAuth auth, String path, String data) {
}

@SneakyThrows
protected void writeDataToInbox(UserIDAuth auth, String path, String data) {
protected void writeDataToInbox(UserIDAuth owner, UserIDAuth auth, String path, String data) {
try (OutputStream stream = writeToInbox.write(
WriteRequest.forDefaultPublic(Collections.singleton(auth.getUserID()), path)
WriteInboxRequest.forDefaultPublic(owner, Collections.singleton(auth.getUserID()), path)
)) {

stream.write(data.getBytes(UTF_8));
Expand Down Expand Up @@ -191,9 +192,9 @@ protected void registerJohnAndJane() {
}

@SneakyThrows
protected void sendToInbox(UserID to, String filename, String data) {
protected void sendToInbox(UserIDAuth from, UserID to, String filename, String data) {
try (OutputStream stream = writeToInbox.write(
WriteRequest.forDefaultPublic(Collections.singleton(to), "./" + filename)
WriteInboxRequest.forDefaultPublic(from, Collections.singleton(to), "./" + filename)
)) {
stream.write(data.getBytes());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.adorsys.datasafe.types.api.actions.ListRequest;
import de.adorsys.datasafe.types.api.actions.ReadRequest;
import de.adorsys.datasafe.types.api.actions.RemoveRequest;
import de.adorsys.datasafe.types.api.actions.WriteInboxRequest;
import de.adorsys.datasafe.types.api.actions.WriteRequest;
import de.adorsys.datasafe.types.api.global.Version;
import de.adorsys.datasafe.types.api.resource.AbsoluteLocation;
Expand Down Expand Up @@ -194,12 +195,15 @@ void testUserIsRemovedWithFiles(WithStorageProvider.StorageDescriptor descriptor
void testMultipleRecipientsSharing(WithStorageProvider.StorageDescriptor descriptor) {
init(descriptor);

UserIDAuth owner = registerUser("owner");

UserIDAuth john = registerUser("john");
UserIDAuth jane = registerUser("jane");
UserIDAuth jamie = registerUser("jamie");

String multiShareFile = "multishare.txt";
try (OutputStream os = writeToInbox.write(WriteRequest.forDefaultPublic(
try (OutputStream os = writeToInbox.write(WriteInboxRequest.forDefaultPublic(
owner,
ImmutableSet.of(john.getUserID(), jane.getUserID(), jamie.getUserID()),
multiShareFile))
) {
Expand All @@ -217,14 +221,17 @@ void testMultipleRecipientsSharing(WithStorageProvider.StorageDescriptor descrip
void testMultipleRecipientsSharingLargeChunk(WithStorageProvider.StorageDescriptor descriptor) {
init(descriptor);

UserIDAuth owner = registerUser("owner");

UserIDAuth john = registerUser("john");
UserIDAuth jane = registerUser("jane");
UserIDAuth jamie = registerUser("jamie");

String multiShareFile = "multishare.txt";
byte[] bytes = new byte[LARGE_SIZE];
ThreadLocalRandom.current().nextBytes(bytes);
try (OutputStream os = writeToInbox.write(WriteRequest.forDefaultPublic(
try (OutputStream os = writeToInbox.write(WriteInboxRequest.forDefaultPublic(
owner,
ImmutableSet.of(john.getUserID(), jane.getUserID(), jamie.getUserID()),
multiShareFile))
) {
Expand Down Expand Up @@ -253,7 +260,7 @@ void testWriteToPrivateListPrivateReadPrivateAndSendToAndReadFromInbox(

String privateContentJane = readPrivateUsingPrivateKey(jane, privateJane.getResource().asPrivate());

sendToInbox(john.getUserID(), SHARED_FILE_PATH, privateContentJane);
sendToInbox(jane, john.getUserID(), SHARED_FILE_PATH, privateContentJane);

AbsoluteLocation<ResolvedResource> inboxJohn = getFirstFileInInbox(john);

Expand Down Expand Up @@ -308,9 +315,9 @@ void listingInboxValidation(WithStorageProvider.StorageDescriptor descriptor) {

registerJohnAndJane();

writeDataToInbox(jane, "root.file", MESSAGE_ONE);
writeDataToInbox(jane, "level1/file", MESSAGE_ONE);
writeDataToInbox(jane, "level1/level2/file", MESSAGE_ONE);
writeDataToInbox(john, jane, "root.file", MESSAGE_ONE);
writeDataToInbox(john, jane, "level1/file", MESSAGE_ONE);
writeDataToInbox(john, jane, "level1/level2/file", MESSAGE_ONE);

assertInboxSpaceList(jane, "", "root.file", "level1/file", "level1/level2/file");
assertInboxSpaceList(jane, "./", "root.file", "level1/file", "level1/level2/file");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ void listingPrivatePathWithUnicode(WithStorageProvider.StorageDescriptor descrip
void readInboxContentWithUnicodeUsingUnicodePath(WithStorageProvider.StorageDescriptor descriptor) {
init(descriptor);

john = registerUser("john");
jane = registerUser("jane");


String unicodeMessage = "привет мир!";
writeDataToInbox(jane, " привет/prüfungsdokument=/файл:&? с пробелом.док", unicodeMessage);
writeDataToInbox(john, jane, " привет/prüfungsdokument=/файл:&? с пробелом.док", unicodeMessage);

String inboxContentJane = readInboxUsingPrivateKey(
jane,
Expand All @@ -107,9 +108,9 @@ void listingInboxPathWithUnicode(WithStorageProvider.StorageDescriptor descripto

registerJohnAndJane();

writeDataToInbox(jane, "prüfungsdokument.doc+doc", MESSAGE_ONE);
writeDataToInbox(jane, "уровень1/?файл+doc", MESSAGE_ONE);
writeDataToInbox(jane, "уровень1/уровень 2=+/&файл пробел+плюс", MESSAGE_ONE);
writeDataToInbox(john, jane, "prüfungsdokument.doc+doc", MESSAGE_ONE);
writeDataToInbox(john, jane, "уровень1/?файл+doc", MESSAGE_ONE);
writeDataToInbox(john, jane, "уровень1/уровень 2=+/&файл пробел+плюс", MESSAGE_ONE);

assertInboxSpaceList(jane, "", "prüfungsdokument.doc+doc", "уровень1/?файл+doc", "уровень1/уровень 2=+/&файл пробел+плюс");
assertInboxSpaceList(jane, "./", "prüfungsdokument.doc+doc", "уровень1/?файл+doc", "уровень1/уровень 2=+/&файл пробел+плюс");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import de.adorsys.datasafe.encrypiton.api.types.UserIDAuth;
import de.adorsys.datasafe.teststorage.WithStorageProvider;
import de.adorsys.datasafe.types.api.actions.ReadRequest;
import de.adorsys.datasafe.types.api.actions.WriteRequest;
import de.adorsys.datasafe.types.api.actions.WriteInboxRequest;
import de.adorsys.datasafe.types.api.resource.AbsoluteLocation;
import de.adorsys.datasafe.types.api.resource.ResolvedResource;
import de.adorsys.datasafe.types.api.resource.Uri;
Expand Down Expand Up @@ -60,12 +60,14 @@ void testUserIsRemovedWithFiles(WithStorageProvider.StorageDescriptor descriptor
void testMultipleRecipientsSharing(WithStorageProvider.StorageDescriptor descriptor) {
init(descriptor);

UserIDAuth sender = registerUser("sender");

UserIDAuth john = registerUser("john");
UserIDAuth jane = registerUser("jane");
UserIDAuth jamie = registerUser("jamie");

String multiShareFile = "multishare.txt";
multishareFiles(john, jane, jamie, multiShareFile);
multishareFiles(sender, john, jane, jamie, multiShareFile);

Stream.of(john, jane, jamie).forEach(
it -> checkUpdatedCredsWorkAndOldDont(
Expand Down Expand Up @@ -102,7 +104,7 @@ void testWriteToPrivateListPrivateReadPrivateAndSendToAndReadFromInbox(

String privateContentJane = readPrivateUsingPrivateKey(jane, privateJane.getResource().asPrivate());

sendToInbox(john.getUserID(), SHARED_FILE_PATH, privateContentJane);
sendToInbox(jane, john.getUserID(), SHARED_FILE_PATH, privateContentJane);

AbsoluteLocation<ResolvedResource> inboxJohn = getFirstFileInInbox(john);

Expand Down Expand Up @@ -188,8 +190,9 @@ void listingValidation(WithStorageProvider.StorageDescriptor descriptor) {
}

@SneakyThrows
private void multishareFiles(UserIDAuth userOne, UserIDAuth userTwo, UserIDAuth userThree, String multiShareFile) {
try (OutputStream os = writeToInbox.write(WriteRequest.forDefaultPublic(
private void multishareFiles(UserIDAuth sender, UserIDAuth userOne, UserIDAuth userTwo, UserIDAuth userThree, String multiShareFile) {
try (OutputStream os = writeToInbox.write(WriteInboxRequest.forDefaultPublic(
sender,
ImmutableSet.of(userOne.getUserID(), userTwo.getUserID(), userThree.getUserID()),
multiShareFile))
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import de.adorsys.datasafe.business.impl.service.DefaultDatasafeServices;
import de.adorsys.datasafe.types.api.actions.ListRequest;
import de.adorsys.datasafe.types.api.actions.ReadRequest;
import de.adorsys.datasafe.types.api.actions.WriteInboxRequest;
import de.adorsys.datasafe.types.api.actions.WriteRequest;
import de.adorsys.datasafe.types.api.resource.AbsoluteLocation;
import de.adorsys.datasafe.types.api.resource.ResolvedResource;
Expand Down Expand Up @@ -82,7 +83,7 @@ void testPrivateDocumentContentTamperResistance() {
@SneakyThrows
void testInboxDocumentContentTamperResistance() {
try (OutputStream os = writeToInbox.write(
WriteRequest.forDefaultPublic(Collections.singleton(john.getUserID()), FILENAME))
WriteInboxRequest.forDefaultPublic(jane, Collections.singleton(john.getUserID()), FILENAME))
) {
os.write(FILE_TEXT.getBytes(StandardCharsets.UTF_8));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.google.common.io.ByteStreams;
import com.google.common.io.MoreFiles;
import de.adorsys.datasafe.encrypiton.api.types.UserID;
import de.adorsys.datasafe.types.api.actions.WriteRequest;
import de.adorsys.datasafe.types.api.actions.WriteInboxRequest;
import lombok.SneakyThrows;
import picocli.CommandLine;

Expand Down Expand Up @@ -41,7 +41,8 @@ public class Share implements Runnable {
public void run() {
try (OutputStream os = inbox.getCli().datasafe().inboxService()
.write(
WriteRequest.forDefaultPublic(
WriteInboxRequest.forDefaultPublic(
inbox.getCli().auth(),
recipients.stream().map(UserID::new).collect(Collectors.toSet()),
filename
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import de.adorsys.datasafe.types.api.types.ReadKeyPassword;

import java.security.Key;
import java.security.KeyPair;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -42,4 +43,6 @@ public interface DocumentKeyStoreOperations {
* @return Key aliases from keystore.
*/
Set<String> readAliases(UserIDAuth forUser);

KeyPair getKeyPair(UserIDAuth forUser);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import de.adorsys.datasafe.encrypiton.api.types.keystore.SecretKeyIDWithKey;

import java.security.Key;
import java.security.KeyPair;
import java.util.Map;
import java.util.Set;

Expand Down Expand Up @@ -45,4 +46,6 @@ public interface PrivateKeyService {
* {@code keyIds} that are missing - they are silently ignored and not returned in result.
*/
Map<String, Key> keysByIds(UserIDAuth forUser, Set<String> keyIds);

KeyPair getKeyPair(UserIDAuth forUser);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import javax.crypto.SecretKey;
import javax.inject.Inject;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import java.util.Collection;
Expand Down Expand Up @@ -100,6 +101,11 @@ public Map<String, Key> keysByIds(UserIDAuth forUser, Set<String> keyIds) {
);
}

@Override
public KeyPair getKeyPair(UserIDAuth forUser) {
return keyStoreOper.getKeyPair(forUser);
}

protected SecretKeyIDWithKey keyByPrefix(UserIDAuth forUser, String prefix) {
return keyByPrefix(
forUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@
import javax.inject.Inject;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -103,6 +105,16 @@ public void updateReadKeyPassword(UserIDAuth forUser, ReadKeyPassword newPasswor
genericOper.updateReadKeyPassword(keyStore(forUser), location, forUser, newPassword);
}

@Override
@SneakyThrows
public KeyPair getKeyPair(UserIDAuth forUser) {
KeyStore keyStore = keyStore(forUser);
KeyStoreAuth auth = keystoreAuth(forUser, forUser.getReadKeyPassword());
List<PublicKeyIDWithPublicKey> publicKeys = keyStoreService.getPublicKeys(new KeyStoreAccess(keyStore, auth));
Key key = genericOper.getKey(() -> keyStore(forUser), forUser, publicKeys.get(0).getKeyID().getValue());
return new KeyPair(publicKeys.get(0).getPublicKey(), (PrivateKey) key);
}

private AbsoluteLocation<PrivateResource> keystoreLocationWithAccess(UserIDAuth forUser) {
return this.access.privateAccessFor(
forUser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
Expand All @@ -25,7 +26,8 @@ public interface CMSEncryptionService {
* @return Encrypted stream that wraps {@code dataContentStream}
* @apiNote Closes underlying stream when result is closed
*/
OutputStream buildEncryptionOutputStream(OutputStream dataContentStream, Set<PublicKeyIDWithPublicKey> publicKeys);
OutputStream buildEncryptionOutputStream(OutputStream dataContentStream, Set<PublicKeyIDWithPublicKey> publicKeys,
KeyPair senderKeyPair);

/**
* Builds symmetrically encrypted stream.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.adorsys.datasafe.types.api.resource.WithCallback;

import java.io.OutputStream;
import java.security.KeyPair;
import java.util.Map;

/**
Expand All @@ -22,7 +23,7 @@ public interface EncryptedDocumentWriteService {
* @param recipientsWithInbox Map of (recipient public key - recipients' inbox) of users with whom to share file.
* @return Sink where you can send unencrypted data that will be encrypted and stored
*/
OutputStream write(Map<PublicKeyIDWithPublicKey, AbsoluteLocation> recipientsWithInbox);
OutputStream write(Map<PublicKeyIDWithPublicKey, AbsoluteLocation> recipientsWithInbox, KeyPair senderKeyPair);

/**
* Writes and encrypts data using symmetric cryptography.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,32 @@ public static class SecretKeyCreationCfg {
public static class EncryptingKeyCreationCfg {

@Builder.Default
private final String algo = "RSA";
private final String algo = "ECDH";

@Builder.Default
private final int size = 2048;
private final int size = 256;
francis-pouatcha marked this conversation as resolved.
Show resolved Hide resolved

@Builder.Default
private final String sigAlgo = "SHA256withECDSA";
francis-pouatcha marked this conversation as resolved.
Show resolved Hide resolved

@Builder.Default
private final String sigAlgo = "SHA256withRSA";
private final String curve = "secp256r1";
}

@Getter
@Builder
public static class SigningKeyCreationCfg {

@Builder.Default
private final String algo = "RSA";
private final String algo = "ECDH";

@Builder.Default
private final int size = 256;

@Builder.Default
private final int size = 2048;
private final String sigAlgo = "SHA256withECDSA";

@Builder.Default
private final String sigAlgo = "SHA256withRSA";
private final String curve = "secp256r1";
}
}
Loading
Loading