/* Index ECM Engine - A system for managing the capture (when created
* or received), classification (cataloguing), storage, retrieval,
* revision, sharing, reuse and disposition of documents.
*
* Copyright (C) 2008 Regione Piemonte
* Copyright (C) 2008 Provincia di Torino
* Copyright (C) 2008 Comune di Torino
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
package it.doqui.index.ecmengine.business.personalization.encryption.content;
import it.doqui.index.ecmengine.business.personalization.encryption.CryptoTransformationSpec;
import it.doqui.index.ecmengine.business.personalization.encryption.EncryptingContentWriter;
import it.doqui.index.ecmengine.business.personalization.encryption.exception.EncryptionRuntimeException;
import it.doqui.index.ecmengine.business.personalization.encryption.util.EncryptionUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Locale;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.cmr.repository.ContentIOException;
import org.alfresco.service.cmr.repository.ContentReader;
import org.alfresco.service.cmr.repository.ContentStreamListener;
import org.alfresco.service.cmr.repository.ContentWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.FileCopyUtils;
public class EncryptingContentWriterDecorator implements EncryptingContentWriter {
private Log logger = LogFactory.getLog(EncryptionUtils.ENCRYPTION_LOG_CATEGORY);
private ContentWriter writer;
private SecretKey secretKey;
private CryptoTransformationSpec transformationSpec;
public EncryptingContentWriterDecorator(ContentWriter writer, SecretKey key, CryptoTransformationSpec transformationSpec) {
logger.debug("[EncryptingContentWriterDecorator::EncryptingContentWriter] BEGIN");
this.writer = writer;
this.secretKey = key;
this.transformationSpec = transformationSpec;
logger.debug("[EncryptingContentWriterDecorator::EncryptingContentWriter] END");
}
public OutputStream getContentOutputStream() throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::getContentOutputStream] BEGIN");
IvParameterSpec iv = null;
try {
Cipher cipher = null;
try {
cipher = Cipher.getInstance(CryptoTransformationSpec.buildTransformationString(transformationSpec), "SunJCE");
} catch (NoSuchProviderException e) {
logger.warn("[EncryptingContentWriterDecorator::getContentOutputStream] Unknown provider \"SunJCE\". Using default...");
cipher = Cipher.getInstance(CryptoTransformationSpec.buildTransformationString(transformationSpec));
}
if (transformationSpec.getMode() != null && !transformationSpec.getMode().equalsIgnoreCase("ECB")) {
iv = new IvParameterSpec(transformationSpec.getIv());
cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
} else {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
}
logger.debug("[EncryptingContentWriterDecorator::getContentOutputStream] " +
"Cipher initialized: ENCRYPT - " + cipher.getProvider() + " - " + cipher.getAlgorithm());
CipherOutputStream cos = new CipherOutputStream(
writer.getContentOutputStream(), cipher);
return cos;
} catch (NoSuchPaddingException e) {
logger.warn("[EncryptingContentWriterDecorator::getContentOutputStream] Invalid padding: " + transformationSpec.getPadding());
throw new EncryptionRuntimeException("Invalid padding: " + transformationSpec.getPadding(), e);
} catch (NoSuchAlgorithmException e) {
logger.warn("[EncryptingContentWriterDecorator::getContentOutputStream] Invalid algorithm: " + transformationSpec.getAlgorithm());
throw new EncryptionRuntimeException("Invalid algorithm: " + transformationSpec.getAlgorithm(), e);
} catch (InvalidKeyException e) {
logger.warn("[EncryptingContentWriterDecorator::getContentOutputStream] Invalid key!");
throw new EncryptionRuntimeException("Invalid key!", e);
} catch (InvalidAlgorithmParameterException e) {
logger.warn("[EncryptingContentWriterDecorator::getContentOutputStream] Invalid algorithm parameter: " + iv);
throw new EncryptionRuntimeException("Invalid algorithm parameter: " + iv, e);
} finally {
logger.debug("[EncryptingContentWriterDecorator::getContentOutputStream] END");
}
}
public FileChannel getFileChannel(boolean truncate) throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::getWritableChannel] BEGIN");
try {
throw new UnsupportedOperationException("Cannot get random file access to encrypted content.");
} finally {
logger.debug("[EncryptingContentWriterDecorator::getWritableChannel] END");
}
}
public ContentReader getReader() throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::getReader] BEGIN");
try {
return new DecryptingContentReaderDecorator(writer.getReader(),
secretKey, transformationSpec);
} finally {
logger.debug("[EncryptingContentWriterDecorator::getReader] END");
}
}
public WritableByteChannel getWritableChannel() throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::getWritableChannel] BEGIN");
try {
return Channels.newChannel(getContentOutputStream());
} finally {
logger.debug("[EncryptingContentWriterDecorator::getWritableChannel] END");
}
}
public boolean isClosed() {
logger.debug("[EncryptingContentWriterDecorator::isClosed] BEGIN");
try {
return writer.isClosed();
} finally {
logger.debug("[EncryptingContentWriterDecorator::isClosed] END");
}
}
public void putContent(ContentReader reader) throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::putContent] BEGIN");
try {
FileCopyUtils.copy(reader.getContentInputStream(), getContentOutputStream());
} catch (IOException e) {
logger.error("[EncryptingContentWriterDecorator::putContent] I/O Error writing to: " + writer, e);
throw new ContentIOException("Failed to copy content from content reader: \n" +
" accessor: " + this, e);
} finally {
logger.debug("[EncryptingContentWriterDecorator::putContent] END");
}
}
public void putContent(InputStream is) throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::putContent] BEGIN");
try {
FileCopyUtils.copy(is, getContentOutputStream());
} catch (IOException e) {
logger.error("[EncryptingContentWriterDecorator::putContent] I/O Error writing to: " + writer, e);
throw new ContentIOException("Failed to copy content from input stream: \n" +
" accessor: " + this, e);
} finally {
logger.debug("[EncryptingContentWriterDecorator::putContent] END");
}
}
public void putContent(File file) throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::putContent] BEGIN");
try {
FileCopyUtils.copy(new FileInputStream(file), getContentOutputStream());
} catch (IOException e) {
logger.error("[EncryptingContentWriterDecorator::putContent] I/O Error writing to: " + writer, e);
throw new ContentIOException("Failed to copy content from file: \n" +
" accessor: " + this, e);
} finally {
logger.debug("[EncryptingContentWriterDecorator::putContent] END");
}
}
public void putContent(String content) throws ContentIOException {
logger.debug("[EncryptingContentWriterDecorator::putContent] BEGIN");
try {
FileCopyUtils.copy(new ByteArrayInputStream(content.getBytes()), getContentOutputStream());
} catch (IOException e) {
logger.error("[EncryptingContentWriterDecorator::putContent] I/O Error writing to: " + writer, e);
throw new ContentIOException("Failed to copy content from string: \n" +
" accessor: " + this, e);
} finally {
logger.debug("[EncryptingContentWriterDecorator::putContent] END");
}
}
public void addListener(ContentStreamListener listener) {
logger.debug("[EncryptingContentWriterDecorator::addListener] BEGIN");
try {
this.writer.addListener(listener);
} finally {
logger.debug("[EncryptingContentWriterDecorator::addListener] END");
}
}
public ContentData getContentData() {
logger.debug("[EncryptingContentWriterDecorator::getContentData] BEGIN");
try {
return this.writer.getContentData();
} finally {
logger.debug("[EncryptingContentWriterDecorator::getContentData] END");
}
}
public String getContentUrl() {
logger.debug("[EncryptingContentWriterDecorator::getContentUrl] BEGIN");
try {
return this.writer.getContentUrl();
} finally {
logger.debug("[EncryptingContentWriterDecorator::getContentUrl] END");
}
}
public String getEncoding() {
logger.debug("[EncryptingContentWriterDecorator::getEncoding] BEGIN");
try {
return this.writer.getEncoding();
} finally {
logger.debug("[EncryptingContentWriterDecorator::getEncoding] END");
}
}
public Locale getLocale() {
logger.debug("[EncryptingContentWriterDecorator::getLocale] BEGIN");
try {
return this.writer.getLocale();
} finally {
logger.debug("[EncryptingContentWriterDecorator::getLocale] END");
}
}
public String getMimetype() {
logger.debug("[EncryptingContentWriterDecorator::getMimetype] BEGIN");
try {
return this.writer.getMimetype();
} finally {
logger.debug("[EncryptingContentWriterDecorator::getMimetype] END");
}
}
public long getSize() {
logger.debug("[EncryptingContentWriterDecorator::getSize] BEGIN");
try {
return this.writer.getSize();
} finally {
logger.debug("[EncryptingContentWriterDecorator::getSize] END");
}
}
public boolean isChannelOpen() {
logger.debug("[EncryptingContentWriterDecorator::isChannelOpen] BEGIN");
try {
return this.writer.isChannelOpen();
} finally {
logger.debug("[EncryptingContentWriterDecorator::isChannelOpen] END");
}
}
public void setEncoding(String encoding) {
logger.debug("[EncryptingContentWriterDecorator::setEncoding] BEGIN");
try {
this.writer.setEncoding(encoding);
} finally {
logger.debug("[EncryptingContentWriterDecorator::setEncoding] END");
}
}
public void setLocale(Locale locale) {
logger.debug("[EncryptingContentWriterDecorator::setLocale] BEGIN");
try {
this.writer.setLocale(locale);
} finally {
logger.debug("[EncryptingContentWriterDecorator::setLocale] END");
}
}
public void setMimetype(String mimeType) {
logger.debug("[EncryptingContentWriterDecorator::setMimetype] BEGIN");
try {
this.writer.setMimetype(mimeType);
} finally {
logger.debug("[EncryptingContentWriterDecorator::setMimetype] END");
}
}
public void setRetryingTransactionHelper(RetryingTransactionHelper transactionHelper) {
logger.debug("[EncryptingContentWriterDecorator::setRetryingTransactionHelper] BEGIN");
try {
this.writer.setRetryingTransactionHelper(transactionHelper);
} finally {
logger.debug("[EncryptingContentWriterDecorator::setRetryingTransactionHelper] END");
}
}
}