package com.vm.shadowsocks.tunnel.shadowsocks;

import org.bouncycastle.crypto.StreamCipher;
import org.bouncycastle.crypto.engines.ChaChaEngine;
import org.bouncycastle.crypto.engines.ChaCha7539Engine;

import java.io.ByteArrayOutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

public class Chacha20Crypt extends CryptBase {
	public final static String CIPHER_CHACHA20 = "chacha20";
	public final static String CIPHER_CHACHA20_IETF = "chacha20-ietf";

	public static Map<String, String> getCiphers() {
		Map<String, String> ciphers = new HashMap<>();
		ciphers.put(CIPHER_CHACHA20, Chacha20Crypt.class.getName());
		ciphers.put(CIPHER_CHACHA20_IETF, Chacha20Crypt.class.getName());
		return ciphers;
	}

	public Chacha20Crypt(String name, String password) {
		super(name, password);
	}

	@Override
	protected StreamCipher getCipher(boolean isEncrypted) throws InvalidAlgorithmParameterException {
		if (_name.equals(CIPHER_CHACHA20)) {
			return new ChaChaEngine();
		}
		else if (_name.equals(CIPHER_CHACHA20_IETF)) {
			return new ChaCha7539Engine();
		}
		return null;
	}

	@Override
	protected SecretKey getKey() {
		return new SecretKeySpec(_ssKey.getEncoded(), "AES");

	}

	@Override
	protected void _encrypt(byte[] data, ByteArrayOutputStream stream) {
		int noBytesProcessed;
		byte[] buffer = new byte[data.length];

		noBytesProcessed = encCipher.processBytes(data, 0, data.length, buffer, 0);
		stream.write(buffer, 0, noBytesProcessed);
	}

	@Override
	protected void _decrypt(byte[] data, ByteArrayOutputStream stream) {
		int BytesProcessedNum;
		byte[] buffer = new byte[data.length];
		BytesProcessedNum = decCipher.processBytes(data, 0, data.length, buffer, 0);
		stream.write(buffer, 0, BytesProcessedNum);

	}

	@Override
	public int getKeyLength() {
		if (_name.equals(CIPHER_CHACHA20) || _name.equals(CIPHER_CHACHA20_IETF)) {
			return 32;
		}
		return 0;
	}

	@Override
	public int getIVLength() {
		if (_name.equals(CIPHER_CHACHA20)) {
			return 8;
		}
		else if (_name.equals(CIPHER_CHACHA20_IETF)) {
			return 12;
		}
		return 0;
	}
}