finished config streaming out/in

This commit is contained in:
anhefti 2019-05-11 21:42:33 +02:00
parent 06da2d026b
commit 27b75062cc
12 changed files with 326 additions and 309 deletions

View file

@ -8,14 +8,8 @@
package ch.ethz.seb.sebserver.gbl.async; 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 java.util.function.Supplier;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -72,41 +66,4 @@ public class AsyncService {
momoized); 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);
}
}
});
}
} }

View file

@ -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 /** Use this to map a given Result of type T to another Result of type U
* within a given mapping function. * within a given mapping function.
* *

View file

@ -10,10 +10,8 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Set; import java.util.Set;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy;
/** Interface for a SEB Configuration encryption and decryption 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 */ * @return Set of strategies a concrete implementation is supporting */
Set<Strategy> strategies(); 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( void encrypt(
final OutputStream encryptedOutput, final OutputStream output,
final InputStream plainTextInputStream, final InputStream input,
final SebConfigEncryptionContext context); final SebConfigEncryptionContext context);
void decrypt( void decrypt(
final OutputStream plainTextOutput, final OutputStream output,
final InputStream cipherInputStream, final InputStream input,
final SebConfigEncryptionContext context); final SebConfigEncryptionContext context);
} }

View file

@ -29,8 +29,9 @@ public interface SebConfigEncryptionContext {
/** Get a defined Certificate if supported. /** Get a defined Certificate if supported.
* *
* @param key The key of the Certificate to get
* @return a defined Certificate * @return a defined Certificate
* @throws UnsupportedOperationException if not supported */ * @throws UnsupportedOperationException if not supported */
Certificate getCertificate(); Certificate getCertificate(CharSequence key);
} }

View file

@ -10,12 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils; import ch.ethz.seb.sebserver.gbl.util.Utils;
public interface SebConfigEncryptionService { public interface SebConfigEncryptionService {
@ -60,21 +58,18 @@ public interface SebConfigEncryptionService {
* @param plainTextConfig plainTextConfig plain text SEB Configuration as CharSequence * @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 * @return Result of plain text SEB Configuration within a ByteBuffer or a reference to an Exception on error
* case */ * case */
Result<ByteBuffer> plainText(CharSequence plainTextConfig); // void streamPlainData(
// final OutputStream output,
// final InputStream input);
void streamEncryption( void streamEncrypted(
final OutputStream output, final OutputStream output,
final InputStream input, final InputStream input,
final Strategy strategy, SebConfigEncryptionContext context);
final CharSequence password);
Result<ByteBuffer> encryptWithCertificate( void streamDecrypted(
CharSequence plainTextConfig, final OutputStream output,
Strategy strategy, final InputStream input,
Certificate certificate);
Result<ByteBuffer> decrypt(
ByteBuffer cipher,
Supplier<CharSequence> passwordSupplier, Supplier<CharSequence> passwordSupplier,
Function<CharSequence, Certificate> certificateStore); Function<CharSequence, Certificate> certificateStore);

View file

@ -16,4 +16,5 @@ public interface ZipService {
void write(OutputStream out, InputStream in); void write(OutputStream out, InputStream in);
void read(OutputStream out, InputStream in); void read(OutputStream out, InputStream in);
} }

View file

@ -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");
}
}
}
}

View file

