SEBSERV-135 finished up decryption

This commit is contained in:
anhefti 2021-05-12 11:15:24 +02:00
parent a4cb075f42
commit c9be24197d
3 changed files with 98 additions and 36 deletions

View file

@ -11,17 +11,57 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.Certificate;
import java.util.Enumeration;
import java.util.Objects;
import javax.crypto.Cipher;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
public abstract class AbstractCertificateCryptor {
private static final Logger log = LoggerFactory.getLogger(AbstractCertificateCryptor.class);
protected static final int PUBLIC_KEY_HASH_SIZE = 20;
protected static final int ENCRYPTION_KEY_BITS = 256;
protected static final int KEY_LENGTH_SIZE = 4;
protected final CertificateService certificateService;
public AbstractCertificateCryptor(final CertificateService certificateService) {
this.certificateService = certificateService;
}
protected Certificate getCertificateByPublicKeyHash(final Long institutionId, final byte[] publicKeyHash) {
try {
final Certificates certs = this.certificateService
.getCertificates(institutionId)
.getOrThrow();
@SuppressWarnings("unchecked")
final Enumeration<String> engineAliases = certs.keyStore.engineAliases();
while (engineAliases.hasMoreElements()) {
final Certificate certificate = certs.keyStore.engineGetCertificate(engineAliases.nextElement());
final byte[] otherPublicKeyHash = generatePublicKeyHash(certificate);
if (Objects.equals(otherPublicKeyHash, publicKeyHash)) {
return certificate;
}
}
return null;
} catch (final Exception e) {
log.error("Unexpected error while trying to get certificate by public key hash: ", e);
return null;
}
}
protected byte[] generatePublicKeyHash(final Certificate cert) {
try {
@ -38,7 +78,11 @@ public abstract class AbstractCertificateCryptor {
return encryptWithCert(cert, data, data.length);
}
protected byte[] encryptWithCert(final Certificate cert, final byte[] data, final int length) throws Exception {
protected byte[] encryptWithCert(
final Certificate cert,
final byte[] data,
final int length) throws Exception {
final String algorithm = cert.getPublicKey().getAlgorithm();
final Cipher encryptCipher = Cipher.getInstance(algorithm);
encryptCipher.init(Cipher.ENCRYPT_MODE, cert);
@ -46,10 +90,17 @@ public abstract class AbstractCertificateCryptor {
}
protected byte[] decryptWithCert(final Certificate cert, final byte[] encryptedData) throws Exception {
return decryptWithCert(cert, encryptedData, encryptedData.length);
}
protected byte[] decryptWithCert(
final Certificate cert,
final byte[] encryptedData, final int length) throws Exception {
final String algorithm = cert.getPublicKey().getAlgorithm();
final Cipher encryptCipher = Cipher.getInstance(algorithm);
encryptCipher.init(Cipher.DECRYPT_MODE, cert);
return encryptCipher.doFinal(encryptedData);
return encryptCipher.doFinal(encryptedData, 0, length);
}
protected byte[] parsePublicKeyHash(final InputStream input) throws IOException {

View file

@ -21,6 +21,7 @@ import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigCryptor;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionContext;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SEBConfigEncryptionService.Strategy;
@ -32,9 +33,14 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i
private static final Logger log = LoggerFactory.getLogger(CertificateAsymetricKeyCryptor.class);
private static final int BUFFER_LENGTH = 128;
private static final Set<Strategy> STRATEGIES = Utils.immutableSetOf(
Strategy.PUBLIC_KEY_HASH);
public CertificateAsymetricKeyCryptor(final CertificateService certificateService) {
super(certificateService);
}
@Override
public Set<Strategy> strategies() {
return STRATEGIES;
@ -57,7 +63,7 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i
output.write(publicKeyHash, 0, publicKeyHash.length);
final byte[] buffer = new byte[128];
final byte[] buffer = new byte[BUFFER_LENGTH];
int readBytes = input.read(buffer, 0, buffer.length);
while (readBytes > 0) {
@ -86,7 +92,36 @@ public class CertificateAsymetricKeyCryptor extends AbstractCertificateCryptor i
final InputStream input,
final SEBConfigEncryptionContext context) {
// TODO Auto-generated method stub
try {
final byte[] publicKeyHash = parsePublicKeyHash(input);
final Certificate certificate = getCertificateByPublicKeyHash(
context.institutionId(),
publicKeyHash);
if (certificate == null) {
throw new RuntimeException("No matching certificate found to decrypt the configuration");
}
final byte[] buffer = new byte[BUFFER_LENGTH];
int readBytes = input.read(buffer, 0, buffer.length);
while (readBytes > 0) {
final byte[] encryptedBlock = decryptWithCert(certificate, buffer, readBytes);
output.write(encryptedBlock, 0, encryptedBlock.length);
readBytes = input.read(buffer, 0, buffer.length);
}
} catch (final Exception e) {
log.error("Error while trying to stream and decrypt data: ", e);
} finally {
try {
output.flush();
output.close();
} catch (final Exception e) {
log.error("Failed to close output: ", e);
}
}
if (log.isDebugEnabled()) {
log.debug("*** Start streaming asynchronous certificate asymmetric-key decryption");
}

View file

@ -16,8 +16,6 @@ import java.nio.ByteOrder;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.util.Base64;
import java.util.Enumeration;
import java.util.Objects;
import java.util.Set;
import javax.crypto.KeyGenerator;
@ -30,7 +28,6 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Certificates;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.CertificateService;
@ -59,16 +56,15 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im
private final PasswordEncryptor passwordEncryptor;
private final PasswordDecryptor passwordDecryptor;
private final CertificateService certificateService;
public CertificateSymetricKeyCryptor(
final PasswordEncryptor passwordEncryptor,
final PasswordDecryptor passwordDecryptor,
final CertificateService certificateService) {
super(certificateService);
this.passwordEncryptor = passwordEncryptor;
this.passwordDecryptor = passwordDecryptor;
this.certificateService = certificateService;
}
@Override
@ -124,11 +120,16 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im
try {
final byte[] publicKeyHash = parsePublicKeyHash(input);
final Certificate cert = getCertificateByPublicKeyHash(
final Certificate certificate = getCertificateByPublicKeyHash(
context.institutionId(),
publicKeyHash);
if (certificate == null) {
throw new RuntimeException("No matching certificate found to decrypt the configuration");
}
final byte[] encryptedKey = getEncryptedKey(input);
final byte[] symetricKey = decryptWithCert(cert, encryptedKey);
final byte[] symetricKey = decryptWithCert(certificate, encryptedKey);
final CharSequence symetricKeyBase64 = Base64.getEncoder().encodeToString(symetricKey);
this.passwordDecryptor.decrypt(output, input, symetricKeyBase64);
@ -161,31 +162,6 @@ public class CertificateSymetricKeyCryptor extends AbstractCertificateCryptor im
return encryptedKey;
}
private Certificate getCertificateByPublicKeyHash(final Long institutionId, final byte[] publicKeyHash) {
try {
final Certificates certs = this.certificateService
.getCertificates(institutionId)
.getOrThrow();
@SuppressWarnings("unchecked")
final Enumeration<String> engineAliases = certs.keyStore.engineAliases();
while (engineAliases.hasMoreElements()) {
final Certificate certificate = certs.keyStore.engineGetCertificate(engineAliases.nextElement());
final byte[] otherPublicKeyHash = generatePublicKeyHash(certificate);
if (Objects.equals(otherPublicKeyHash, publicKeyHash)) {
return certificate;
}
}
return null;
} catch (final Exception e) {
log.error("Unexpected error while trying to get certificate by public key hash: ", e);
return null;
}
}
private byte[] generateSymetricKey() throws NoSuchAlgorithmException {
final KeyGenerator keyGenerator = KeyGenerator.getInstance(Constants.AES);
keyGenerator.init(ENCRYPTION_KEY_BITS);