Skip to content

Commit 5e3f2d0

Browse files
authored
Merge pull request #10 from ftn-projects/feature/update-key-management
Fix lob issues and key ownership
2 parents 08fe733 + e5041e2 commit 5e3f2d0

10 files changed

Lines changed: 276 additions & 63 deletions

File tree

MiniKms/logs/controller.log

Lines changed: 186 additions & 0 deletions
Large diffs are not rendered by default.

MiniKms/src/main/java/ftn/security/minikms/controller/KeyComputeController.java

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,64 +30,63 @@ public ResponseEntity<?> encryptSymmetric(@RequestBody CryptoDTO dto) throws Inv
3030
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
3131
BadPaddingException, InvalidKeyException {
3232
try {
33-
String encrypted = service.encryptAes(dto.getMessage(), dto.getKeyId(),
34-
dto.getUsername(), dto.getVersion());
33+
String encrypted = service.encryptAes(dto.getMessage(), dto.getKeyId(), dto.getVersion());
3534
return ResponseEntity.status(HttpStatus.CREATED).body(encrypted);
3635
} catch (InvalidParameterException e) {
3736
return ResponseEntity.badRequest().body(e.getMessage());
3837
}
3938
}
39+
4040
@PostMapping("/decrypt/symmetric")
4141
public ResponseEntity<?> decryptSymmetric(@RequestBody CryptoDTO dto) throws InvalidAlgorithmParameterException,
4242
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
4343
BadPaddingException, InvalidKeyException {
4444
try {
45-
String decrypted = service.decryptAes(dto.getMessage(), dto.getKeyId(),
46-
dto.getUsername(), dto.getVersion());
45+
String decrypted = service.decryptAes(dto.getMessage(), dto.getKeyId(), dto.getVersion());
4746
return ResponseEntity.status(HttpStatus.CREATED).body(decrypted);
4847
} catch (InvalidParameterException e) {
4948
return ResponseEntity.badRequest().body(e.getMessage());
5049
}
5150
}
51+
5252
@PostMapping("/encrypt/asymmetric")
5353
public ResponseEntity<?> encryptAsymmetric(@RequestBody CryptoDTO dto) throws
5454
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
5555
BadPaddingException, InvalidKeyException, InvalidKeySpecException {
5656
try {
57-
String encrypted = service.encryptRsa(dto.getMessage(), dto.getKeyId(),
58-
dto.getUsername(), dto.getVersion());
57+
String encrypted = service.encryptRsa(dto.getMessage(), dto.getKeyId(), dto.getVersion());
5958
return ResponseEntity.status(HttpStatus.CREATED).body(encrypted);
6059
} catch (InvalidParameterException e) {
6160
return ResponseEntity.badRequest().body(e.getMessage());
6261
}
6362
}
63+
6464
@PostMapping("/decrypt/asymmetric")
6565
public ResponseEntity<?> decryptAsymmetric(@RequestBody CryptoDTO dto) throws
6666
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
6767
BadPaddingException, InvalidKeyException, InvalidKeySpecException {
6868
try {
69-
String decrypted = service.decryptRsa(dto.getMessage(), dto.getKeyId(),
70-
dto.getUsername(), dto.getVersion());
69+
String decrypted = service.decryptRsa(dto.getMessage(), dto.getKeyId(), dto.getVersion());
7170
return ResponseEntity.status(HttpStatus.CREATED).body(decrypted);
7271
} catch (InvalidParameterException e) {
7372
return ResponseEntity.badRequest().body(e.getMessage());
7473
}
7574
}
75+
7676
@PostMapping("/compute/hmac")
7777
public ResponseEntity<?> computeHmac(@RequestBody CryptoDTO dto) throws Exception {
7878
try {
79-
String computed = service.computeHmac(dto.getMessage(), dto.getKeyId(),
80-
dto.getUsername(), dto.getVersion());
79+
String computed = service.computeHmac(dto.getMessage(), dto.getKeyId(), dto.getVersion());
8180
return ResponseEntity.status(HttpStatus.CREATED).body(computed);
8281
} catch (InvalidParameterException e) {
8382
return ResponseEntity.badRequest().body(e.getMessage());
8483
}
8584
}
85+
8686
@PostMapping("/verify/hmac")
8787
public ResponseEntity<?> verifyHmac(@RequestBody CryptoDTO dto) throws Exception {
8888
try {
89-
Boolean verified = service.verifyHmac(dto.getMessage(), dto.getHmacBase64(), dto.getKeyId(),
90-
dto.getUsername(), dto.getVersion());
89+
Boolean verified = service.verifyHmac(dto.getMessage(), dto.getHmacBase64(), dto.getKeyId(), dto.getVersion());
9190
return ResponseEntity.status(HttpStatus.CREATED).body(verified);
9291
} catch (InvalidParameterException e) {
9392
return ResponseEntity.badRequest().body(e.getMessage());

MiniKms/src/main/java/ftn/security/minikms/controller/KeyManagementController.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,35 @@ public ResponseEntity<?> createKey(@RequestBody KeyDTO dto, Principal principal)
3939
}
4040

4141
@PostMapping("/rotate")
42-
public ResponseEntity<?> rotateKey(@RequestBody KeyDTO dto, Principal principal) throws GeneralSecurityException {
43-
var username = principal.getName();
44-
42+
public ResponseEntity<?> rotateKey(@RequestBody KeyDTO dto) throws GeneralSecurityException {
4543
try {
46-
var created = keyService.rotateKey(dto.getId(), username);
44+
var created = keyService.rotateKey(dto.getId());
4745
return ResponseEntity.status(HttpStatus.CREATED).body(mapper.toDto(created));
4846
} catch (InvalidParameterException e) {
4947
return ResponseEntity.badRequest().body(e.getMessage());
5048
}
5149
}
5250

53-
@DeleteMapping("/{id}")
54-
public ResponseEntity<?> deleteKey(@PathVariable UUID id, Principal principal) {
55-
var username = principal.getName();
51+
@GetMapping
52+
public ResponseEntity<?> getKeyMetadata() {
53+
var keys = keyService.getAllKeys();
54+
return ResponseEntity.ok(keys.stream().map(mapper::toDto).toList());
55+
}
56+
57+
@GetMapping("/{id}")
58+
public ResponseEntity<?> getKeyById(@PathVariable UUID id) {
59+
try {
60+
var key = keyService.getKeyById(id);
61+
return ResponseEntity.ok(mapper.toDto(key));
62+
} catch (InvalidParameterException e) {
63+
return ResponseEntity.badRequest().body(e.getMessage());
64+
}
65+
}
5666

67+
@DeleteMapping("/{id}")
68+
public ResponseEntity<?> deleteKey(@PathVariable UUID id) {
5769
try {
58-
keyService.deleteKey(id, username);
70+
keyService.deleteKey(id);
5971
return ResponseEntity.noContent().build();
6072
} catch (InvalidParameterException e) {
6173
return ResponseEntity.badRequest().body(e.getMessage());

MiniKms/src/main/java/ftn/security/minikms/dto/CryptoDTO.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
public class CryptoDTO {
1111
private String message;
1212
private UUID keyId;
13-
private String username;
1413
private Integer version;
1514
private String hmacBase64;
1615
}

MiniKms/src/main/java/ftn/security/minikms/entity/KeyMetadata.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class KeyMetadata {
3636
@ManyToOne
3737
@JoinColumn(name = "user_id", nullable = false)
3838
@OnDelete(action = OnDeleteAction.CASCADE)
39-
private User user;
39+
private User createdBy;
4040

4141
private Instant createdAt;
4242
private Instant rotatedAt;
@@ -50,7 +50,7 @@ public static KeyMetadata of(String alias, KeyType keyType, List<KeyOperation> a
5050
entity.primaryVersion = 0;
5151
entity.keyType = keyType;
5252
entity.allowedOperations = allowedOperations;
53-
entity.user = user;
53+
entity.createdBy = user;
5454
entity.createdAt = Instant.now();
5555
return entity;
5656
}
@@ -62,10 +62,4 @@ public void updatePrimaryVersion(Integer version) {
6262
rotatedAt = Instant.now();
6363
}
6464
}
65-
public WrappedKey getVersion(int version) {
66-
return versions.stream()
67-
.filter(wk -> wk.getVersion() == version)
68-
.findFirst()
69-
.orElse(null);
70-
}
7165
}

MiniKms/src/main/java/ftn/security/minikms/entity/WrappedKey.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ public class WrappedKey {
2727
@OnDelete(action = OnDeleteAction.CASCADE)
2828
private KeyMetadata metadata;
2929

30-
public static WrappedKey of(KeyMaterial wrappedMaterial, KeyMetadata metadata) {
30+
public static WrappedKey of(Integer version, KeyMaterial wrappedMaterial, KeyMetadata metadata) {
3131
var entity = new WrappedKey();
32-
entity.version = 1;
32+
entity.version = version;
3333
entity.wrappedMaterial = wrappedMaterial;
3434
entity.metadata = metadata;
3535
return entity;

MiniKms/src/main/java/ftn/security/minikms/repository/KeyMetadataRepository.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@
33
import ftn.security.minikms.entity.KeyMetadata;
44
import org.springframework.data.jpa.repository.JpaRepository;
55

6-
import java.util.Optional;
76
import java.util.UUID;
87

98
public interface KeyMetadataRepository extends JpaRepository<KeyMetadata, UUID> {
10-
boolean existsByIdAndUserUsername(UUID id, String username);
11-
Optional<KeyMetadata> findByIdAndUserUsername(UUID id, String username);
129
}

MiniKms/src/main/java/ftn/security/minikms/repository/WrappedKeyRepository.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,9 @@
33
import ftn.security.minikms.entity.WrappedKey;
44
import org.springframework.data.jpa.repository.JpaRepository;
55

6+
import java.util.Optional;
7+
import java.util.UUID;
8+
69
public interface WrappedKeyRepository extends JpaRepository<WrappedKey, Long> {
10+
Optional<WrappedKey> findByMetadataIdAndVersion(UUID metadataId, Integer version);
711
}

MiniKms/src/main/java/ftn/security/minikms/service/KeyComputeService.java

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
import ftn.security.minikms.entity.KeyMaterial;
44
import ftn.security.minikms.repository.KeyMetadataRepository;
5+
import ftn.security.minikms.repository.WrappedKeyRepository;
56
import org.springframework.stereotype.Service;
7+
import org.springframework.transaction.annotation.Transactional;
68

79
import javax.crypto.BadPaddingException;
810
import javax.crypto.IllegalBlockSizeException;
@@ -15,50 +17,63 @@
1517
import java.util.UUID;
1618

1719
@Service
20+
@Transactional
1821
public class KeyComputeService {
1922
private final KeyMetadataRepository metadataRepository;
23+
private final WrappedKeyRepository keyRepository;
2024
private final AESService aesService;
2125
private final RSAService rsaService;
2226
private final HMACService hmacService;
23-
private static final String NOT_AUTHORIZED_MSG = "You do not own a key with given id";
2427

25-
public KeyComputeService(KeyMetadataRepository metadataRepository) {
28+
public KeyComputeService(KeyMetadataRepository metadataRepository, WrappedKeyRepository keyRepository) {
2629
this.metadataRepository = metadataRepository;
30+
this.keyRepository = keyRepository;
2731
this.aesService = new AESService();
2832
this.rsaService = new RSAService();
2933
this.hmacService = new HMACService();
3034
}
31-
public String encryptAes(String message, UUID keyId, String username, Integer version)
35+
36+
public String encryptAes(String message, UUID keyId, Integer version)
3237
throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException,
3338
NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
34-
return aesService.encrypt(message, getKey(keyId, username, version));
39+
return aesService.encrypt(message, getKey(keyId, version));
3540
}
36-
public String decryptAes(String message, UUID keyId, String username, Integer version)
41+
42+
public String decryptAes(String message, UUID keyId, Integer version)
3743
throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException,
3844
NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
39-
return aesService.decrypt(message, getKey(keyId, username, version));
45+
return aesService.decrypt(message, getKey(keyId, version));
4046
}
41-
public String encryptRsa(String message, UUID keyId, String username, Integer version)
47+
48+
public String encryptRsa(String message, UUID keyId, Integer version)
4249
throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
4350
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
44-
return rsaService.encrypt(message, getKey(keyId, username, version));
51+
return rsaService.encrypt(message, getKey(keyId, version));
4552
}
46-
public String decryptRsa(String message, UUID keyId, String username, Integer version)
53+
54+
public String decryptRsa(String message, UUID keyId, Integer version)
4755
throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
4856
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
49-
return rsaService.decrypt(message, getKey(keyId, username, version));
57+
return rsaService.decrypt(message, getKey(keyId, version));
5058
}
51-
public String computeHmac(String message, UUID keyId, String username, Integer version) throws Exception {
52-
return hmacService.computeHmac(message, getKey(keyId, username, version));
59+
60+
public String computeHmac(String message, UUID keyId, Integer version) throws Exception {
61+
return hmacService.computeHmac(message, getKey(keyId, version));
5362
}
54-
public boolean verifyHmac(String message, String hmacBase64, UUID keyId, String username, Integer version)
63+
64+
public boolean verifyHmac(String message, String hmacBase64, UUID keyId, Integer version)
5565
throws Exception {
56-
return hmacService.verifyHmac(message,hmacBase64, getKey(keyId, username, version));
66+
return hmacService.verifyHmac(message,hmacBase64, getKey(keyId, version));
5767
}
58-
private KeyMaterial getKey(UUID keyId, String username, Integer version){
59-
var metadata = metadataRepository.findByIdAndUserUsername(keyId, username)
60-
.orElseThrow(() -> new InvalidParameterException(NOT_AUTHORIZED_MSG));
61-
var wrappedKey = version != null? metadata.getVersion(version) : metadata.getVersion(metadata.getPrimaryVersion());
68+
69+
public KeyMaterial getKey(UUID keyId, Integer version) {
70+
var metadata = metadataRepository.findById(keyId)
71+
.orElseThrow(() -> new InvalidParameterException("Key with given id does not exist"));
72+
73+
if (version == null) version = metadata.getPrimaryVersion();
74+
var wrappedKey = keyRepository.findByMetadataIdAndVersion(keyId, version)
75+
.orElseThrow(() -> new InvalidParameterException("Key with given id and version does not exist"));
76+
6277
return wrappedKey.getWrappedMaterial();
6378
}
6479
}

MiniKms/src/main/java/ftn/security/minikms/service/KeyManagementService.java

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class KeyManagementService {
2323
private final UserRepository userRepository;
2424
private final RootKeyManager rootKeyManager;
2525
private final Map<KeyType, ICryptoService> cryptoServices;
26-
private static final String NOT_AUTHORIZED_MSG = "You do not own a key with given id";
26+
private static final String KEY_NOT_FOUND = "Key with given id does not exist";
2727

2828
public KeyManagementService(
2929
KeyMetadataRepository metadataRepository,
@@ -48,16 +48,13 @@ public KeyMetadata createKey(String alias, KeyType keyType, List<KeyOperation> a
4848
return createNewKeyVersion(metadata, 1);
4949
}
5050

51-
public void deleteKey(UUID id, String username) throws InvalidParameterException {
52-
if (!metadataRepository.existsByIdAndUserUsername(id, username))
53-
throw new InvalidParameterException(NOT_AUTHORIZED_MSG);
54-
51+
public void deleteKey(UUID id) throws InvalidParameterException {
5552
metadataRepository.deleteById(id);
5653
}
5754

58-
public KeyMetadata rotateKey(UUID id, String username) throws InvalidParameterException, GeneralSecurityException {
59-
var metadata = metadataRepository.findByIdAndUserUsername(id, username)
60-
.orElseThrow(() -> new InvalidParameterException(NOT_AUTHORIZED_MSG));
55+
public KeyMetadata rotateKey(UUID id) throws InvalidParameterException, GeneralSecurityException {
56+
var metadata = metadataRepository.findById(id)
57+
.orElseThrow(() -> new InvalidParameterException(KEY_NOT_FOUND));
6158

6259
var nextVersion = metadata.getPrimaryVersion() + 1;
6360
return createNewKeyVersion(metadata, nextVersion);
@@ -66,6 +63,8 @@ public KeyMetadata rotateKey(UUID id, String username) throws InvalidParameterEx
6663
private KeyMetadata createNewKeyVersion(KeyMetadata metadata, Integer version) throws GeneralSecurityException {
6764
var id = metadata.getId();
6865
var keyType = metadata.getKeyType();
66+
metadata.updatePrimaryVersion(version); // Set the latest version as primary
67+
var saved = metadataRepository.save(metadata);
6968

7069
var material = cryptoServices.get(keyType).generateKey();
7170
var secretKey = material.getKey();
@@ -76,13 +75,21 @@ private KeyMetadata createNewKeyVersion(KeyMetadata metadata, Integer version) t
7675

7776
material.setKey(wrapped);
7877

79-
var key = keyRepository.save(WrappedKey.of(material, metadata));
80-
metadata.updatePrimaryVersion(version); // Set the latest version as primary
81-
return metadataRepository.save(metadata);
78+
keyRepository.save(WrappedKey.of(version, material, saved));
79+
return saved;
8280
}
8381

8482
private User findUserByUsername(String username) throws InvalidParameterException {
8583
return userRepository.findByUsername(username).orElseThrow(() ->
8684
new InvalidParameterException("User with given username does not exist"));
8785
}
86+
87+
public List<KeyMetadata> getAllKeys() {
88+
return metadataRepository.findAll();
89+
}
90+
91+
public KeyMetadata getKeyById(UUID id) {
92+
return metadataRepository.findById(id).orElseThrow(() ->
93+
new InvalidParameterException("Key with given id does not exist"));
94+
}
8895
}

0 commit comments

Comments
 (0)