Initial commit from SVN.
This commit is contained in:
166
Common/src/com/common/io/CryptoOutputStream.java
Normal file
166
Common/src/com/common/io/CryptoOutputStream.java
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright (c) 2003,2009 Declarative Engineering LLC.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Declarative Engineering LLC
|
||||
* verson 1 which accompanies this distribution, and is available at
|
||||
* http://declarativeengineering.com/legal/DE_Developer_License_v1.txt
|
||||
*/
|
||||
package com.common.io;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
import com.common.security.*;
|
||||
|
||||
/*
|
||||
* This class allows an asymmetric stream to be plugged into an output stream so that written bytes are encrypted using the public key.
|
||||
*/
|
||||
public abstract class CryptoOutputStream extends OutputStream implements IOutputStream {
|
||||
protected OutputStream stream = null;
|
||||
protected int encryptionCount;
|
||||
protected byte[] encryptedBuffer = null;
|
||||
protected byte[] decryptedBuffer = null;
|
||||
protected int decryptedBufferOffset = 0;
|
||||
/**
|
||||
* CryptoOutputStream constructor.
|
||||
*/
|
||||
public CryptoOutputStream(OutputStream stream, IAlgorithm algorithm) {
|
||||
super();
|
||||
|
||||
if(stream == null) {
|
||||
throw new IllegalArgumentException("Must provide a valid output stream.");
|
||||
}//if//
|
||||
else if(algorithm == null) {
|
||||
throw new IllegalArgumentException("Must provide a valid algorithm.");
|
||||
}//if//
|
||||
|
||||
this.stream = stream;
|
||||
}//CryptoOutputStream()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IOutputStream#canEncrypt()
|
||||
*/
|
||||
public boolean canEncrypt() {
|
||||
return true;
|
||||
}//canEncrypt()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.OutputStream#close()
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
while(isEncrypting()) {
|
||||
encrypt(false);
|
||||
}//while//
|
||||
|
||||
super.close();
|
||||
stream.close();
|
||||
}//close()//
|
||||
/**
|
||||
* Empties the buffer containing to-be encrypted data.
|
||||
*/
|
||||
protected void emptyBuffer() throws IOException {
|
||||
if(decryptedBufferOffset > 0) {
|
||||
int size = encrypt(decryptedBuffer, 0, decryptedBufferOffset, encryptedBuffer, 0);
|
||||
|
||||
//Write the block header.//
|
||||
stream.write(0xFF);
|
||||
//Write the encrypted size.//
|
||||
StreamSupport.writeInt(size, stream);
|
||||
//Write the block data.//
|
||||
stream.write(encryptedBuffer, 0, size);
|
||||
//Reset the block indexes.//
|
||||
decryptedBufferOffset = 0;
|
||||
}//if//
|
||||
}//emptyBuffer()//
|
||||
/**
|
||||
* Encrypts or signs the data.
|
||||
* @param data The buffer containing unencrypted data.
|
||||
* @param dataOffset The index of the first unencrypted byte.
|
||||
* @param dataLength The number of unencrypted data bytes.
|
||||
* @param output A buffer to contain the encrypted data.
|
||||
* @param outputOffset The location of the first encrypted byte in the output buffer.
|
||||
* @return The number of encrypted bytes (includes formatting and padding).
|
||||
*/
|
||||
protected abstract int encrypt(byte[] data, int dataOffset, int dataLength, byte[] output, int outputOffset);
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IOutputStream#encrypt(boolean)
|
||||
*/
|
||||
public void encrypt(boolean encrypt) throws IOException {
|
||||
if(encrypt) {
|
||||
//Flush any unencrypted data before beginning an encrypted segment.//
|
||||
if(encryptionCount == 0) {
|
||||
//TODO: Should flush data from all wrappering streams. This isn't possible with the current "pipe" design pattern for streams.//
|
||||
}//if//
|
||||
|
||||
encryptionCount++;
|
||||
}//if//
|
||||
else {
|
||||
encryptionCount--;
|
||||
|
||||
if(encryptionCount == 0) {
|
||||
//TODO: Should flush data from all wrappering streams. This isn't possible with the current "pipe" design pattern for streams.//
|
||||
//Empty the buffer and end the encrypted segment.//
|
||||
emptyBuffer();
|
||||
stream.write(0xF0);
|
||||
}//if//
|
||||
}//else//
|
||||
}//encrypt()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.OutputStream#flush()
|
||||
*/
|
||||
public void flush() throws IOException {
|
||||
/* This could cause a lot of unnecessary padding.
|
||||
if(encryptionCount > 0) {
|
||||
emptyBuffer();
|
||||
}//if//
|
||||
*/
|
||||
stream.flush();
|
||||
}//flush()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IOutputStream#isEncrypting()
|
||||
*/
|
||||
public boolean isEncrypting() {
|
||||
return encryptionCount > 0;
|
||||
}//isEncrypting()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.OutputStream#write(byte[], int, int)
|
||||
*/
|
||||
public void write(byte[] buffer, int offset, int length) throws IOException {
|
||||
if(encryptionCount > 0) {
|
||||
int count = 0;
|
||||
|
||||
while(count != length) {
|
||||
int size = 0;
|
||||
|
||||
if(decryptedBufferOffset == decryptedBuffer.length) {
|
||||
emptyBuffer();
|
||||
}//if//
|
||||
|
||||
size = decryptedBuffer.length - decryptedBufferOffset;
|
||||
|
||||
if(size > length - count) {
|
||||
size = length - count;
|
||||
}//if//
|
||||
|
||||
System.arraycopy(buffer, offset + count, decryptedBuffer, decryptedBufferOffset, size);
|
||||
count += size;
|
||||
decryptedBufferOffset += size;
|
||||
}//while//
|
||||
}//if//
|
||||
else {
|
||||
stream.write(buffer, offset, length);
|
||||
}//else//
|
||||
}//write()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.OutputStream#write(int)
|
||||
*/
|
||||
public void write(int b) throws IOException {
|
||||
if(encryptionCount > 0) {
|
||||
if(decryptedBufferOffset == decryptedBuffer.length) {
|
||||
emptyBuffer();
|
||||
}//if//
|
||||
|
||||
decryptedBuffer[decryptedBufferOffset++] = (byte) b;
|
||||
}//if//
|
||||
else {
|
||||
stream.write(b);
|
||||
}//else//
|
||||
}//write()//
|
||||
}//CryptoOutputStream//
|
||||
Reference in New Issue
Block a user