finished config streaming out/in
This commit is contained in:
parent
06da2d026b
commit
27b75062cc
12 changed files with 326 additions and 309 deletions
|
@ -8,14 +8,8 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gbl.async;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
@ -72,41 +66,4 @@ public class AsyncService {
|
|||
momoized);
|
||||
}
|
||||
|
||||
public void pipeToOutputStream(
|
||||
final OutputStream output,
|
||||
final Consumer<PipedOutputStream> consumer) {
|
||||
|
||||
this.asyncRunner.runAsync(() -> {
|
||||
|
||||
PipedOutputStream pout = null;
|
||||
PipedInputStream pin = null;
|
||||
try {
|
||||
pout = new PipedOutputStream();
|
||||
pin = new PipedInputStream(pout);
|
||||
|
||||
consumer.accept(pout);
|
||||
|
||||
IOUtils.copyLarge(pin, output);
|
||||
|
||||
pin.close();
|
||||
pout.flush();
|
||||
pout.close();
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while pipe stream data: ", e);
|
||||
} finally {
|
||||
try {
|
||||
pin.close();
|
||||
} catch (final IOException e1) {
|
||||
log.error("Failed to close PipedInputStream: ", e1);
|
||||
}
|
||||
try {
|
||||
pout.close();
|
||||
} catch (final IOException e1) {
|
||||
log.error("Failed to close PipedOutputStream: ", e1);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -181,6 +181,12 @@ public final class Result<T> {
|
|||
}
|
||||
}
|
||||
|
||||
public void ifPresent(final Consumer<T> consumer) {
|
||||
if (this.value != null) {
|
||||
consumer.accept(this.value);
|
||||
}
|
||||
}
|
||||
|
||||
/** Use this to map a given Result of type T to another Result of type U
|
||||
* within a given mapping function.
|
||||
*
|
||||
|
|
|
@ -10,10 +10,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Set;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy;
|
||||
|
||||
/** Interface for a SEB Configuration encryption and decryption strategy.
|
||||
|
@ -27,32 +25,14 @@ public interface SebConfigCryptor {
|
|||
* @return Set of strategies a concrete implementation is supporting */
|
||||
Set<Strategy> strategies();
|
||||
|
||||
/** Encrypt a given SEB configuration plain text representation within the given SebConfigEncryptionContext
|
||||
*
|
||||
* @param plainTextConfig SEB configuration plain text representation
|
||||
* @param context SebConfigEncryptionContext containing additional data if needed
|
||||
* @return Result of encrypted data within a ByteBuffer or reference to an Exception on error case */
|
||||
Result<ByteBuffer> encrypt(
|
||||
final CharSequence plainTextConfig,
|
||||
final SebConfigEncryptionContext context);
|
||||
|
||||
/** Decrypt a given encrypted SEB configuration that has been encrypted by one of the supported strategies.
|
||||
*
|
||||
* @param cipher the encrypted SEB configuration cipher(text) within a ByteBuffer
|
||||
* @param context SebConfigEncryptionContext containing additional data if needed
|
||||
* @return Result of decrypted SEB configuration within a ByteBuffer or reference to an Exception on error case. */
|
||||
Result<ByteBuffer> decrypt(
|
||||
final ByteBuffer cipher,
|
||||
final SebConfigEncryptionContext context);
|
||||
|
||||
void encrypt(
|
||||
final OutputStream encryptedOutput,
|
||||
final InputStream plainTextInputStream,
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context);
|
||||
|
||||
void decrypt(
|
||||
final OutputStream plainTextOutput,
|
||||
final InputStream cipherInputStream,
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context);
|
||||
|
||||
}
|
||||
|
|
|
@ -29,8 +29,9 @@ public interface SebConfigEncryptionContext {
|
|||
|
||||
/** Get a defined Certificate if supported.
|
||||
*
|
||||
* @param key The key of the Certificate to get
|
||||
* @return a defined Certificate
|
||||
* @throws UnsupportedOperationException if not supported */
|
||||
Certificate getCertificate();
|
||||
Certificate getCertificate(CharSequence key);
|
||||
|
||||
}
|
||||
|
|
|
@ -10,12 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
|
|||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
|
||||
public interface SebConfigEncryptionService {
|
||||
|
@ -60,21 +58,18 @@ public interface SebConfigEncryptionService {
|
|||
* @param plainTextConfig plainTextConfig plain text SEB Configuration as CharSequence
|
||||
* @return Result of plain text SEB Configuration within a ByteBuffer or a reference to an Exception on error
|
||||
* case */
|
||||
Result<ByteBuffer> plainText(CharSequence plainTextConfig);
|
||||
// void streamPlainData(
|
||||
// final OutputStream output,
|
||||
// final InputStream input);
|
||||
|
||||
void streamEncryption(
|
||||
void streamEncrypted(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final Strategy strategy,
|
||||
final CharSequence password);
|
||||
SebConfigEncryptionContext context);
|
||||
|
||||
Result<ByteBuffer> encryptWithCertificate(
|
||||
CharSequence plainTextConfig,
|
||||
Strategy strategy,
|
||||
Certificate certificate);
|
||||
|
||||
Result<ByteBuffer> decrypt(
|
||||
ByteBuffer cipher,
|
||||
void streamDecrypted(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
Supplier<CharSequence> passwordSupplier,
|
||||
Function<CharSequence, Certificate> certificateStore);
|
||||
|
||||
|
|
|
@ -16,4 +16,5 @@ public interface ZipService {
|
|||
void write(OutputStream out, InputStream in);
|
||||
|
||||
void read(OutputStream out, InputStream in);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
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;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@WebServiceProfile
|
||||
public class NoneEncryptor implements SebConfigCryptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NoneEncryptor.class);
|
||||
|
||||
private static final Set<Strategy> STRATEGIES = Utils.immutableSetOf(
|
||||
Strategy.PLAIN_TEXT);
|
||||
|
||||
@Override
|
||||
public Set<Strategy> strategies() {
|
||||
return STRATEGIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
public void encrypt(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No encryption, write plain input data");
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
IOUtils.copyLarge(input, output);
|
||||
|
||||
input.close();
|
||||
output.flush();
|
||||
output.close();
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while streaming plain data to output: ", e);
|
||||
} finally {
|
||||
try {
|
||||
input.close();
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to close InputStream");
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Finished with no encryption. Close input stream");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
public void decrypt(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No decryption, read plain input data");
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
IOUtils.copyLarge(input, output);
|
||||
|
||||
input.close();
|
||||
output.flush();
|
||||
output.close();
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while streaming plain data to output: ", e);
|
||||
} finally {
|
||||
try {
|
||||
input.close();
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to close InputStream");
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Finished with no encryption. Close input stream");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -11,13 +11,12 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.tomcat.util.http.fileupload.IOUtils;
|
||||
import org.cryptonode.jncryptor.AES256JNCryptorInputStream;
|
||||
import org.cryptonode.jncryptor.AES256JNCryptorOutputStream;
|
||||
import org.cryptonode.jncryptor.CryptorException;
|
||||
import org.cryptonode.jncryptor.JNCryptor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
@ -26,7 +25,6 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigCryptor;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionContext;
|
||||
|
@ -43,35 +41,11 @@ public class PasswordEncryptor implements SebConfigCryptor {
|
|||
Strategy.PASSWORD_PSWD,
|
||||
Strategy.PASSWORD_PWCC);
|
||||
|
||||
private final JNCryptor jnCryptor;
|
||||
|
||||
protected PasswordEncryptor(final JNCryptor jnCryptor) {
|
||||
this.jnCryptor = jnCryptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Strategy> strategies() {
|
||||
return STRATEGIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ByteBuffer> encrypt(final CharSequence plainTextConfig, final SebConfigEncryptionContext context) {
|
||||
return Result.tryCatch(() -> {
|
||||
return ByteBuffer.wrap(this.jnCryptor.encryptData(
|
||||
Utils.toByteArray(plainTextConfig),
|
||||
Utils.toCharArray(context.getPassword())));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ByteBuffer> decrypt(final ByteBuffer cipher, final SebConfigEncryptionContext context) {
|
||||
return Result.tryCatch(() -> {
|
||||
return ByteBuffer.wrap(this.jnCryptor.decryptData(
|
||||
Utils.toByteArray(cipher),
|
||||
Utils.toCharArray(context.getPassword())));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
public void encrypt(
|
||||
|
@ -80,7 +54,7 @@ public class PasswordEncryptor implements SebConfigCryptor {
|
|||
final SebConfigEncryptionContext context) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous encryption of SEB exam configuration data");
|
||||
log.debug("*** Start streaming asynchronous encryption");
|
||||
}
|
||||
|
||||
AES256JNCryptorOutputStream encryptOutput = null;
|
||||
|
@ -88,17 +62,17 @@ public class PasswordEncryptor implements SebConfigCryptor {
|
|||
|
||||
encryptOutput = new AES256JNCryptorOutputStream(
|
||||
output,
|
||||
Utils.toCharArray(context.getPassword()));
|
||||
Utils.toCharArray(context.getPassword()),
|
||||
10000);
|
||||
|
||||
IOUtils.copyLarge(input, encryptOutput);
|
||||
|
||||
encryptOutput.close();
|
||||
input.close();
|
||||
encryptOutput.flush();
|
||||
encryptOutput.close();
|
||||
output.flush();
|
||||
|
||||
} catch (final CryptorException e) {
|
||||
log.error("Error while trying to stream and encrypt seb exam configuration data: ", e);
|
||||
log.error("Error while trying to stream and encrypt data: ", e);
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while trying to read/write form/to streams: ", e);
|
||||
} finally {
|
||||
|
@ -110,7 +84,7 @@ public class PasswordEncryptor implements SebConfigCryptor {
|
|||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Finish streaming asynchronous encryption of SEB exam configuration data");
|
||||
log.debug("*** Finish streaming asynchronous encryption");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -118,11 +92,42 @@ public class PasswordEncryptor implements SebConfigCryptor {
|
|||
@Override
|
||||
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
|
||||
public void decrypt(
|
||||
final OutputStream plainTextOutput,
|
||||
final InputStream cipherInputStream,
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final SebConfigEncryptionContext context) {
|
||||
|
||||
// TODO Auto-generated method stub
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Start streaming asynchronous decryption");
|
||||
}
|
||||
|
||||
AES256JNCryptorInputStream encryptInput = null;
|
||||
try {
|
||||
|
||||
encryptInput = new AES256JNCryptorInputStream(
|
||||
input,
|
||||
Utils.toCharArray(context.getPassword()));
|
||||
|
||||
IOUtils.copyLarge(encryptInput, output);
|
||||
|
||||
input.close();
|
||||
encryptInput.close();
|
||||
output.flush();
|
||||
output.close();
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while trying to read/write form/to streams: ", e);
|
||||
} finally {
|
||||
try {
|
||||
if (encryptInput != null)
|
||||
encryptInput.close();
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to close AES256JNCryptorOutputStream: ", e);
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Finish streaming asynchronous decryption");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -31,7 +29,6 @@ import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
|||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentialService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO;
|
||||
|
@ -40,6 +37,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebClientConfigSe
|
|||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ZipService;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl.SebConfigEncryptionServiceImpl.EncryptionContext;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
|
@ -147,6 +145,7 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
PipedOutputStream pOut = null;
|
||||
PipedInputStream pIn = null;
|
||||
try {
|
||||
|
||||
// zip the plain text
|
||||
final InputStream plainIn = IOUtils.toInputStream(plainTextConfig, "UTF-8");
|
||||
pOut = new PipedOutputStream();
|
||||
|
@ -157,7 +156,10 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
if (encryptionPassword != null) {
|
||||
passwordEncryption(output, encryptionPassword, pIn);
|
||||
} else {
|
||||
noEncryption(output, plainTextConfig);
|
||||
this.sebConfigEncryptionService.streamEncrypted(
|
||||
output,
|
||||
pIn,
|
||||
EncryptionContext.contextOfPlainText());
|
||||
}
|
||||
|
||||
} catch (final Exception e) {
|
||||
|
@ -177,21 +179,6 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
}
|
||||
}
|
||||
|
||||
private void noEncryption(
|
||||
final OutputStream output,
|
||||
final String plainTextConfig) throws IOException {
|
||||
|
||||
log.debug("Serve plain text seb configuration with specified header");
|
||||
|
||||
final ByteBuffer encryptedConfig = this.sebConfigEncryptionService.plainText(plainTextConfig)
|
||||
.getOrThrow();
|
||||
|
||||
IOUtils.copyLarge(
|
||||
new ByteArrayInputStream(Utils.toByteArray(encryptedConfig)),
|
||||
output);
|
||||
|
||||
}
|
||||
|
||||
private void passwordEncryption(
|
||||
final OutputStream output,
|
||||
final CharSequence encryptionPassword,
|
||||
|
@ -204,11 +191,12 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
final CharSequence encryptionPasswordPlaintext = this.clientCredentialService
|
||||
.decrypt(encryptionPassword);
|
||||
|
||||
this.sebConfigEncryptionService.streamEncryption(
|
||||
this.sebConfigEncryptionService.streamEncrypted(
|
||||
output,
|
||||
input,
|
||||
Strategy.PASSWORD_PSWD,
|
||||
encryptionPasswordPlaintext);
|
||||
EncryptionContext.contextOf(
|
||||
Strategy.PASSWORD_PSWD,
|
||||
encryptionPasswordPlaintext));
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("*** Finished Seb client configuration with password based encryption");
|
||||
|
|
|
@ -13,7 +13,6 @@ import java.io.InputStream;
|
|||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
@ -31,7 +30,6 @@ import org.springframework.stereotype.Service;
|
|||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
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;
|
||||
|
@ -57,27 +55,24 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ByteBuffer> plainText(final CharSequence plainTextConfig) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("No encryption, use plain text with header");
|
||||
}
|
||||
|
||||
return Result.tryCatch(() -> {
|
||||
return addHeader(
|
||||
Utils.toByteBuffer(plainTextConfig),
|
||||
Strategy.PLAIN_TEXT);
|
||||
});
|
||||
}
|
||||
// @Override
|
||||
// public void streamPlainData(
|
||||
// final OutputStream output,
|
||||
// final InputStream input) {
|
||||
//
|
||||
//
|
||||
// getEncryptor(strategy)
|
||||
// .getOrThrow()
|
||||
// .encrypt(pout, input, context);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void streamEncryption(
|
||||
public void streamEncrypted(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final Strategy strategy,
|
||||
final CharSequence password) {
|
||||
final SebConfigEncryptionContext context) {
|
||||
|
||||
final Strategy strategy = context.getStrategy();
|
||||
PipedOutputStream pout = null;
|
||||
PipedInputStream pin = null;
|
||||
try {
|
||||
|
@ -91,26 +86,27 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
pout.write(strategy.header);
|
||||
getEncryptor(strategy)
|
||||
.getOrThrow()
|
||||
.encrypt(pout,
|
||||
input,
|
||||
EncryptionContext.contextOf(strategy, password));
|
||||
.encrypt(pout, input, context);
|
||||
|
||||
IOUtils.copyLarge(pin, output);
|
||||
|
||||
pin.close();
|
||||
pout.flush();
|
||||
pout.close();
|
||||
output.flush();
|
||||
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while stream encrypted data: ", e);
|
||||
} finally {
|
||||
try {
|
||||
pin.close();
|
||||
if (pin != null)
|
||||
pin.close();
|
||||
} catch (final IOException e1) {
|
||||
log.error("Failed to close PipedInputStream: ", e1);
|
||||
}
|
||||
try {
|
||||
pout.close();
|
||||
if (pout != null)
|
||||
pout.close();
|
||||
} catch (final IOException e1) {
|
||||
log.error("Failed to close PipedOutputStream: ", e1);
|
||||
}
|
||||
|
@ -118,95 +114,72 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
}
|
||||
|
||||
@Override
|
||||
public Result<ByteBuffer> encryptWithCertificate(
|
||||
final CharSequence plainTextConfig,
|
||||
final Strategy strategy,
|
||||
final Certificate certificate) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Certificate encryption with strategy: {}", strategy);
|
||||
}
|
||||
|
||||
return getEncryptor(strategy)
|
||||
.flatMap(encryptor -> encryptor.encrypt(
|
||||
plainTextConfig,
|
||||
EncryptionContext.contextOf(strategy, certificate)))
|
||||
.map(bb -> addHeader(bb, strategy));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<ByteBuffer> decrypt(
|
||||
final ByteBuffer cipher,
|
||||
public void streamDecrypted(
|
||||
final OutputStream output,
|
||||
final InputStream input,
|
||||
final Supplier<CharSequence> passwordSupplier,
|
||||
final Function<CharSequence, Certificate> certificateStore) {
|
||||
|
||||
return verifyStrategy(cipher)
|
||||
.flatMap(strategy -> decrypt(strategy, cipher, passwordSupplier, certificateStore));
|
||||
}
|
||||
PipedOutputStream pout = null;
|
||||
PipedInputStream pin = null;
|
||||
try {
|
||||
pout = new PipedOutputStream();
|
||||
pin = new PipedInputStream(pout);
|
||||
|
||||
private Result<ByteBuffer> decrypt(
|
||||
final Strategy strategy,
|
||||
final ByteBuffer cipher,
|
||||
final Supplier<CharSequence> passwordSupplier,
|
||||
final Function<CharSequence, Certificate> certificateStore) {
|
||||
final Strategy strategy = verifyStrategy(input);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Decryption with strategy: {}", strategy);
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Password decryption with strategy: {}", strategy);
|
||||
}
|
||||
|
||||
if (strategy == Strategy.PLAIN_TEXT) {
|
||||
return Result.of(removeHeader(cipher, strategy));
|
||||
}
|
||||
final EncryptionContext context = new EncryptionContext(
|
||||
strategy,
|
||||
(passwordSupplier != null) ? passwordSupplier.get() : null,
|
||||
certificateStore);
|
||||
|
||||
return getEncryptor(strategy)
|
||||
.flatMap(encryptor -> encryptor.decrypt(
|
||||
removeHeader(cipher, strategy),
|
||||
(strategy.type == Type.PASSWORD)
|
||||
? EncryptionContext.contextOf(strategy, passwordSupplier.get())
|
||||
: EncryptionContext.contextOf(strategy, certificateStore)));
|
||||
}
|
||||
getEncryptor(strategy)
|
||||
.getOrThrow()
|
||||
.decrypt(pout, input, context);
|
||||
|
||||
private ByteBuffer addHeader(final ByteBuffer input, final Strategy strategy) {
|
||||
final ByteBuffer _input = (input == null) ? ByteBuffer.allocate(0) : input;
|
||||
IOUtils.copyLarge(pin, output);
|
||||
|
||||
_input.rewind();
|
||||
final ByteBuffer buffer = ByteBuffer.allocate(
|
||||
SebConfigEncryptionServiceImpl.HEADER_SIZE +
|
||||
_input.limit());
|
||||
pin.close();
|
||||
pout.flush();
|
||||
pout.close();
|
||||
output.flush();
|
||||
|
||||
buffer.put(strategy.header);
|
||||
buffer.put(_input);
|
||||
return buffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
private ByteBuffer removeHeader(final ByteBuffer input, final Strategy strategy) {
|
||||
input.rewind();
|
||||
final byte[] header = new byte[SebConfigEncryptionServiceImpl.HEADER_SIZE];
|
||||
input.get(header);
|
||||
|
||||
if (Arrays.equals(strategy.header, header)) {
|
||||
final byte[] b = new byte[input.remaining()];
|
||||
input.get(b);
|
||||
return ByteBuffer.wrap(b).asReadOnlyBuffer();
|
||||
} else {
|
||||
input.clear();
|
||||
return input.asReadOnlyBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
private Result<Strategy> verifyStrategy(final ByteBuffer cipher) {
|
||||
cipher.rewind();
|
||||
final byte[] header = new byte[HEADER_SIZE];
|
||||
cipher.get(header);
|
||||
//final String headerString = Utils.toString(header);
|
||||
for (final Strategy s : Strategy.values()) {
|
||||
if (Arrays.equals(s.header, header)) {
|
||||
return Result.of(s);
|
||||
} catch (final IOException e) {
|
||||
log.error("Error while stream decrypted data: ", e);
|
||||
} finally {
|
||||
try {
|
||||
if (pin != null)
|
||||
pin.close();
|
||||
} catch (final IOException e1) {
|
||||
log.error("Failed to close PipedInputStream: ", e1);
|
||||
}
|
||||
try {
|
||||
if (pout != null)
|
||||
pout.close();
|
||||
} catch (final IOException e1) {
|
||||
log.error("Failed to close PipedOutputStream: ", e1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.error("Failed to verify encryption strategy. Fallback to plain text strategy");
|
||||
return Result.of(Strategy.PLAIN_TEXT);
|
||||
private Strategy verifyStrategy(final InputStream input) {
|
||||
try {
|
||||
final byte[] header = new byte[HEADER_SIZE];
|
||||
input.read(header);
|
||||
for (final Strategy s : Strategy.values()) {
|
||||
if (Arrays.equals(s.header, header)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Failed to verify decryption strategy from input stream");
|
||||
} catch (final IOException e) {
|
||||
log.error("Failed to read decryption strategy from input stream");
|
||||
throw new IllegalStateException("Failed to verify decryption strategy from input stream");
|
||||
}
|
||||
}
|
||||
|
||||
private Result<SebConfigCryptor> getEncryptor(final Strategy strategy) {
|
||||
|
@ -218,21 +191,20 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
return Result.of(encryptor);
|
||||
}
|
||||
|
||||
protected static class EncryptionContext implements SebConfigEncryptionContext {
|
||||
static class EncryptionContext implements SebConfigEncryptionContext {
|
||||
|
||||
public final Strategy strategy;
|
||||
public final CharSequence password;
|
||||
public final Certificate certificate;
|
||||
public final Function<CharSequence, Certificate> certificateStore;
|
||||
|
||||
private EncryptionContext(
|
||||
final Strategy strategy,
|
||||
final CharSequence password,
|
||||
final Certificate certificate,
|
||||
final Function<CharSequence, Certificate> certificateStore) {
|
||||
|
||||
this.strategy = strategy;
|
||||
this.password = password;
|
||||
this.certificate = certificate;
|
||||
this.certificateStore = certificateStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -246,18 +218,16 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
}
|
||||
|
||||
@Override
|
||||
public Certificate getCertificate() {
|
||||
return this.certificate;
|
||||
public Certificate getCertificate(final CharSequence key) {
|
||||
if (this.certificateStore == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return this.certificateStore.apply(key);
|
||||
}
|
||||
|
||||
static SebConfigEncryptionContext contextOf(final Strategy strategy, final CharSequence password) {
|
||||
checkPasswordbased(strategy);
|
||||
return new EncryptionContext(strategy, password, null, null);
|
||||
}
|
||||
|
||||
static SebConfigEncryptionContext contextOf(final Strategy strategy, final Certificate certificate) {
|
||||
checkCertificateBased(strategy);
|
||||
return new EncryptionContext(strategy, null, certificate, null);
|
||||
return new EncryptionContext(strategy, password, null);
|
||||
}
|
||||
|
||||
static SebConfigEncryptionContext contextOf(
|
||||
|
@ -265,7 +235,7 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
final Function<CharSequence, Certificate> certificateStore) {
|
||||
|
||||
checkCertificateBased(strategy);
|
||||
return new EncryptionContext(strategy, null, null, certificateStore);
|
||||
return new EncryptionContext(strategy, null, certificateStore);
|
||||
}
|
||||
|
||||
static void checkPasswordbased(final Strategy strategy) {
|
||||
|
@ -280,6 +250,10 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
|
|||
}
|
||||
}
|
||||
|
||||
public static SebConfigEncryptionContext contextOfPlainText() {
|
||||
return new EncryptionContext(Strategy.PLAIN_TEXT, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,10 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -22,7 +22,6 @@ import org.cryptonode.jncryptor.AES256JNCryptorOutputStream;
|
|||
import org.cryptonode.jncryptor.JNCryptor;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionContext;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy;
|
||||
|
@ -45,7 +44,7 @@ public class PasswordEncryptorTest {
|
|||
public void testUsingPassword() throws Exception {
|
||||
|
||||
final String config = "<TestConfig></TestConfig>";
|
||||
final byte[] plaintext = Utils.toByteArray(config);//getRandomBytes(127);
|
||||
final byte[] plaintext = Utils.toByteArray(config);
|
||||
|
||||
final String password = "Testing1234";
|
||||
|
||||
|
@ -63,36 +62,9 @@ public class PasswordEncryptorTest {
|
|||
assertArrayEquals(plaintext, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test1() {
|
||||
final JNCryptor jnCryptor = new AES256JNCryptor();
|
||||
jnCryptor.setPBKDFIterations(10000);
|
||||
final PasswordEncryptor encryptor = new PasswordEncryptor(jnCryptor);
|
||||
|
||||
final String config = "<TestConfig></TestConfig>";
|
||||
final String pwd = "password";
|
||||
|
||||
final SebConfigEncryptionContext context = EncryptionContext.contextOf(
|
||||
Strategy.PASSWORD_PWCC,
|
||||
pwd);
|
||||
|
||||
final Result<ByteBuffer> encrypt = encryptor.encrypt(config, context);
|
||||
assertFalse(encrypt.hasError());
|
||||
final ByteBuffer cipher = encrypt.getOrThrow();
|
||||
final byte[] byteArray = Utils.toByteArray(cipher);
|
||||
|
||||
final Result<ByteBuffer> decrypt = encryptor.decrypt(cipher, context);
|
||||
assertFalse(decrypt.hasError());
|
||||
|
||||
final String decryptedConfig = Utils.toString(decrypt.getOrThrow());
|
||||
assertEquals(config, decryptedConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test2() throws IOException {
|
||||
final JNCryptor jnCryptor = new AES256JNCryptor();
|
||||
jnCryptor.setPBKDFIterations(10000);
|
||||
final PasswordEncryptor encryptor = new PasswordEncryptor(jnCryptor);
|
||||
final PasswordEncryptor encryptor = new PasswordEncryptor();
|
||||
|
||||
final String config = "<TestConfig></TestConfig>";
|
||||
final String pwd = "password";
|
||||
|
@ -109,14 +81,16 @@ public class PasswordEncryptorTest {
|
|||
|
||||
final byte[] byteArray = out.toByteArray();
|
||||
|
||||
final Result<ByteBuffer> decrypt = encryptor.decrypt(
|
||||
ByteBuffer.wrap(byteArray),
|
||||
final ByteArrayOutputStream out2 = new ByteArrayOutputStream(512);
|
||||
encryptor.decrypt(
|
||||
out2,
|
||||
new ByteArrayInputStream(byteArray),
|
||||
context);
|
||||
assertFalse(decrypt.hasError());
|
||||
|
||||
final ByteBuffer buffer = decrypt.getOrThrow();
|
||||
buffer.rewind();
|
||||
final String decryptedConfig = Utils.toString(buffer);
|
||||
final byte[] byteArray2 = out2.toByteArray();
|
||||
assertNotNull(byteArray2);
|
||||
|
||||
final String decryptedConfig = new String(byteArray2, "UTF-8");
|
||||
assertEquals(config, decryptedConfig);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
|
|||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
@ -17,31 +18,44 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.cryptonode.jncryptor.AES256JNCryptor;
|
||||
import org.cryptonode.jncryptor.JNCryptor;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigCryptor;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy;
|
||||
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl.SebConfigEncryptionServiceImpl.EncryptionContext;
|
||||
|
||||
public class SebConfigEncryptionServiceImplTest {
|
||||
|
||||
@Test
|
||||
public void testPlainText() {
|
||||
public void testPlainText() throws IOException {
|
||||
final SebConfigEncryptionServiceImpl sebConfigEncryptionServiceImpl = sebConfigEncryptionServiceImpl();
|
||||
|
||||
final String config = "<TestConfig></TestConfig>";
|
||||
|
||||
final Result<ByteBuffer> plainText = sebConfigEncryptionServiceImpl.plainText(config);
|
||||
assertFalse(plainText.hasError());
|
||||
final ByteBuffer cipher = plainText.get();
|
||||
assertEquals("plnd<TestConfig></TestConfig>", Utils.toString(cipher));
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
sebConfigEncryptionServiceImpl
|
||||
.streamEncrypted(
|
||||
out,
|
||||
IOUtils.toInputStream(config, "UTF-8"),
|
||||
EncryptionContext.contextOfPlainText());
|
||||
|
||||
final Result<ByteBuffer> decrypt = sebConfigEncryptionServiceImpl.decrypt(cipher, null, null);
|
||||
assertFalse(decrypt.hasError());
|
||||
assertEquals("<TestConfig></TestConfig>", Utils.toString(decrypt.get()));
|
||||
final byte[] plainWithHeader = out.toByteArray();
|
||||
assertNotNull(plainWithHeader);
|
||||
assertEquals("plnd<TestConfig></TestConfig>", Utils.toString(plainWithHeader));
|
||||
|
||||
final ByteArrayOutputStream out2 = new ByteArrayOutputStream(512);
|
||||
sebConfigEncryptionServiceImpl.streamDecrypted(
|
||||
out2,
|
||||
new ByteArrayInputStream(plainWithHeader),
|
||||
null,
|
||||
null);
|
||||
|
||||
final byte[] byteArray2 = out2.toByteArray();
|
||||
assertNotNull(byteArray2);
|
||||
|
||||
final String decryptedConfig = new String(byteArray2, "UTF-8");
|
||||
assertEquals(config, decryptedConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -53,11 +67,12 @@ public class SebConfigEncryptionServiceImplTest {
|
|||
|
||||
final ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
|
||||
sebConfigEncryptionServiceImpl.streamEncryption(
|
||||
sebConfigEncryptionServiceImpl.streamEncrypted(
|
||||
out,
|
||||
IOUtils.toInputStream(config, "UTF-8"),
|
||||
Strategy.PASSWORD_PWCC,
|
||||
pwd);
|
||||
EncryptionContext.contextOf(
|
||||
Strategy.PASSWORD_PWCC,
|
||||
pwd));
|
||||
|
||||
final byte[] byteArray = out.toByteArray();
|
||||
|
||||
|
@ -65,17 +80,24 @@ public class SebConfigEncryptionServiceImplTest {
|
|||
final ByteBuffer cipher = ByteBuffer.wrap(byteArray);
|
||||
assertTrue(Utils.toString(cipher).startsWith(Utils.toString(Strategy.PASSWORD_PWCC.header)));
|
||||
|
||||
final Result<ByteBuffer> decrypt = sebConfigEncryptionServiceImpl.decrypt(cipher, () -> pwd, null);
|
||||
assertFalse(decrypt.hasError());
|
||||
assertEquals("<TestConfig></TestConfig>", Utils.toString(decrypt.get()));
|
||||
final ByteArrayOutputStream out2 = new ByteArrayOutputStream(512);
|
||||
sebConfigEncryptionServiceImpl.streamDecrypted(
|
||||
out2,
|
||||
new ByteArrayInputStream(byteArray),
|
||||
() -> pwd,
|
||||
null);
|
||||
|
||||
final byte[] byteArray2 = out2.toByteArray();
|
||||
assertNotNull(byteArray2);
|
||||
|
||||
final String decryptedConfig = new String(byteArray2, "UTF-8");
|
||||
assertEquals(config, decryptedConfig);
|
||||
}
|
||||
|
||||
private SebConfigEncryptionServiceImpl sebConfigEncryptionServiceImpl() {
|
||||
final JNCryptor jnCryptor = new AES256JNCryptor();
|
||||
jnCryptor.setPBKDFIterations(10000);
|
||||
|
||||
final List<SebConfigCryptor> encryptors = Arrays.asList(
|
||||
new PasswordEncryptor(jnCryptor));
|
||||
new PasswordEncryptor(),
|
||||
new NoneEncryptor());
|
||||
return new SebConfigEncryptionServiceImpl(encryptors);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue