From c9be24197dad28fb58f94330bb638cce5bddca58 Mon Sep 17 00:00:00 2001 From: anhefti Date: Wed, 12 May 2021 11:15:24 +0200 Subject: [PATCH] SEBSERV-135 finished up decryption --- .../impl/AbstractCertificateCryptor.java | 55 ++++++++++++++++++- .../impl/CertificateAsymetricKeyCryptor.java | 39 ++++++++++++- .../impl/CertificateSymetricKeyCryptor.java | 40 +++----------- 3 files changed, 98 insertions(+), 36 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java index e02ba44f..b709061a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/AbstractCertificateCryptor.java @@ -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 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 { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java index 94fbfb68..159a03fa 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateAsymetricKeyCryptor.java @@ -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 STRATEGIES = Utils.immutableSetOf( Strategy.PUBLIC_KEY_HASH); + public CertificateAsymetricKeyCryptor(final CertificateService certificateService) { + super(certificateService); + } + @Override public Set 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"); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java index 74d89588..19362bea 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/sebconfig/impl/CertificateSymetricKeyCryptor.java @@ -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 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);