Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 186 additions & 0 deletions MiniKms/logs/controller.log

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -30,64 +30,63 @@ public ResponseEntity<?> encryptSymmetric(@RequestBody CryptoDTO dto) throws Inv
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
BadPaddingException, InvalidKeyException {
try {
String encrypted = service.encryptAes(dto.getMessage(), dto.getKeyId(),
dto.getUsername(), dto.getVersion());
String encrypted = service.encryptAes(dto.getMessage(), dto.getKeyId(), dto.getVersion());
return ResponseEntity.status(HttpStatus.CREATED).body(encrypted);
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@PostMapping("/decrypt/symmetric")
public ResponseEntity<?> decryptSymmetric(@RequestBody CryptoDTO dto) throws InvalidAlgorithmParameterException,
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
BadPaddingException, InvalidKeyException {
try {
String decrypted = service.decryptAes(dto.getMessage(), dto.getKeyId(),
dto.getUsername(), dto.getVersion());
String decrypted = service.decryptAes(dto.getMessage(), dto.getKeyId(), dto.getVersion());
return ResponseEntity.status(HttpStatus.CREATED).body(decrypted);
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@PostMapping("/encrypt/asymmetric")
public ResponseEntity<?> encryptAsymmetric(@RequestBody CryptoDTO dto) throws
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
BadPaddingException, InvalidKeyException, InvalidKeySpecException {
try {
String encrypted = service.encryptRsa(dto.getMessage(), dto.getKeyId(),
dto.getUsername(), dto.getVersion());
String encrypted = service.encryptRsa(dto.getMessage(), dto.getKeyId(), dto.getVersion());
return ResponseEntity.status(HttpStatus.CREATED).body(encrypted);
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@PostMapping("/decrypt/asymmetric")
public ResponseEntity<?> decryptAsymmetric(@RequestBody CryptoDTO dto) throws
NoSuchPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException,
BadPaddingException, InvalidKeyException, InvalidKeySpecException {
try {
String decrypted = service.decryptRsa(dto.getMessage(), dto.getKeyId(),
dto.getUsername(), dto.getVersion());
String decrypted = service.decryptRsa(dto.getMessage(), dto.getKeyId(), dto.getVersion());
return ResponseEntity.status(HttpStatus.CREATED).body(decrypted);
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@PostMapping("/compute/hmac")
public ResponseEntity<?> computeHmac(@RequestBody CryptoDTO dto) throws Exception {
try {
String computed = service.computeHmac(dto.getMessage(), dto.getKeyId(),
dto.getUsername(), dto.getVersion());
String computed = service.computeHmac(dto.getMessage(), dto.getKeyId(), dto.getVersion());
return ResponseEntity.status(HttpStatus.CREATED).body(computed);
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@PostMapping("/verify/hmac")
public ResponseEntity<?> verifyHmac(@RequestBody CryptoDTO dto) throws Exception {
try {
Boolean verified = service.verifyHmac(dto.getMessage(), dto.getHmacBase64(), dto.getKeyId(),
dto.getUsername(), dto.getVersion());
Boolean verified = service.verifyHmac(dto.getMessage(), dto.getHmacBase64(), dto.getKeyId(), dto.getVersion());
return ResponseEntity.status(HttpStatus.CREATED).body(verified);
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,35 @@ public ResponseEntity<?> createKey(@RequestBody KeyDTO dto, Principal principal)
}

@PostMapping("/rotate")
public ResponseEntity<?> rotateKey(@RequestBody KeyDTO dto, Principal principal) throws GeneralSecurityException {
var username = principal.getName();

public ResponseEntity<?> rotateKey(@RequestBody KeyDTO dto) throws GeneralSecurityException {
try {
var created = keyService.rotateKey(dto.getId(), username);
var created = keyService.rotateKey(dto.getId());
return ResponseEntity.status(HttpStatus.CREATED).body(mapper.toDto(created));
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@DeleteMapping("/{id}")
public ResponseEntity<?> deleteKey(@PathVariable UUID id, Principal principal) {
var username = principal.getName();
@GetMapping
public ResponseEntity<?> getKeyMetadata() {
var keys = keyService.getAllKeys();
return ResponseEntity.ok(keys.stream().map(mapper::toDto).toList());
}

@GetMapping("/{id}")
public ResponseEntity<?> getKeyById(@PathVariable UUID id) {
try {
var key = keyService.getKeyById(id);
return ResponseEntity.ok(mapper.toDto(key));
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
}
}

@DeleteMapping("/{id}")
public ResponseEntity<?> deleteKey(@PathVariable UUID id) {
try {
keyService.deleteKey(id, username);
keyService.deleteKey(id);
return ResponseEntity.noContent().build();
} catch (InvalidParameterException e) {
return ResponseEntity.badRequest().body(e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
public class CryptoDTO {
private String message;
private UUID keyId;
private String username;
private Integer version;
private String hmacBase64;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class KeyMetadata {
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
@OnDelete(action = OnDeleteAction.CASCADE)
private User user;
private User createdBy;

private Instant createdAt;
private Instant rotatedAt;
Expand All @@ -50,7 +50,7 @@ public static KeyMetadata of(String alias, KeyType keyType, List<KeyOperation> a
entity.primaryVersion = 0;
entity.keyType = keyType;
entity.allowedOperations = allowedOperations;
entity.user = user;
entity.createdBy = user;
entity.createdAt = Instant.now();
return entity;
}
Expand All @@ -62,10 +62,4 @@ public void updatePrimaryVersion(Integer version) {
rotatedAt = Instant.now();
}
}
public WrappedKey getVersion(int version) {
return versions.stream()
.filter(wk -> wk.getVersion() == version)
.findFirst()
.orElse(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public class WrappedKey {
@OnDelete(action = OnDeleteAction.CASCADE)
private KeyMetadata metadata;

public static WrappedKey of(KeyMaterial wrappedMaterial, KeyMetadata metadata) {
public static WrappedKey of(Integer version, KeyMaterial wrappedMaterial, KeyMetadata metadata) {
var entity = new WrappedKey();
entity.version = 1;
entity.version = version;
entity.wrappedMaterial = wrappedMaterial;
entity.metadata = metadata;
return entity;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@
import ftn.security.minikms.entity.KeyMetadata;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;
import java.util.UUID;

public interface KeyMetadataRepository extends JpaRepository<KeyMetadata, UUID> {
boolean existsByIdAndUserUsername(UUID id, String username);
Optional<KeyMetadata> findByIdAndUserUsername(UUID id, String username);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,9 @@
import ftn.security.minikms.entity.WrappedKey;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;
import java.util.UUID;

public interface WrappedKeyRepository extends JpaRepository<WrappedKey, Long> {
Optional<WrappedKey> findByMetadataIdAndVersion(UUID metadataId, Integer version);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import ftn.security.minikms.entity.KeyMaterial;
import ftn.security.minikms.repository.KeyMetadataRepository;
import ftn.security.minikms.repository.WrappedKeyRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
Expand All @@ -15,50 +17,63 @@
import java.util.UUID;

@Service
@Transactional
public class KeyComputeService {
private final KeyMetadataRepository metadataRepository;
private final WrappedKeyRepository keyRepository;
private final AESService aesService;
private final RSAService rsaService;
private final HMACService hmacService;
private static final String NOT_AUTHORIZED_MSG = "You do not own a key with given id";

public KeyComputeService(KeyMetadataRepository metadataRepository) {
public KeyComputeService(KeyMetadataRepository metadataRepository, WrappedKeyRepository keyRepository) {
this.metadataRepository = metadataRepository;
this.keyRepository = keyRepository;
this.aesService = new AESService();
this.rsaService = new RSAService();
this.hmacService = new HMACService();
}
public String encryptAes(String message, UUID keyId, String username, Integer version)

public String encryptAes(String message, UUID keyId, Integer version)
throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException,
NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
return aesService.encrypt(message, getKey(keyId, username, version));
return aesService.encrypt(message, getKey(keyId, version));
}
public String decryptAes(String message, UUID keyId, String username, Integer version)

public String decryptAes(String message, UUID keyId, Integer version)
throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException,
NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
return aesService.decrypt(message, getKey(keyId, username, version));
return aesService.decrypt(message, getKey(keyId, version));
}
public String encryptRsa(String message, UUID keyId, String username, Integer version)

public String encryptRsa(String message, UUID keyId, Integer version)
throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
return rsaService.encrypt(message, getKey(keyId, username, version));
return rsaService.encrypt(message, getKey(keyId, version));
}
public String decryptRsa(String message, UUID keyId, String username, Integer version)

public String decryptRsa(String message, UUID keyId, Integer version)
throws IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException,
NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException {
return rsaService.decrypt(message, getKey(keyId, username, version));
return rsaService.decrypt(message, getKey(keyId, version));
}
public String computeHmac(String message, UUID keyId, String username, Integer version) throws Exception {
return hmacService.computeHmac(message, getKey(keyId, username, version));

public String computeHmac(String message, UUID keyId, Integer version) throws Exception {
return hmacService.computeHmac(message, getKey(keyId, version));
}
public boolean verifyHmac(String message, String hmacBase64, UUID keyId, String username, Integer version)

public boolean verifyHmac(String message, String hmacBase64, UUID keyId, Integer version)
throws Exception {
return hmacService.verifyHmac(message,hmacBase64, getKey(keyId, username, version));
return hmacService.verifyHmac(message,hmacBase64, getKey(keyId, version));
}
private KeyMaterial getKey(UUID keyId, String username, Integer version){
var metadata = metadataRepository.findByIdAndUserUsername(keyId, username)
.orElseThrow(() -> new InvalidParameterException(NOT_AUTHORIZED_MSG));
var wrappedKey = version != null? metadata.getVersion(version) : metadata.getVersion(metadata.getPrimaryVersion());

public KeyMaterial getKey(UUID keyId, Integer version) {
var metadata = metadataRepository.findById(keyId)
.orElseThrow(() -> new InvalidParameterException("Key with given id does not exist"));

if (version == null) version = metadata.getPrimaryVersion();
var wrappedKey = keyRepository.findByMetadataIdAndVersion(keyId, version)
.orElseThrow(() -> new InvalidParameterException("Key with given id and version does not exist"));

return wrappedKey.getWrappedMaterial();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public class KeyManagementService {
private final UserRepository userRepository;
private final RootKeyManager rootKeyManager;
private final Map<KeyType, ICryptoService> cryptoServices;
private static final String NOT_AUTHORIZED_MSG = "You do not own a key with given id";
private static final String KEY_NOT_FOUND = "Key with given id does not exist";

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

public void deleteKey(UUID id, String username) throws InvalidParameterException {
if (!metadataRepository.existsByIdAndUserUsername(id, username))
throw new InvalidParameterException(NOT_AUTHORIZED_MSG);

public void deleteKey(UUID id) throws InvalidParameterException {
metadataRepository.deleteById(id);
}

public KeyMetadata rotateKey(UUID id, String username) throws InvalidParameterException, GeneralSecurityException {
var metadata = metadataRepository.findByIdAndUserUsername(id, username)
.orElseThrow(() -> new InvalidParameterException(NOT_AUTHORIZED_MSG));
public KeyMetadata rotateKey(UUID id) throws InvalidParameterException, GeneralSecurityException {
var metadata = metadataRepository.findById(id)
.orElseThrow(() -> new InvalidParameterException(KEY_NOT_FOUND));

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

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

material.setKey(wrapped);

var key = keyRepository.save(WrappedKey.of(material, metadata));
metadata.updatePrimaryVersion(version); // Set the latest version as primary
return metadataRepository.save(metadata);
keyRepository.save(WrappedKey.of(version, material, saved));
return saved;
}

private User findUserByUsername(String username) throws InvalidParameterException {
return userRepository.findByUsername(username).orElseThrow(() ->
new InvalidParameterException("User with given username does not exist"));
}

public List<KeyMetadata> getAllKeys() {
return metadataRepository.findAll();
}

public KeyMetadata getKeyById(UUID id) {
return metadataRepository.findById(id).orElseThrow(() ->
new InvalidParameterException("Key with given id does not exist"));
}
}
Loading