@ -11,13 +11,12 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Set; import java.util.Set;
import org.apache.tomcat.util.http.fileupload.IOUtils; import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.cryptonode.jncryptor.AES256JNCryptorInputStream;
import org.cryptonode.jncryptor.AES256JNCryptorOutputStream; import org.cryptonode.jncryptor.AES256JNCryptorOutputStream;
import org.cryptonode.jncryptor.CryptorException; import org.cryptonode.jncryptor.CryptorException;
import org.cryptonode.jncryptor.JNCryptor;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; 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.async.AsyncServiceSpringConfig;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; 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.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigCryptor; 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.SebConfigEncryptionContext;
@ -43,35 +41,11 @@ public class PasswordEncryptor implements SebConfigCryptor {
Strategy.PASSWORD_PSWD, Strategy.PASSWORD_PSWD,
Strategy.PASSWORD_PWCC); Strategy.PASSWORD_PWCC);
private final JNCryptor jnCryptor;
protected PasswordEncryptor(final JNCryptor jnCryptor) {
this.jnCryptor = jnCryptor;
}
@Override @Override
public Set<Strategy> strategies() { public Set<Strategy> strategies() {
return 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 @Override
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
public void encrypt( public void encrypt(
@ -80,7 +54,7 @@ public class PasswordEncryptor implements SebConfigCryptor {
final SebConfigEncryptionContext context) { final SebConfigEncryptionContext context) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("*** Start streaming asynchronous encryption of SEB exam configuration data"); log.debug("*** Start streaming asynchronous encryption");
} }
AES256JNCryptorOutputStream encryptOutput = null; AES256JNCryptorOutputStream encryptOutput = null;
@ -88,17 +62,17 @@ public class PasswordEncryptor implements SebConfigCryptor {
encryptOutput = new AES256JNCryptorOutputStream( encryptOutput = new AES256JNCryptorOutputStream(
output, output,
Utils.toCharArray(context.getPassword())); Utils.toCharArray(context.getPassword()),
10000);
IOUtils.copyLarge(input, encryptOutput); IOUtils.copyLarge(input, encryptOutput);
encryptOutput.close(); input.close();
encryptOutput.flush(); encryptOutput.flush();
encryptOutput.close(); encryptOutput.close();
output.flush();
} catch (final CryptorException e) { } 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) { } catch (final IOException e) {
log.error("Error while trying to read/write form/to streams: ", e); log.error("Error while trying to read/write form/to streams: ", e);
} finally { } finally {
@ -110,7 +84,7 @@ public class PasswordEncryptor implements SebConfigCryptor {
} }
if (log.isDebugEnabled()) { 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 @Override
@Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME) @Async(AsyncServiceSpringConfig.EXECUTOR_BEAN_NAME)
public void decrypt( public void decrypt(
final OutputStream plainTextOutput, final OutputStream output,
final InputStream cipherInputStream, final InputStream input,
final SebConfigEncryptionContext context) { 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");
}
}
} }

View file

