/**
*
* Code derived and adapted from the Jitsi client side SRTP framework.
*
* Distributed under LGPL license.
* See terms of license at gnu.org.
*/
package org.restcomm.media.rtp.crypto;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
/**
* SRTCPTransformer implements PacketTransformer.
* It encapsulate the encryption / decryption logic for SRTCP packets
*
* @author Bing SU (nova.su@gmail.com)
* @author Werner Dittmann <Werner.Dittmann@t-online.de>
*/
public class SRTCPTransformer implements PacketTransformer {
private final RawPacket packet;
private SRTPTransformEngine forwardEngine;
private SRTPTransformEngine reverseEngine;
/** All the known SSRC's corresponding SRTCPCryptoContexts */
private Hashtable<Long,SRTCPCryptoContext> contexts;
/**
* Constructs a SRTCPTransformer object.
*
* @param engine The associated SRTPTransformEngine object for both
* transform directions.
*/
public SRTCPTransformer(SRTPTransformEngine engine)
{
this(engine, engine);
}
/**
* Constructs a SRTCPTransformer object.
*
* @param forwardEngine The associated SRTPTransformEngine object for
* forward transformations.
* @param reverseEngine The associated SRTPTransformEngine object for
* reverse transformations.
*/
public SRTCPTransformer(SRTPTransformEngine forwardEngine, SRTPTransformEngine reverseEngine) {
this.packet = new RawPacket();
this.forwardEngine = forwardEngine;
this.reverseEngine = reverseEngine;
this.contexts = new Hashtable<Long,SRTCPCryptoContext>();
}
/**
* Encrypts a SRTCP packet
*
* @param pkt plain SRTCP packet to be encrypted
* @return encrypted SRTCP packet
*/
public byte[] transform(byte[] pkt) {
return transform(pkt, 0, pkt.length);
}
public byte[] transform(byte[] pkt, int offset, int length) {
// Wrap the data into raw packet for readable format
this.packet.wrap(pkt, offset, length);
// Associate the packet with its encryption context
long ssrc = this.packet.getRTCPSSRC();
SRTCPCryptoContext context = contexts.get(ssrc);
if (context == null) {
context = forwardEngine.getDefaultContextControl().deriveContext(ssrc);
context.deriveSrtcpKeys();
contexts.put(ssrc, context);
}
// Secure packet into SRTCP format
context.transformPacket(packet);
return packet.getData();
}
public byte[] reverseTransform(byte[] pkt) {
return reverseTransform(pkt, 0, pkt.length);
}
public byte[] reverseTransform(byte[] pkt, int offset, int length) {
// wrap data into raw packet for readable format
this.packet.wrap(pkt, offset, length);
// Associate the packet with its encryption context
long ssrc = this.packet.getRTCPSSRC();
SRTCPCryptoContext context = this.contexts.get(ssrc);
if (context == null) {
context = reverseEngine.getDefaultContextControl().deriveContext(ssrc);
context.deriveSrtcpKeys();
contexts.put(new Long(ssrc), context);
}
// Decode packet to RTCP format
boolean reversed = context.reverseTransformPacket(packet);
if(reversed) {
return packet.getData();
}
return null;
}
/**
* Close the transformer and underlying transform engine.
*
* The close functions closes all stored crypto contexts. This deletes key data
* and forces a cleanup of the crypto contexts.
*/
public void close()
{
forwardEngine.close();
if (forwardEngine != reverseEngine)
reverseEngine.close();
Iterator<Map.Entry<Long, SRTCPCryptoContext>> iter
= contexts.entrySet().iterator();
while (iter.hasNext())
{
Map.Entry<Long, SRTCPCryptoContext> entry = iter.next();
SRTCPCryptoContext context = entry.getValue();
iter.remove();
if (context != null)
context.close();
}
}
}