package org.ifsoft.rtp;

import org.ifsoft.*;

import java.util.ArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Encryptor
{
    private EncryptionMode _encryptionMode;
    private Byte _localKey[];
    private Byte _localSalt[];
    private Long _octetCount;
    private Long _packetCount;
    private Byte _remoteKey[];
    private Byte _remoteSalt[];
    private static Byte _rTCPAuthLabel = Byte.valueOf((byte)0);
    private AESCounter _rTCPDecryption;
    private Byte _rTCPDecryptionAuth[];
    private AESCounter _rTCPEncryption;
    private Byte _rTCPEncryptionAuth[];
    private Integer _rTCPIntegritySize;
    private static Byte _rTCPKeyLabel = Byte.valueOf((byte)0);
    private static Byte _rTCPSaltLabel = Byte.valueOf((byte)0);
    private static Byte _rTPAuthLabel = Byte.valueOf((byte)0);
    private AESCounter _rTPDecryption;
    private Byte _rTPDecryptionAuth[];
    private Integer _rTPDecryptionHighestSequenceNumber;
    private Long _rTPDecryptionROC;
    private AESCounter _rTPEncryption;
    private Byte _rTPEncryptionAuth[];
    private Long _rTPEncryptionROC;
    private Integer _rTPIntegritySize;
    private static Byte _rTPKeyLabel = Byte.valueOf((byte)0);
    private static Byte _rTPSaltLabel = Byte.valueOf((byte)0);
    private Integer _sRTCPIndex;

    private static final Logger Log = LoggerFactory.getLogger(Encryptor.class);

    static
    {
        _rTPKeyLabel = new Byte((byte)0);
        _rTPAuthLabel = new Byte((byte)1);
        _rTPSaltLabel = new Byte((byte)2);
        _rTCPKeyLabel = new Byte((byte)3);
        _rTCPAuthLabel = new Byte((byte)4);
        _rTCPSaltLabel = new Byte((byte)5);
    }

    private static void copyRTPProperties(RTPPacket source, RTPPacket target)
    {
        target.setMarker(source.getMarker());
        target.setSequenceNumber(source.getSequenceNumber());
        target.setSynchronizationSource(source.getSynchronizationSource());
        target.setTimestamp(source.getTimestamp());
    }

    public RTCPPacket[] decryptRTCP(Byte encryptedBytes[])
    {
        EncryptionMode _var0 = getEncryptionMode();

        if(_var0 != null ? _var0.equals(EncryptionMode.Null) : _var0 == EncryptionMode.Null)
        {
			Log.info("decryptRTCP no encryption found");
            return RTCPPacket.parseBytes(encryptedBytes);
		}
        if(ArrayExtensions.getLength(encryptedBytes).intValue() < 12 + _rTCPIntegritySize.intValue())
        {
			Log.info("decryptRTCP packet too small");
            return null;
		}
        Byte buffer[] = BitAssistant.subArray(encryptedBytes, Integer.valueOf(0), Integer.valueOf(ArrayExtensions.getLength(encryptedBytes).intValue() - _rTCPIntegritySize.intValue()));
        Byte buffer2[] = BitAssistant.subArray(encryptedBytes, Integer.valueOf(ArrayExtensions.getLength(encryptedBytes).intValue() - _rTCPIntegritySize.intValue()), _rTCPIntegritySize);
        Byte buffer4[] = BitAssistant.subArray(Crypto.getHmacSha1(_rTCPDecryptionAuth, buffer), Integer.valueOf(0), _rTCPIntegritySize);

        if(!BitAssistant.sequencesAreEqual(buffer2, buffer4).booleanValue())
        {
			Log.info("decryptRTCP sequences Are not Equal");
            return null;
		}

        Long ssrc = BitAssistant.toLongFromIntegerNetwork(buffer, Integer.valueOf(4));
        Byte buffer5[] = BitAssistant.subArray(buffer, Integer.valueOf(ArrayExtensions.getLength(buffer).intValue() - 4));
        buffer5[0] = new Byte((byte)(buffer5[0].byteValue() & 0x7f));
        Integer num2 = BitAssistant.toIntegerNetwork(buffer5, Integer.valueOf(0));
        Byte data[] = BitAssistant.subArray(buffer, Integer.valueOf(8), Integer.valueOf(ArrayExtensions.getLength(buffer).intValue() - 12));
        Byte buffer7[];

        if(_rTCPDecryption == null)
            buffer7 = data;
        else
            buffer7 = _rTCPDecryption.decrypt(data, ssrc, new Long((new Integer(num2.intValue())).longValue()));

        ArrayList list = new ArrayList();
        ArrayListExtensions.addRange(list, BitAssistant.subArray(buffer, Integer.valueOf(0), Integer.valueOf(8)));
        ArrayListExtensions.addRange(list, buffer7);
        return RTCPPacket.parseBytes((Byte[])list.toArray(new Byte[0]));
    }

    public RTPPacket decryptRTP(Byte encryptedBytes[])
        throws Exception
    {
        if(ArrayExtensions.getLength(encryptedBytes).intValue() < 12)
        {
			Log.info("decryptRTP packet less than 12 bytes");
            return null;
		}
        Integer num = new Integer(encryptedBytes[1].byteValue() & 0x7f);

        if(num.intValue() >= 72 && num.intValue() <= 76)
        {
			Log.info("decryptRTP packet first bye no good " + encryptedBytes[1]);
            return null;
		}
        EncryptionMode _var0 = getEncryptionMode();

        if(_var0 != null ? _var0.equals(EncryptionMode.Null) : _var0 == EncryptionMode.Null)
        {
			Log.info("decryptRTP no encryption found");
            return RTPPacket.parseBytes(encryptedBytes);
		}
        if(ArrayExtensions.getLength(encryptedBytes).intValue() < 12 + _rTPIntegritySize.intValue())
        {
			Log.info("decryptRTP packet too small");
            return null;
		}
        Byte collection[] = BitAssistant.subArray(encryptedBytes, Integer.valueOf(0), Integer.valueOf(ArrayExtensions.getLength(encryptedBytes).intValue() - _rTPIntegritySize.intValue()));
        Byte buffer2[] = BitAssistant.subArray(encryptedBytes, Integer.valueOf(ArrayExtensions.getLength(encryptedBytes).intValue() - _rTPIntegritySize.intValue()), _rTPIntegritySize);
        ArrayList list = ArrayListExtensions.createArray(collection);
        ArrayListExtensions.addRange(list, BitAssistant.getIntegerBytesFromLongNetwork(_rTPDecryptionROC));
        Byte buffer4[] = BitAssistant.subArray(Crypto.getHmacSha1(_rTPDecryptionAuth, (Byte[])list.toArray(new Byte[0])), Integer.valueOf(0), _rTPIntegritySize);

        if(!BitAssistant.sequencesAreEqual(buffer2, buffer4).booleanValue())
        {
			//Log.info("decryptRTP sequences Are not Equal");
            //return null;
		}
        RTPPacket packet = RTPPacket.parseBytes(collection);

        if(packet == null)
        {
			Log.info("decryptRTP collection is bad");
            return null;
		}

        if(_rTPDecryption != null)
            packet.setPayload(_rTPDecryption.decrypt(packet.getPayload(), packet.getSynchronizationSource(), getRTPDecryptionPacketIndex(packet.getSequenceNumber())));
        return packet;
    }

    public Byte[] encryptRTCP(RTCPPacket packets[])
        throws Exception
    {
        if(packets == null || ArrayExtensions.getLength(packets).intValue() == 0)
            throw new Exception("Cannot encrypt a null RTCP packet.");
        if(!(packets[0] instanceof RTCPSRPacket))
            throw new Exception("RTCP transmissions must start with a Sender Report (RTCPSRPacket).");
        RTCPPacket arr$[] = packets;
        int len$ = arr$.length;
        for(int i$ = 0; i$ < len$; i$++)
        {
            RTCPPacket packet = arr$[i$];
            if(packet instanceof RTCPSRPacket)
            {
                RTCPSRPacket packet2 = (RTCPSRPacket)(RTCPSRPacket)packet;
                packet2.setPacketCount(_packetCount);
                packet2.setOctetCount(_octetCount);
            }
        }

        Byte bytes[] = RTCPPacket.getBytes(packets);
        EncryptionMode _var0 = getEncryptionMode();
        if(_var0 != null ? _var0.equals(EncryptionMode.Null) : _var0 == EncryptionMode.Null)
            return bytes;
        Integer rTCPEncryptionPacketIndex = getRTCPEncryptionPacketIndex();
        Long ssrc = BitAssistant.toLongFromIntegerNetwork(bytes, Integer.valueOf(4));
        Byte data[] = BitAssistant.subArray(bytes, Integer.valueOf(8), Integer.valueOf(ArrayExtensions.getLength(bytes).intValue() - 8));
        Byte buffer3[];
        if(_rTCPEncryption == null)
            buffer3 = data;
        else
            buffer3 = _rTCPEncryption.encrypt(data, ssrc, new Long((new Integer(rTCPEncryptionPacketIndex.intValue())).longValue()));
        ArrayList collection = new ArrayList();
        ArrayListExtensions.addRange(collection, BitAssistant.subArray(bytes, Integer.valueOf(0), Integer.valueOf(8)));
        ArrayListExtensions.addRange(collection, buffer3);
        Byte integerBytesNetwork[] = BitAssistant.getIntegerBytesNetwork(rTCPEncryptionPacketIndex);
        integerBytesNetwork[0] = new Byte((byte)(integerBytesNetwork[0].byteValue() | 0x80));
        ArrayListExtensions.addRange(collection, integerBytesNetwork);
        Byte buffer6[] = BitAssistant.subArray(Crypto.getHmacSha1(_rTCPEncryptionAuth, (Byte[])collection.toArray(new Byte[0])), Integer.valueOf(0), _rTCPIntegritySize);
        ArrayList list2 = new ArrayList();
        ArrayListExtensions.addRange(list2, collection);
        ArrayListExtensions.addRange(list2, buffer6);
        return (Byte[])list2.toArray(new Byte[0]);
    }

    public Byte[] encryptRTP(RTPPacket packet)
        throws Exception
    {
        if(packet == null)
            throw new Exception("Cannot encrypt a null RTP packet.");
        Long num = Long.valueOf(_packetCount.longValue() + 1L);
        Long num2 = Long.valueOf(_octetCount.longValue() + (long)ArrayExtensions.getLength(packet.getPayload()).intValue());
        if(num.longValue() >= 0x100000000L)
            num = Long.valueOf(num.longValue() - 0x100000000L);
        if(num2.longValue() >= 0x100000000L)
            num2 = Long.valueOf(num2.longValue() - 0x100000000L);
        _packetCount = num;
        _octetCount = num2;
        EncryptionMode _var0 = getEncryptionMode();
        if(_var0 != null ? _var0.equals(EncryptionMode.Null) : _var0 == EncryptionMode.Null)
            return packet.getBytes();
        Byte buffer[];
        if(_rTPEncryption == null)
            buffer = packet.getPayload();
        else
            buffer = _rTPEncryption.encrypt(packet.getPayload(), packet.getSynchronizationSource(), getRTPEncryptionPacketIndex(packet.getSequenceNumber()));
        Byte payload[] = packet.getPayload();
        packet.setPayload(buffer);
        Byte bytes[] = packet.getBytes();
        packet.setPayload(payload);
        ArrayList list = ArrayListExtensions.createArray(bytes);
        ArrayListExtensions.addRange(list, BitAssistant.getIntegerBytesFromLongNetwork(_rTPEncryptionROC));
        Byte collection[] = BitAssistant.subArray(Crypto.getHmacSha1(_rTPEncryptionAuth, (Byte[])list.toArray(new Byte[0])), Integer.valueOf(0), _rTPIntegritySize);
        ArrayList list2 = new ArrayList();
        ArrayListExtensions.addRange(list2, bytes);
        ArrayListExtensions.addRange(list2, collection);
        return (Byte[])list2.toArray(new Byte[0]);
    }

    public Encryptor(EncryptionMode encryptionMode, Byte localKey[], Byte localSalt[], Byte remoteKey[], Byte remoteSalt[])
        throws Exception
    {
        _octetCount = Long.valueOf(0L);
        _packetCount = Long.valueOf(0L);
        _rTCPIntegritySize = Integer.valueOf(0);
        _rTPDecryptionHighestSequenceNumber = Integer.valueOf(0);
        _rTPDecryptionROC = Long.valueOf(0L);
        _rTPEncryptionROC = Long.valueOf(0L);
        _rTPIntegritySize = Integer.valueOf(0);
        _sRTCPIndex = Integer.valueOf(0);
        _rTPEncryptionROC = Long.valueOf(0L);
        _rTPDecryptionROC = Long.valueOf(0L);
        _rTPDecryptionHighestSequenceNumber = Integer.valueOf(0);
        _sRTCPIndex = Integer.valueOf(0);
        _packetCount = Long.valueOf(0L);
        _octetCount = Long.valueOf(0L);
        setEncryptionMode(encryptionMode);
        EncryptionMode _var0 = getEncryptionMode();
        if(_var0 != null ? !_var0.equals(EncryptionMode.Null) : _var0 != EncryptionMode.Null)
        {
            AESCounter counter = new AESCounter(localKey, localSalt);
            AESCounter counter2 = new AESCounter(remoteKey, remoteSalt);
            EncryptionMode _var1 = encryptionMode;
            EncryptionMode _var2 = encryptionMode;
            if((_var1 != null ? _var1.equals(EncryptionMode.Default) : _var1 == EncryptionMode.Default) || (_var2 != null ? _var2.equals(EncryptionMode.AES128Weak) : _var2 == EncryptionMode.AES128Weak))
            {
                Byte key[] = counter.generate(_rTPKeyLabel, Integer.valueOf(16));
                Byte salt[] = counter.generate(_rTPSaltLabel, Integer.valueOf(14));
                _rTPEncryption = new AESCounter(key, salt);
                Byte buffer3[] = counter.generate(_rTCPKeyLabel, Integer.valueOf(16));
                Byte buffer4[] = counter.generate(_rTCPSaltLabel, Integer.valueOf(14));
                _rTCPEncryption = new AESCounter(buffer3, buffer4);
                Byte buffer5[] = counter2.generate(_rTPKeyLabel, Integer.valueOf(16));
                Byte buffer6[] = counter2.generate(_rTPSaltLabel, Integer.valueOf(14));
                _rTPDecryption = new AESCounter(buffer5, buffer6);
                Byte buffer7[] = counter2.generate(_rTCPKeyLabel, Integer.valueOf(16));
                Byte buffer8[] = counter2.generate(_rTCPSaltLabel, Integer.valueOf(14));
                _rTCPDecryption = new AESCounter(buffer7, buffer8);
            }
            Byte buffer9[] = counter.generate(_rTPAuthLabel, Integer.valueOf(20));
            _rTPEncryptionAuth = buffer9;
            Byte buffer10[] = counter.generate(_rTCPAuthLabel, Integer.valueOf(20));
            _rTCPEncryptionAuth = buffer10;
            Byte buffer11[] = counter2.generate(_rTPAuthLabel, Integer.valueOf(20));
            _rTPDecryptionAuth = buffer11;
            Byte buffer12[] = counter2.generate(_rTCPAuthLabel, Integer.valueOf(20));
            _rTCPDecryptionAuth = buffer12;
            EncryptionMode _var3 = getEncryptionMode();
            if(_var3 == EncryptionMode.Default || _var3 == EncryptionMode.NullStrong)
                _rTPIntegritySize = Integer.valueOf(10);
            else
            if(_var3 == EncryptionMode.AES128Weak || _var3 == EncryptionMode.NullWeak)
                _rTPIntegritySize = Integer.valueOf(4);
            _rTCPIntegritySize = Integer.valueOf(10);
        }
    }

    public EncryptionMode getEncryptionMode()
    {
        return _encryptionMode;
    }

    public Byte[] getLocalKey()
    {
        return _localKey;
    }

    public Byte[] getLocalSalt()
    {
        return _localSalt;
    }

    public Byte[] getRemoteKey()
    {
        return _remoteKey;
    }

    public Byte[] getRemoteSalt()
    {
        return _remoteSalt;
    }

    private Integer getRTCPEncryptionPacketIndex()
    {
        Encryptor encryptor = this;
        Integer integer = encryptor._sRTCPIndex;
        Integer integer1 = encryptor._sRTCPIndex = Integer.valueOf(encryptor._sRTCPIndex.intValue() + 1);
        return integer;
    }

    private Long getRTPDecryptionPacketIndex(Integer sequenceNumber)
    {
        Long rTPDecryptionROC;
        if(_rTPDecryptionHighestSequenceNumber.intValue() < 32768)
        {
            if(sequenceNumber.intValue() - _rTPDecryptionHighestSequenceNumber.intValue() > 32768)
            {
                rTPDecryptionROC = Long.valueOf((_rTPDecryptionROC.longValue() - 1L) % 34L);
            } else
            {
                rTPDecryptionROC = _rTPDecryptionROC;
                _rTPDecryptionHighestSequenceNumber = Math.max(_rTPDecryptionHighestSequenceNumber, sequenceNumber);
            }
        } else
        if(_rTPDecryptionHighestSequenceNumber.intValue() - 32768 > sequenceNumber.intValue())
        {
            rTPDecryptionROC = Long.valueOf((_rTPDecryptionROC.longValue() + 1L) % 34L);
            _rTPDecryptionHighestSequenceNumber = sequenceNumber;
            _rTPDecryptionROC = rTPDecryptionROC;
        } else
        {
            rTPDecryptionROC = _rTPDecryptionROC;
            _rTPDecryptionHighestSequenceNumber = Math.max(_rTPDecryptionHighestSequenceNumber, sequenceNumber);
        }
        return Long.valueOf(18L * rTPDecryptionROC.longValue() + (long)sequenceNumber.intValue());
    }

    private Long getRTPEncryptionPacketIndex(Integer sequenceNumber)
    {
        Long rTPEncryptionROC = _rTPEncryptionROC;
        if(sequenceNumber.intValue() == 65535)
            _rTPEncryptionROC = Long.valueOf((_rTPEncryptionROC.longValue() + 1L) % 34L);
        return Long.valueOf(18L * rTPEncryptionROC.longValue() + (long)sequenceNumber.intValue());
    }

    private void setEncryptionMode(EncryptionMode value)
    {
        _encryptionMode = value;
    }

    private void setLocalKey(Byte value[])
    {
        _localKey = value;
    }

    private void setLocalSalt(Byte value[])
    {
        _localSalt = value;
    }

    private void setRemoteKey(Byte value[])
    {
        _remoteKey = value;
    }

    private void setRemoteSalt(Byte value[])
    {
        _remoteSalt = value;
    }

    public static void testSRTP()
        throws Exception
    {
        Byte key[] = {
            Byte.valueOf((byte)-31), Byte.valueOf((byte)-7), Byte.valueOf((byte)122), Byte.valueOf((byte)13), Byte.valueOf((byte)62), Byte.valueOf((byte)1), Byte.valueOf((byte)-117), Byte.valueOf((byte)-32), Byte.valueOf((byte)-42), Byte.valueOf((byte)79),
            Byte.valueOf((byte)-93), Byte.valueOf((byte)44), Byte.valueOf((byte)6), Byte.valueOf((byte)-34), Byte.valueOf((byte)65), Byte.valueOf((byte)57)
        };
        Byte salt[] = {
            Byte.valueOf((byte)14), Byte.valueOf((byte)-58), Byte.valueOf((byte)117), Byte.valueOf((byte)-83), Byte.valueOf((byte)73), Byte.valueOf((byte)-118), Byte.valueOf((byte)-2), Byte.valueOf((byte)-21), Byte.valueOf((byte)-74), Byte.valueOf((byte)-106),
            Byte.valueOf((byte)11), Byte.valueOf((byte)58), Byte.valueOf((byte)-85), Byte.valueOf((byte)-26)
        };
        AESCounter counter = new AESCounter(key, salt);
        Byte buffer3[] = counter.generate(_rTPKeyLabel, Integer.valueOf(16));
        Byte buffer4[] = counter.generate(_rTPAuthLabel, Integer.valueOf(20));
        Byte buffer5[] = counter.generate(_rTPSaltLabel, Integer.valueOf(14));
        AESCounter counter2 = new AESCounter(buffer3, buffer5);
        Byte bytes[] = {
            Byte.valueOf((byte)-128), Byte.valueOf((byte)15), Byte.valueOf((byte)18), Byte.valueOf((byte)52), Byte.valueOf((byte)-34), Byte.valueOf((byte)-54), Byte.valueOf((byte)-5), Byte.valueOf((byte)-83), Byte.valueOf((byte)-54), Byte.valueOf((byte)-2),
            Byte.valueOf((byte)-70), Byte.valueOf((byte)-66), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85),
            Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85), Byte.valueOf((byte)-85)
        };
        String hexString = BitAssistant.getHexString(new Byte[] {
            Byte.valueOf((byte)-128), Byte.valueOf((byte)15), Byte.valueOf((byte)18), Byte.valueOf((byte)52), Byte.valueOf((byte)-34), Byte.valueOf((byte)-54), Byte.valueOf((byte)-5), Byte.valueOf((byte)-83), Byte.valueOf((byte)-54), Byte.valueOf((byte)-2),
            Byte.valueOf((byte)-70), Byte.valueOf((byte)-66), Byte.valueOf((byte)78), Byte.valueOf((byte)85), Byte.valueOf((byte)-36), Byte.valueOf((byte)76), Byte.valueOf((byte)-25), Byte.valueOf((byte)-103), Byte.valueOf((byte)120), Byte.valueOf((byte)-40),
            Byte.valueOf((byte)-116), Byte.valueOf((byte)-92), Byte.valueOf((byte)-46), Byte.valueOf((byte)21), Byte.valueOf((byte)-108), Byte.valueOf((byte)-99), Byte.valueOf((byte)36), Byte.valueOf((byte)2), Byte.valueOf((byte)-73), Byte.valueOf((byte)-115),
            Byte.valueOf((byte)106), Byte.valueOf((byte)-52), Byte.valueOf((byte)-103), Byte.valueOf((byte)-22), Byte.valueOf((byte)23), Byte.valueOf((byte)-101), Byte.valueOf((byte)-115), Byte.valueOf((byte)-69)
        });
        RTPPacket packet = RTPPacket.parseBytes(bytes);
        Byte array[] = packet.getBytes();
        String str2 = BitAssistant.getHexString(bytes);
        String str3 = BitAssistant.getHexString(array);
        String _var0 = str2;
        if(_var0 != null ? !_var0.equals(str3) : _var0 != str3)
            throw new Exception();
        Integer num = Integer.valueOf(0);
        packet.setPayload(counter2.encrypt(packet.getPayload(), packet.getSynchronizationSource(), new Long((new Integer(num.intValue() + packet.getSequenceNumber().intValue())).longValue())));
        Byte buffer9[] = packet.getBytes();
        String str4 = StringExtensions.substring(hexString, 0, StringExtensions.getLength(hexString).intValue() - 20);
        String str5 = BitAssistant.getHexString(buffer9);
        String _var1 = str4;
        if(_var1 != null ? !_var1.equals(str5) : _var1 != str5)
            throw new Exception();
        ArrayList list = ArrayListExtensions.createArray(buffer9);
        ArrayListExtensions.addRange(list, BitAssistant.getIntegerBytesFromLongNetwork(new Long((new Integer(num.intValue())).longValue())));
        Byte buffer11[] = BitAssistant.subArray(Crypto.getHmacSha1(buffer4, (Byte[])list.toArray(new Byte[0])), Integer.valueOf(0), Integer.valueOf(10));
        String str6 = hexString.substring(StringExtensions.getLength(hexString).intValue() - 20);
        String str7 = BitAssistant.getHexString(buffer11);
        String _var2 = str6;
        if(_var2 != null ? !_var2.equals(str7) : _var2 != str7)
            throw new Exception();
        else
            return;
    }
}