@ -8,13 +8,11 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl; package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.nio.ByteBuffer;
import java.util.Collection; import java.util.Collection;
import java.util.UUID; 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.model.sebconfig.SebClientConfig;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; 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.ClientCredentialService;
import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials; import ch.ethz.seb.sebserver.webservice.servicelayer.client.ClientCredentials;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.InstitutionDAO; 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;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy; 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.ZipService;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl.SebConfigEncryptionServiceImpl.EncryptionContext;
@Lazy @Lazy
@Service @Service
@ -147,6 +145,7 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
PipedOutputStream pOut = null; PipedOutputStream pOut = null;
PipedInputStream pIn = null; PipedInputStream pIn = null;
try { try {
// zip the plain text // zip the plain text
final InputStream plainIn = IOUtils.toInputStream(plainTextConfig, "UTF-8"); final InputStream plainIn = IOUtils.toInputStream(plainTextConfig, "UTF-8");
pOut = new PipedOutputStream(); pOut = new PipedOutputStream();
@ -157,7 +156,10 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
if (encryptionPassword != null) { if (encryptionPassword != null) {
passwordEncryption(output, encryptionPassword, pIn); passwordEncryption(output, encryptionPassword, pIn);
} else { } else {
noEncryption(output, plainTextConfig); this.sebConfigEncryptionService.streamEncrypted(
output,
pIn,
EncryptionContext.contextOfPlainText());
} }
} catch (final Exception e) { } 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( private void passwordEncryption(
final OutputStream output, final OutputStream output,
final CharSequence encryptionPassword, final CharSequence encryptionPassword,
@ -204,11 +191,12 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
final CharSequence encryptionPasswordPlaintext = this.clientCredentialService final CharSequence encryptionPasswordPlaintext = this.clientCredentialService
.decrypt(encryptionPassword); .decrypt(encryptionPassword);
this.sebConfigEncryptionService.streamEncryption( this.sebConfigEncryptionService.streamEncrypted(
output, output,
input, input,
Strategy.PASSWORD_PSWD, EncryptionContext.contextOf(
encryptionPasswordPlaintext); Strategy.PASSWORD_PSWD,
encryptionPasswordPlaintext));
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("*** Finished Seb client configuration with password based encryption"); log.debug("*** Finished Seb client configuration with password based encryption");

View file

@ -13,7 +13,6 @@ import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PipedInputStream; import java.io.PipedInputStream;
import java.io.PipedOutputStream; import java.io.PipedOutputStream;
import java.nio.ByteBuffer;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; 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.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; 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.SebConfigCryptor;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionContext; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionContext;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService;
@ -57,27 +55,24 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
} }
@Override // @Override
public Result<ByteBuffer> plainText(final CharSequence plainTextConfig) { // public void streamPlainData(
// final OutputStream output,
if (log.isDebugEnabled()) { // final InputStream input) {
log.debug("No encryption, use plain text with header"); //
} //
// getEncryptor(strategy)
return Result.tryCatch(() -> { // .getOrThrow()
return addHeader( // .encrypt(pout, input, context);
Utils.toByteBuffer(plainTextConfig), // }
Strategy.PLAIN_TEXT);
});
}
@Override @Override
public void streamEncryption( public void streamEncrypted(
final OutputStream output, final OutputStream output,
final InputStream input, final InputStream input,
final Strategy strategy, final SebConfigEncryptionContext context) {
final CharSequence password) {
final Strategy strategy = context.getStrategy();
PipedOutputStream pout = null; PipedOutputStream pout = null;
PipedInputStream pin = null; PipedInputStream pin = null;
try { try {
@ -91,26 +86,27 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
pout.write(strategy.header); pout.write(strategy.header);
getEncryptor(strategy) getEncryptor(strategy)
.getOrThrow() .getOrThrow()
.encrypt(pout, .encrypt(pout, input, context);
input,
EncryptionContext.contextOf(strategy, password));
IOUtils.copyLarge(pin, output); IOUtils.copyLarge(pin, output);
pin.close(); pin.close();
pout.flush(); pout.flush();
pout.close(); pout.close();
output.flush();
} catch (final IOException e) { } catch (final IOException e) {
log.error("Error while stream encrypted data: ", e); log.error("Error while stream encrypted data: ", e);
} finally { } finally {
try { try {
pin.close(); if (pin != null)
pin.close();
} catch (final IOException e1) { } catch (final IOException e1) {
log.error("Failed to close PipedInputStream: ", e1); log.error("Failed to close PipedInputStream: ", e1);
} }
try { try {
pout.close(); if (pout != null)
pout.close();
} catch (final IOException e1) { } catch (final IOException e1) {
log.error("Failed to close PipedOutputStream: ", e1); log.error("Failed to close PipedOutputStream: ", e1);
} }
@ -118,95 +114,72 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
} }
@Override @Override
public Result<ByteBuffer> encryptWithCertificate( public void streamDecrypted(
final CharSequence plainTextConfig, final OutputStream output,
final Strategy strategy, final InputStream input,
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,
final Supplier<CharSequence> passwordSupplier, final Supplier<CharSequence> passwordSupplier,
final Function<CharSequence, Certificate> certificateStore) { final Function<CharSequence, Certificate> certificateStore) {
return verifyStrategy(cipher) PipedOutputStream pout = null;
.flatMap(strategy -> decrypt(strategy, cipher, passwordSupplier, certificateStore)); PipedInputStream pin = null;
} try {
pout = new PipedOutputStream();
pin = new PipedInputStream(pout);
private Result<ByteBuffer> decrypt( final Strategy strategy = verifyStrategy(input);
final Strategy strategy,
final ByteBuffer cipher,
final Supplier<CharSequence> passwordSupplier,
final Function<CharSequence, Certificate> certificateStore) {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Decryption with strategy: {}", strategy); log.debug("Password decryption with strategy: {}", strategy);
} }
if (strategy == Strategy.PLAIN_TEXT) { final EncryptionContext context = new EncryptionContext(
return Result.of(removeHeader(cipher, strategy)); strategy,
} (passwordSupplier != null) ? passwordSupplier.get() : null,
certificateStore);
return getEncryptor(strategy) getEncryptor(strategy)
.flatMap(encryptor -> encryptor.decrypt( .getOrThrow()
removeHeader(cipher, strategy), .decrypt(pout, input, context);
(strategy.type == Type.PASSWORD)
? EncryptionContext.contextOf(strategy, passwordSupplier.get())
: EncryptionContext.contextOf(strategy, certificateStore)));
}
private ByteBuffer addHeader(final ByteBuffer input, final Strategy strategy) { IOUtils.copyLarge(pin, output);
final ByteBuffer _input = (input == null) ? ByteBuffer.allocate(0) : input;
_input.rewind(); pin.close();
final ByteBuffer buffer = ByteBuffer.allocate( pout.flush();
SebConfigEncryptionServiceImpl.HEADER_SIZE + pout.close();
_input.limit()); output.flush();
buffer.put(strategy.header); } catch (final IOException e) {
buffer.put(_input); log.error("Error while stream decrypted data: ", e);
return buffer.asReadOnlyBuffer(); } finally {
} try {
if (pin != null)
private ByteBuffer removeHeader(final ByteBuffer input, final Strategy strategy) { pin.close();
input.rewind(); } catch (final IOException e1) {
final byte[] header = new byte[SebConfigEncryptionServiceImpl.HEADER_SIZE]; log.error("Failed to close PipedInputStream: ", e1);
input.get(header); }
try {
if (Arrays.equals(strategy.header, header)) { if (pout != null)
final byte[] b = new byte[input.remaining()]; pout.close();
input.get(b); } catch (final IOException e1) {
return ByteBuffer.wrap(b).asReadOnlyBuffer(); log.error("Failed to close PipedOutputStream: ", e1);
} 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);
} }
} }
}
log.error("Failed to verify encryption strategy. Fallback to plain text strategy"); private Strategy verifyStrategy(final InputStream input) {
return Result.of(Strategy.PLAIN_TEXT); 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) { private Result<SebConfigCryptor> getEncryptor(final Strategy strategy) {
@ -218,21 +191,20 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
return Result.of(encryptor); return Result.of(encryptor);
} }
protected static class EncryptionContext implements SebConfigEncryptionContext { static class EncryptionContext implements SebConfigEncryptionContext {
public final Strategy strategy; public final Strategy strategy;
public final CharSequence password; public final CharSequence password;
public final Certificate certificate; public final Function<CharSequence, Certificate> certificateStore;
private EncryptionContext( private EncryptionContext(
final Strategy strategy, final Strategy strategy,
final CharSequence password, final CharSequence password,
final Certificate certificate,
final Function<CharSequence, Certificate> certificateStore) { final Function<CharSequence, Certificate> certificateStore) {
this.strategy = strategy; this.strategy = strategy;
this.password = password; this.password = password;
this.certificate = certificate; this.certificateStore = certificateStore;
} }
@Override @Override
@ -246,18 +218,16 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
} }
@Override @Override
public Certificate getCertificate() { public Certificate getCertificate(final CharSequence key) {
return this.certificate; if (this.certificateStore == null) {
throw new UnsupportedOperationException();
}
return this.certificateStore.apply(key);
} }
static SebConfigEncryptionContext contextOf(final Strategy strategy, final CharSequence password) { static SebConfigEncryptionContext contextOf(final Strategy strategy, final CharSequence password) {
checkPasswordbased(strategy); checkPasswordbased(strategy);
return new EncryptionContext(strategy, password, null, null); return new EncryptionContext(strategy, password, null);
}
static SebConfigEncryptionContext contextOf(final Strategy strategy, final Certificate certificate) {
checkCertificateBased(strategy);
return new EncryptionContext(strategy, null, certificate, null);
} }
static SebConfigEncryptionContext contextOf( static SebConfigEncryptionContext contextOf(
@ -265,7 +235,7 @@ public final class SebConfigEncryptionServiceImpl implements SebConfigEncryption
final Function<CharSequence, Certificate> certificateStore) { final Function<CharSequence, Certificate> certificateStore) {
checkCertificateBased(strategy); checkCertificateBased(strategy);
return new EncryptionContext(strategy, null, null, certificateStore); return new EncryptionContext(strategy, null, certificateStore);
} }
static void checkPasswordbased(final Strategy strategy) { 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);
}
} }
} }

