Skip to content

Commit

Permalink
fixed dependency issues
Browse files Browse the repository at this point in the history
  • Loading branch information
Elwizzy12 committed Jul 29, 2024
2 parents b04a6b1 + 89da57d commit 25c20bf
Show file tree
Hide file tree
Showing 20 changed files with 220 additions and 72 deletions.
53 changes: 53 additions & 0 deletions SECURITY.WHITEPAPER.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,59 @@ CMS Encryption:
* [RSAES-PKCS1-v1_5](#RSAES-PKCS1-v1_5) - key derivation algorithm for shared files (use public key);
* [SHA256withRSA](#SHA256withRSA) - for public keys.

## ECC Update

With the latest release, Datasafe has transitioned from RSA to Elliptic Curve Cryptography (ECC) to enhance security and performance. This section details the new ECC implementation:

#### Encryption and Signing

- **Encryption Algorithm**: ECDH (Elliptic Curve Diffie-Hellman) with curve `secp256r1`.
- **Signing Algorithm**: SHA256withECDSA (Elliptic Curve Digital Signature Algorithm) with curve `secp256r1`.

#### Benefits of ECC

- **Security**: ECC offers stronger security per bit compared to RSA, making it more resistant to cryptographic attacks.
- **Performance**: ECC algorithms generally require less computational power and are faster.
- **Key Size**: ECC achieves comparable security to RSA with much smaller key sizes (256 bits for ECC vs. 2048 bits for RSA), resulting in reduced storage and transmission requirements.

#### Implementation Details
<details>
<summary>Dynamically choosing between RSA and ECC</summary>

```java
private RecipientInfoGenerator getRecipientInfoGenerator(PublicKeyIDWithPublicKey keyWithId, KeyPair senderKeyPair) {
if ("RSA".equals(keyWithId.getPublicKey().getAlgorithm())) {
return new JceKeyTransRecipientInfoGenerator(keyWithId.getKeyID().getValue().getBytes(), keyWithId.getPublicKey());
}
if (Set.of("ECDH", "EC").contains(keyWithId.getPublicKey().getAlgorithm())) {
return getJceKeyAgreeRecipientInfoGenerator(senderKeyPair, keyWithId);
}
return null;
}
```
in the updated implementation, the getRecipientInfoGenerator method dynamically chooses between RSA and ECC based on the algorithm associated with the public key. For ECC, it uses ECDH for encryption and SHA256withECDSA for signing.

</details>

## Release Notes

##### ECC Integration

#### Added
- **Elliptic Curve Cryptography (ECC)**:
- Implemented ECC for improved security and performance.
- Encryption Algorithm: ECDH (Elliptic Curve Diffie-Hellman) with curve `secp256r1`.
- Signing Algorithm: SHA256withECDSA (Elliptic Curve Digital Signature Algorithm) with curve `secp256r1`.

#### Changed
- **Encryption and Signing**:
- Transitioned from RSA to ECC, enhancing security and reducing key sizes.

#### Improved
- **Security**:
- ECC offers stronger security per bit compared to RSA.
- **Key Size Reduction**:
- ECC achieves comparable security to RSA with much smaller key sizes, reducing storage and transmission requirements.
## General information
Datasafe is a flexible encryption library. It uses different encryption algorithms. They can be
configured by client application. Under the hood Datasafe uses BouncyCastle library to perform encryption.
Expand Down
12 changes: 12 additions & 0 deletions datasafe-examples/datasafe-examples-multidfs/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
12 changes: 12 additions & 0 deletions datasafe-examples/datasafe-examples-versioned-s3/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@
<artifactId>testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
Expand Down
18 changes: 12 additions & 6 deletions datasafe-rest-impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
<description>Spring Boot DataSafe Application</description>

<properties>
<spring-boot.version>3.1.2</spring-boot.version>
<spring-boot.version>3.3.1</spring-boot.version>
<springfox-swagger.version>2.9.2</springfox-swagger.version>
<jjwt.version>0.12.4</jjwt.version>
<spring-restdocs.version>3.0.0</spring-restdocs.version>
<asciidoctor-maven-plugin.version>2.2.4</asciidoctor-maven-plugin.version>
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
<jakarta.validation-api.version>3.0.2</jakarta.validation-api.version>
<springdoc-openapi-starter-webmvc-ui.version>2.3.0</springdoc-openapi-starter-webmvc-ui.version>
<maven.compiler.parameters>true</maven.compiler.parameters>
</properties>

<dependencies>
Expand Down Expand Up @@ -82,12 +82,12 @@
<version>${spring-boot.version}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>${jakarta.validation-api.version}</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>${spring-boot.version}</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
Expand All @@ -103,6 +103,12 @@
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>${jjwt.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class DatasafeRestApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Slf4j
@Configuration
@RequiredArgsConstructor
public class MvcConfig extends WebMvcConfigurationSupport {
public class MvcConfig implements WebMvcConfigurer {

private final DatasafeProperties datasafeProperties;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
Expand All @@ -31,7 +32,7 @@ public class AuthenticateController {
private final AuthenticationManager authenticationManager;

@PostMapping(SecurityConstants.AUTH_LOGIN_URL)
public void authenticate(@RequestBody UserDTO credentialsDTO, HttpServletResponse response) {
public void authenticate(@RequestBody @Validated UserDTO credentialsDTO, HttpServletResponse response) {
String username = credentialsDTO.getUserName();
String password = credentialsDTO.getPassword();
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import de.adorsys.datasafe.types.api.resource.PrivateResource;
import de.adorsys.datasafe.types.api.resource.StorageIdentifier;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
Expand Down Expand Up @@ -49,11 +51,16 @@ public class DocumentController {
*/
@SneakyThrows
@GetMapping(value = "/document/{*path}", produces = APPLICATION_OCTET_STREAM_VALUE)
public void readDocument(@RequestHeader String user,
@RequestHeader String password,
public void readDocument(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@RequestHeader(defaultValue = StorageIdentifier.DEFAULT_ID) String storageId,
@PathVariable String path,
@PathVariable @NotBlank String path,
HttpServletResponse response) {
// Validate and sanitize path
if (path.contains("..")) {
throw new IllegalArgumentException("Invalid path");
}

UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
ReadRequest<UserIDAuth, PrivateResource> request =
ReadRequest.forPrivate(userIDAuth, new StorageIdentifier(storageId), path);
Expand All @@ -72,11 +79,16 @@ public void readDocument(@RequestHeader String user,
*/
@SneakyThrows
@PutMapping(value = "/document/{*path}", consumes = MULTIPART_FORM_DATA_VALUE)
public void writeDocument(@RequestHeader String user,
@RequestHeader String password,
public void writeDocument(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@RequestHeader(defaultValue = StorageIdentifier.DEFAULT_ID) String storageId,
@PathVariable String path,
@RequestParam("file") MultipartFile file) {
@RequestParam("file") @NotNull MultipartFile file) {
// Validate and sanitize path
if (path.contains("..")) {
throw new IllegalArgumentException("Invalid path");
}

UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
WriteRequest<UserIDAuth, PrivateResource> request =
WriteRequest.forPrivate(userIDAuth, new StorageIdentifier(storageId), path);
Expand All @@ -91,14 +103,20 @@ public void writeDocument(@RequestHeader String user,
* lists files in user's private space.
*/
@GetMapping("/documents/{*path}")
public List<String> listDocuments(@RequestHeader String user,
@RequestHeader String password,
public List<String> listDocuments(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@RequestHeader(defaultValue = StorageIdentifier.DEFAULT_ID) String storageId,
@PathVariable(required = false) String path) {
UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
path = Optional.ofNullable(path)
.map(it -> it.replaceAll("^\\.$", ""))
.orElse("./");

// Validate and sanitize path
if (path.contains("..")) {
throw new IllegalArgumentException("Invalid path");
}

try {
List<String> documentList = datasafeService.privateService().list(
ListRequest.forPrivate(userIDAuth, new StorageIdentifier(storageId), path))
Expand All @@ -115,10 +133,16 @@ public List<String> listDocuments(@RequestHeader String user,
* deletes files from user's private space.
*/
@DeleteMapping("/document/{*path}")
public void removeDocument(@RequestHeader String user,
@RequestHeader String password,
public void removeDocument(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@RequestHeader(defaultValue = StorageIdentifier.DEFAULT_ID) String storageId,
@PathVariable String path) {
@PathVariable @NotBlank String path) {

// Validate and sanitize path
if (path.contains("..")) {
throw new IllegalArgumentException("Invalid path");
}

UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
RemoveRequest<UserIDAuth, PrivateResource> request =
RemoveRequest.forPrivate(userIDAuth, new StorageIdentifier(storageId), path);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import de.adorsys.datasafe.types.api.resource.BasePrivateResource;
import de.adorsys.datasafe.types.api.resource.PrivateResource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -28,7 +29,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -52,10 +52,10 @@ public class InboxController {
*/
@SneakyThrows
@PutMapping(value = "/inbox/document/{*path}", consumes = MULTIPART_FORM_DATA_VALUE)
public void writeToInbox(@RequestHeader String user,
@RequestHeader String password,
@RequestHeader Set<String> recipients,
@PathVariable String path,
public void writeToInbox(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@RequestHeader Set<@NotBlank String> recipients,
@PathVariable @NotBlank String path,
@RequestParam("file") MultipartFile file) {
UserIDAuth fromUser = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
Set<UserID> toUsers = recipients.stream().map(UserID::new).collect(Collectors.toSet());
Expand All @@ -72,9 +72,9 @@ public void writeToInbox(@RequestHeader String user,
*/
@SneakyThrows
@GetMapping(value = "/inbox/document/{*path}", produces = APPLICATION_OCTET_STREAM_VALUE)
public void readFromInbox(@RequestHeader String user,
@RequestHeader String password,
@PathVariable String path,
public void readFromInbox(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@PathVariable @NotBlank String path,
HttpServletResponse response) {
path = path.replaceAll("^/", "");
UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
Expand All @@ -93,9 +93,9 @@ public void readFromInbox(@RequestHeader String user,
* Deletes file from users' INBOX.
*/
@DeleteMapping("/inbox/document/{*path}")
public void deleteFromInbox(@RequestHeader String user,
@RequestHeader String password,
@PathVariable String path) {
public void deleteFromInbox(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@PathVariable @NotBlank String path) {
path = path.replaceAll("^/", "");
UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
PrivateResource resource = BasePrivateResource.forPrivate(path);
Expand All @@ -108,8 +108,8 @@ public void deleteFromInbox(@RequestHeader String user,
* list files in users' INBOX.
*/
@GetMapping(value = "/inbox/documents/{*path}", produces = APPLICATION_JSON_VALUE)
public List<String> listInbox(@RequestHeader String user,
@RequestHeader String password,
public List<String> listInbox(@RequestHeader @NotBlank String user,
@RequestHeader @NotBlank String password,
@PathVariable(required = false) String path) {
path = path.replaceAll("^/", "");
UserIDAuth userIDAuth = new UserIDAuth(new UserID(user), ReadKeyPasswordHelper.getForString(password));
Expand Down
Loading

0 comments on commit 25c20bf

Please sign in to comment.