package aalg.crypto;

import java.io.IOException;
import java.io.InputStream;
import aalg.algebra.IElement;
import aalg.algebra.IGroup;
import aalg.algebra.SubGroupDefinition;

public class DHStreamDecryptor<T extends IElement>  implements IStreamDecryptor {
	private final InputStream plainTextStream = new InputStream() {
		@Override
		public int read() throws IOException {
			return decryptor.getTargetStream().read();
		}
	};
	
	private InputStream cipherTextStream;
	private final DHKeyExchange<T> keyExchange;
	private final DlPrivateKey privateKey;
	private final SubGroupDefinition<T> subGroupDefinition;
	private final IElementKeyExtractor<T> keyExtractor;
	private final ISymmetricStreamCipher cipher;
	private ISymmetricStreamDecryptor decryptor;
	
	
	public DHStreamDecryptor(final SubGroupDefinition<T> subGroupDefinition, final IElementKeyExtractor<T> keyExtractor, final ISymmetricStreamCipher cipher, final DlPrivateKey privateKey) {
		this.privateKey = privateKey;
		this.subGroupDefinition = subGroupDefinition;
		this.keyExchange = new DHKeyExchange<T>(subGroupDefinition);
		this.keyExtractor = keyExtractor;
		this.cipher = cipher;
	}

	@Override
	public InputStream getTargetStream() throws IOException {
		return plainTextStream;
	}

	@Override
	public InputStream getSourceStream() throws IOException {
		return cipherTextStream;
	}

	@Override
	public void initialize(final InputStream cipherTextStream) throws IOException {
		this.cipherTextStream = cipherTextStream;
		
		final IGroup<T> group = subGroupDefinition.getGroup();
		
		final DlPublicKey<T> randomPublicKey = DlPublicKey.<T>readFromStream (group, cipherTextStream);
		final T sharedElement = keyExchange.calculateSharedKey(randomPublicKey, privateKey);

		final byte[] sharedKey = keyExtractor.extractKey(sharedElement, 0, cipher.getKeySize());
		
		decryptor = cipher.getDecryptor();
		decryptor.setKey(new ByteArraySymmetricKey(sharedKey));
		decryptor.initialize(cipherTextStream);
	}

	@Override
	public void finish() {
		decryptor.finish();
	}

}
