2021-05-14 17:26:05 +00:00
|
|
|
using Srtp;
|
|
|
|
|
|
|
|
namespace Crypto.Srtp {
|
|
|
|
public const string AES_CM_128_HMAC_SHA1_80 = "AES_CM_128_HMAC_SHA1_80";
|
|
|
|
public const string AES_CM_128_HMAC_SHA1_32 = "AES_CM_128_HMAC_SHA1_32";
|
|
|
|
public const string F8_128_HMAC_SHA1_80 = "F8_128_HMAC_SHA1_80";
|
|
|
|
|
|
|
|
public class Session {
|
|
|
|
public bool has_encrypt { get; private set; default = false; }
|
|
|
|
public bool has_decrypt { get; private set; default = false; }
|
|
|
|
|
|
|
|
private Context encrypt_context;
|
|
|
|
private Context decrypt_context;
|
|
|
|
|
|
|
|
static construct {
|
|
|
|
init();
|
|
|
|
install_log_handler(log);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void log(LogLevel level, string msg) {
|
|
|
|
print(@"SRTP[$level]: $msg\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
public Session() {
|
|
|
|
Context.create(out encrypt_context, null);
|
|
|
|
Context.create(out decrypt_context, null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public uint8[] encrypt_rtp(uint8[] data) throws Error {
|
|
|
|
uint8[] buf = new uint8[data.length + MAX_TRAILER_LEN];
|
|
|
|
Memory.copy(buf, data, data.length);
|
|
|
|
int buf_use = data.length;
|
|
|
|
ErrorStatus res = encrypt_context.protect(buf, ref buf_use);
|
|
|
|
if (res != ErrorStatus.ok) {
|
|
|
|
throw new Error.UNKNOWN(@"SRTP encrypt failed: $res");
|
|
|
|
}
|
2021-12-18 21:35:32 +00:00
|
|
|
buf.length = buf_use;
|
|
|
|
return buf;
|
2021-05-14 17:26:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public uint8[] decrypt_rtp(uint8[] data) throws Error {
|
|
|
|
uint8[] buf = new uint8[data.length];
|
|
|
|
Memory.copy(buf, data, data.length);
|
|
|
|
int buf_use = data.length;
|
|
|
|
ErrorStatus res = decrypt_context.unprotect(buf, ref buf_use);
|
|
|
|
switch (res) {
|
|
|
|
case ErrorStatus.auth_fail:
|
|
|
|
throw new Error.AUTHENTICATION_FAILED("SRTP packet failed the message authentication check");
|
|
|
|
case ErrorStatus.ok:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
throw new Error.UNKNOWN(@"SRTP decrypt failed: $res");
|
|
|
|
}
|
|
|
|
uint8[] ret = new uint8[buf_use];
|
|
|
|
GLib.Memory.copy(ret, buf, buf_use);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
public uint8[] encrypt_rtcp(uint8[] data) throws Error {
|
|
|
|
uint8[] buf = new uint8[data.length + MAX_TRAILER_LEN + 4];
|
|
|
|
Memory.copy(buf, data, data.length);
|
|
|
|
int buf_use = data.length;
|
|
|
|
ErrorStatus res = encrypt_context.protect_rtcp(buf, ref buf_use);
|
|
|
|
if (res != ErrorStatus.ok) {
|
|
|
|
throw new Error.UNKNOWN(@"SRTCP encrypt failed: $res");
|
|
|
|
}
|
2021-12-18 21:35:32 +00:00
|
|
|
buf.length = buf_use;
|
|
|
|
return buf;
|
2021-05-14 17:26:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public uint8[] decrypt_rtcp(uint8[] data) throws Error {
|
|
|
|
uint8[] buf = new uint8[data.length];
|
|
|
|
Memory.copy(buf, data, data.length);
|
|
|
|
int buf_use = data.length;
|
|
|
|
ErrorStatus res = decrypt_context.unprotect_rtcp(buf, ref buf_use);
|
|
|
|
switch (res) {
|
|
|
|
case ErrorStatus.auth_fail:
|
|
|
|
throw new Error.AUTHENTICATION_FAILED("SRTCP packet failed the message authentication check");
|
|
|
|
case ErrorStatus.ok:
|
|
|
|
break;
|
|
|
|
default:
|
2021-11-09 21:06:21 +00:00
|
|
|
throw new Error.UNKNOWN(@"SRTCP decrypt failed: $res");
|
2021-05-14 17:26:05 +00:00
|
|
|
}
|
|
|
|
uint8[] ret = new uint8[buf_use];
|
|
|
|
GLib.Memory.copy(ret, buf, buf_use);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Policy create_policy(string profile) {
|
|
|
|
Policy policy = Policy();
|
|
|
|
switch (profile) {
|
|
|
|
case AES_CM_128_HMAC_SHA1_80:
|
|
|
|
policy.rtp.set_aes_cm_128_hmac_sha1_80();
|
|
|
|
policy.rtcp.set_aes_cm_128_hmac_sha1_80();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return policy;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void set_encryption_key(string profile, uint8[] key, uint8[] salt) {
|
|
|
|
Policy policy = create_policy(profile);
|
|
|
|
policy.ssrc.type = SsrcType.any_outbound;
|
|
|
|
policy.key = new uint8[key.length + salt.length];
|
|
|
|
Memory.copy(policy.key, key, key.length);
|
|
|
|
Memory.copy(((uint8*)policy.key) + key.length, salt, salt.length);
|
2021-11-09 21:06:21 +00:00
|
|
|
policy.next = null;
|
2021-05-14 17:26:05 +00:00
|
|
|
encrypt_context.add_stream(ref policy);
|
|
|
|
has_encrypt = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void set_decryption_key(string profile, uint8[] key, uint8[] salt) {
|
|
|
|
Policy policy = create_policy(profile);
|
|
|
|
policy.ssrc.type = SsrcType.any_inbound;
|
|
|
|
policy.key = new uint8[key.length + salt.length];
|
|
|
|
Memory.copy(policy.key, key, key.length);
|
|
|
|
Memory.copy(((uint8*)policy.key) + key.length, salt, salt.length);
|
2021-11-09 21:06:21 +00:00
|
|
|
policy.next = null;
|
2021-05-14 17:26:05 +00:00
|
|
|
decrypt_context.add_stream(ref policy);
|
|
|
|
has_decrypt = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|