aboutsummaryrefslogtreecommitdiff
path: root/plugins/crypto-vala/src/srtp.vala
blob: 77b5acde5bb02280bd3debf10d15b8710ce18617 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
using Srtp;

public class 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; }
        public bool has_decrypt { get; private set; }

        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");
            }
            uint8[] ret = new uint8[buf_use];
            GLib.Memory.copy(ret, buf, buf_use);
            return ret;
        }

        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");
            }
            uint8[] ret = new uint8[buf_use];
            GLib.Memory.copy(ret, buf, buf_use);
            return ret;
        }

        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:
                    throw new Error.UNKNOWN(@"SRTP decrypt failed: $res");
            }
            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);
            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);
            decrypt_context.add_stream(ref policy);
            has_decrypt = true;
        }
    }
}