Initial commit from SVN.
This commit is contained in:
209
Common/src/com/common/io/CryptoInputStream.java
Normal file
209
Common/src/com/common/io/CryptoInputStream.java
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 1999,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.InputStream;
|
||||
import java.io.IOException;
|
||||
import com.common.security.*;
|
||||
|
||||
/*
|
||||
* This class allows an symmetricly encrypted stream to be plugged into an input stream so that read bytes are decrypted using the private key.
|
||||
*/
|
||||
public abstract class CryptoInputStream extends java.io.InputStream implements IInputStream {
|
||||
protected InputStream stream = null;
|
||||
protected int decryptionCount;
|
||||
protected byte[] encryptedBuffer = null;
|
||||
protected byte[] decryptedBuffer = null;
|
||||
protected int decryptedBufferOffset = 0;
|
||||
protected int decryptionLength = 0;
|
||||
protected boolean stopFlag = false; //Used to notify the read methods that the encrypted segments have ended and that wrappering streams attempting to buffer should be told there are no more bytes at this time.//
|
||||
/**
|
||||
* CryptoInputStream constructor.
|
||||
*/
|
||||
public CryptoInputStream(InputStream 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;
|
||||
}//CryptoInputStream()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.InputStream#available()
|
||||
*/
|
||||
public int available() throws IOException {
|
||||
return stream.available();
|
||||
}//available()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IInputStream#canDecrypt()
|
||||
*/
|
||||
public boolean canDecrypt() {
|
||||
return true;
|
||||
}//canDecrypt()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.InputStream#close()
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
stream.close();
|
||||
}//close()//
|
||||
/**
|
||||
* Decrypts or verifies (unsigns) data and strips all padding.
|
||||
* @param data The buffer containing encrypted data.
|
||||
* @param dataOffset The index of the first encrypted byte.
|
||||
* @param dataLength The number of encrypted data bytes.
|
||||
* @param output A buffer to contain the decrypted data.
|
||||
* @param outputOffset The location of the first decrypted byte in the output buffer.
|
||||
* @return The number of bytes decrypted.
|
||||
*/
|
||||
protected abstract int decrypt(byte[] data, int dataOffset, int dataLength, byte[] output, int outputOffset);
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IInputStream#decrypt(boolean)
|
||||
*/
|
||||
public void decrypt(boolean decrypt) throws IOException {
|
||||
if(decrypt) {
|
||||
if(decryptionCount == 0) {
|
||||
refillBuffer();
|
||||
}//if//
|
||||
|
||||
decryptionCount++;
|
||||
}//if//
|
||||
else {
|
||||
decryptionCount--;
|
||||
|
||||
if(decryptionCount == 0) {
|
||||
if(stopFlag) {
|
||||
stopFlag = false;
|
||||
}//if//
|
||||
else if((stream.read() & 0xFF) != 0xF0) {
|
||||
throw new java.io.StreamCorruptedException("Error: Premature decryption completion.");
|
||||
}//else if//
|
||||
}//if//
|
||||
}//else//
|
||||
}//decrypt()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IInputStream#isDecrypting()
|
||||
*/
|
||||
public boolean isDecrypting() {
|
||||
return decryptionCount > 0;
|
||||
}//isDecrypting()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.InputStream#read()
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
int result = -1;
|
||||
|
||||
if(!stopFlag) {
|
||||
if(decryptionCount > 0) {
|
||||
if(decryptedBufferOffset == decryptionLength) {
|
||||
refillBuffer();
|
||||
}//if//
|
||||
|
||||
//The stop flag may be set when we refilled the buffer.//
|
||||
if(!stopFlag) {
|
||||
result = decryptedBuffer[decryptedBufferOffset++];
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
result = stream.read();
|
||||
}//else//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//read()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.InputStream#read(byte[], int, int)
|
||||
*/
|
||||
public int read(byte[] buffer, int offset, int length) throws IOException {
|
||||
int result = -1;
|
||||
|
||||
if(!stopFlag) {
|
||||
if(decryptionCount > 0) {
|
||||
result = 0;
|
||||
|
||||
while((!stopFlag) && (result != length)) {
|
||||
int size = 0;
|
||||
|
||||
if(decryptedBufferOffset == decryptionLength) {
|
||||
refillBuffer();
|
||||
}//if//
|
||||
|
||||
//The stop flag may be set when we refilled the buffer.//
|
||||
if(!stopFlag) {
|
||||
size = decryptionLength - decryptedBufferOffset;
|
||||
|
||||
if(size > length - result) {
|
||||
size = length - result;
|
||||
}//if//
|
||||
|
||||
System.arraycopy(decryptedBuffer, decryptedBufferOffset, buffer, offset + result, size);
|
||||
result += size;
|
||||
decryptedBufferOffset += size;
|
||||
}//if//
|
||||
}//while//
|
||||
|
||||
if(result == 0) {
|
||||
result = -1;
|
||||
}//if//
|
||||
}//if//
|
||||
else {
|
||||
result = stream.read(buffer, offset, length);
|
||||
}//else//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//read()//
|
||||
/* (non-Javadoc)
|
||||
* @see com.common.io.IInputStream#read(java.io.OutputStream, int)
|
||||
*/
|
||||
public int read(java.io.OutputStream out, int length) throws IOException {
|
||||
int result = 0;
|
||||
byte[] bytes = new byte[length];
|
||||
|
||||
result = stream.read(bytes, 0, bytes.length);
|
||||
out.write(bytes, 0, result);
|
||||
|
||||
return result;
|
||||
}//read()//
|
||||
/* (non-Javadoc)
|
||||
* @see java.io.InputStream#read()
|
||||
*/
|
||||
private boolean refillBuffer() throws IOException {
|
||||
boolean result = !stopFlag;
|
||||
|
||||
if(!stopFlag) {
|
||||
int flag = (stream.read() & 0xFF);
|
||||
|
||||
if(flag == 0xF0) {
|
||||
//Sometimes a wrappering stream will try to buffer beyond the encrypted segment. In such cases we will stop reading until the decryption flag is turned off.//
|
||||
stopFlag = true;
|
||||
result = false;
|
||||
}//if//
|
||||
else if(flag == 0xFF) {
|
||||
int size = StreamSupport.readInt(stream);
|
||||
int count = stream.read(encryptedBuffer, 0, size);
|
||||
|
||||
if(count != size) {
|
||||
throw new IOException("Error: Invalid read length.");
|
||||
}//if//
|
||||
|
||||
decryptionLength = decrypt(encryptedBuffer, 0, count, decryptedBuffer, 0);
|
||||
decryptedBufferOffset = 0;
|
||||
}//else if//
|
||||
else {
|
||||
throw new IOException("Stream corruption found while decrypting.");
|
||||
}//else//
|
||||
}//if//
|
||||
|
||||
return result;
|
||||
}//refillBuffer()//
|
||||
}//CryptoInputStream//
|
||||
Reference in New Issue
Block a user