View file

@ -10,10 +10,10 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@ -22,7 +22,6 @@ import org.cryptonode.jncryptor.AES256JNCryptorOutputStream;
import org.cryptonode.jncryptor.JNCryptor; import org.cryptonode.jncryptor.JNCryptor;
import org.junit.Test; 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.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionContext; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionContext;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigEncryptionService.Strategy;
@ -45,7 +44,7 @@ public class PasswordEncryptorTest {
public void testUsingPassword() throws Exception { public void testUsingPassword() throws Exception {
final String config = "<TestConfig></TestConfig>"; final String config = "<TestConfig></TestConfig>";
final byte[] plaintext = Utils.toByteArray(config);//getRandomBytes(127); final byte[] plaintext = Utils.toByteArray(config);
final String password = "Testing1234"; final String password = "Testing1234";
@ -63,36 +62,9 @@ public class PasswordEncryptorTest {
assertArrayEquals(plaintext, result); 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 @Test
public void test2() throws IOException { public void test2() throws IOException {
final JNCryptor jnCryptor = new AES256JNCryptor(); final PasswordEncryptor encryptor = new PasswordEncryptor();
jnCryptor.setPBKDFIterations(10000);
final PasswordEncryptor encryptor = new PasswordEncryptor(jnCryptor);
final String config = "<TestConfig></TestConfig>"; final String config = "<TestConfig></TestConfig>";
final String pwd = "password"; final String pwd = "password";
@ -109,14 +81,16 @@ public class PasswordEncryptorTest {
final byte[] byteArray = out.toByteArray(); final byte[] byteArray = out.toByteArray();
final Result<ByteBuffer> decrypt = encryptor.decrypt( final ByteArrayOutputStream out2 = new ByteArrayOutputStream(512);
ByteBuffer.wrap(byteArray), encryptor.decrypt(
out2,
new ByteArrayInputStream(byteArray),
context); context);
assertFalse(decrypt.hasError());
final ByteBuffer buffer = decrypt.getOrThrow(); final byte[] byteArray2 = out2.toByteArray();
buffer.rewind(); assertNotNull(byteArray2);
final String decryptedConfig = Utils.toString(buffer);
final String decryptedConfig = new String(byteArray2, "UTF-8");
assertEquals(config, decryptedConfig); assertEquals(config, decryptedConfig);
} }

View file

@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@ -17,31 +18,44 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.cryptonode.jncryptor.AES256JNCryptor;
import org.cryptonode.jncryptor.JNCryptor;
import org.junit.Test; 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.gbl.util.Utils;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebConfigCryptor; 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.SebConfigEncryptionService.Strategy;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl.SebConfigEncryptionServiceImpl.EncryptionContext;
public class SebConfigEncryptionServiceImplTest { public class SebConfigEncryptionServiceImplTest {
@Test @Test
public void testPlainText() { public void testPlainText() throws IOException {
final SebConfigEncryptionServiceImpl sebConfigEncryptionServiceImpl = sebConfigEncryptionServiceImpl(); final SebConfigEncryptionServiceImpl sebConfigEncryptionServiceImpl = sebConfigEncryptionServiceImpl();
final String config = "<TestConfig></TestConfig>"; final String config = "<TestConfig></TestConfig>";
final Result<ByteBuffer> plainText = sebConfigEncryptionServiceImpl.plainText(config); final ByteArrayOutputStream out = new ByteArrayOutputStream();
assertFalse(plainText.hasError()); sebConfigEncryptionServiceImpl
final ByteBuffer cipher = plainText.get(); .streamEncrypted(
assertEquals("plnd<TestConfig></TestConfig>", Utils.toString(cipher)); out,
IOUtils.toInputStream(config, "UTF-8"),
EncryptionContext.contextOfPlainText());
final Result<ByteBuffer> decrypt = sebConfigEncryptionServiceImpl.decrypt(cipher, null, null); final byte[] plainWithHeader = out.toByteArray();
assertFalse(decrypt.hasError()); assertNotNull(plainWithHeader);
assertEquals("<TestConfig></TestConfig>", Utils.toString(decrypt.get())); 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 @Test
@ -53,11 +67,12 @@ public class SebConfigEncryptionServiceImplTest {
final ByteArrayOutputStream out = new ByteArrayOutputStream(1024); final ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
sebConfigEncryptionServiceImpl.streamEncryption( sebConfigEncryptionServiceImpl.streamEncrypted(
out, out,
IOUtils.toInputStream(config, "UTF-8"), IOUtils.toInputStream(config, "UTF-8"),
Strategy.PASSWORD_PWCC, EncryptionContext.contextOf(
pwd); Strategy.PASSWORD_PWCC,
pwd));
final byte[] byteArray = out.toByteArray(); final byte[] byteArray = out.toByteArray();
@ -65,17 +80,24 @@ public class SebConfigEncryptionServiceImplTest {
final ByteBuffer cipher = ByteBuffer.wrap(byteArray); final ByteBuffer cipher = ByteBuffer.wrap(byteArray);
assertTrue(Utils.toString(cipher).startsWith(Utils.toString(Strategy.PASSWORD_PWCC.header))); assertTrue(Utils.toString(cipher).startsWith(Utils.toString(Strategy.PASSWORD_PWCC.header)));
final Result<ByteBuffer> decrypt = sebConfigEncryptionServiceImpl.decrypt(cipher, () -> pwd, null); final ByteArrayOutputStream out2 = new ByteArrayOutputStream(512);
assertFalse(decrypt.hasError()); sebConfigEncryptionServiceImpl.streamDecrypted(
assertEquals("<TestConfig></TestConfig>", Utils.toString(decrypt.get())); 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() { private SebConfigEncryptionServiceImpl sebConfigEncryptionServiceImpl() {
final JNCryptor jnCryptor = new AES256JNCryptor();
jnCryptor.setPBKDFIterations(10000);
final List<SebConfigCryptor> encryptors = Arrays.asList( final List<SebConfigCryptor> encryptors = Arrays.asList(
new PasswordEncryptor(jnCryptor)); new PasswordEncryptor(),
new NoneEncryptor());
return new SebConfigEncryptionServiceImpl(encryptors); return new SebConfigEncryptionServiceImpl(encryptors);
} }