2 * ISMACryp 1.1 & 2.0 protocol as defined in ISMA Encryption and Authentication see http://www.isma.tv
4 * David Castleford, Orange Labs / France Telecom R&D
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 /* TODO: get ISMACryp parameters automatically from SDP info,
29 * if present (typically sent via SAP/SDP),
30 * rather than having manual insertion via preferences
31 * TODO: perhaps better check coherence of certain information?
38 #include <epan/packet.h>
39 #include <epan/tvbuff.h>
40 #include <epan/prefs.h>
42 /* keeps track of current position in buffer in terms of bit and byte offset */
43 typedef struct Toffset_struct
50 static void dissect_ismacryp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint ismacryp_version);
51 static offset_struct* dissect_auheader( tvbuff_t *tvb, offset_struct *poffset, packet_info *pinfo, proto_tree *tree, guint set_version );
52 void proto_reg_handoff_ismacryp(void);
53 static void add_bits(offset_struct* poffset, gint len_bits);
55 #define PROTO_TAG_ISMACRYP "ISMACRYP"
56 #define PROTO_TAG_ISMACRYP_11 "ISMACryp_11"
57 #define PROTO_TAG_ISMACRYP_20 "ISMACryp_20"
60 #define AAC_HBR_MODE 0
61 #define MPEG4_VIDEO_MODE 1
62 #define AVC_VIDEO_MODE 2
63 /* #define USERMODE 3 */
64 #define DEFAULT_SELECTIVE_ENCRYPTION TRUE
65 #define DEFAULT_SLICE_INDICATION FALSE
66 #define DEFAULT_PADDING_INDICATION FALSE
67 #define DEFAULT_IV_LENGTH 4
68 #define DEFAULT_DELTA_IV_LENGTH 0
69 #define DEFAULT_KEY_INDICATOR_LENGTH 0
70 #define DEFAULT_KEY_INDICATOR_PER_AU FALSE
71 #define AU_HEADERS_LENGTH_SIZE 2 /* size in bytes */
72 #define DEFAULT_AU_SIZE_LENGTH 0
73 #define DEFAULT_AU_INDEX_LENGTH 0
74 #define DEFAULT_AU_INDEX_DELTA_LENGTH 0
75 #define DEFAULT_CTS_DELTA_LENGTH 0
76 #define DEFAULT_DTS_DELTA_LENGTH 0
77 #define DEFAULT_RANDOM_ACCESS_INDICATION FALSE
78 #define DEFAULT_STREAM_STATE_INDICATION 0
80 /* Wireshark ID of the ISMACRYP protocol */
81 static int proto_ismacryp = -1;
83 /* parameters set in preferences */
84 static guint pref_dynamic_payload_type = 0; /* RTP dynamic payload type */
85 static guint pref_au_size_length = DEFAULT_AU_SIZE_LENGTH; /* default Au size length */
86 static guint pref_au_index_length = DEFAULT_AU_INDEX_LENGTH; /* default Au index length */
87 static guint pref_au_index_delta_length = DEFAULT_AU_INDEX_DELTA_LENGTH; /* default Au index delta length */
88 static guint pref_cts_delta_length = DEFAULT_CTS_DELTA_LENGTH; /* default CTS delta length */
89 static guint pref_dts_delta_length = DEFAULT_DTS_DELTA_LENGTH; /* default DTS delta length */
90 static gboolean pref_random_access_indication = DEFAULT_RANDOM_ACCESS_INDICATION; /* default random access indication */
91 static guint pref_stream_state_indication = DEFAULT_STREAM_STATE_INDICATION; /* default stream state indication */
92 static guint version_type = V11; /* default to ISMACryp 1.1 */
93 static guint mode = AVC_VIDEO_MODE; /* default codec mode */
94 static gboolean selective_encryption = DEFAULT_SELECTIVE_ENCRYPTION; /* default selective encryption flag */
95 static gboolean slice_indication = DEFAULT_SLICE_INDICATION; /* default slice indication */
96 static gboolean padding_indication = DEFAULT_PADDING_INDICATION; /* default padding indication */
97 static guint key_indicator_length = DEFAULT_KEY_INDICATOR_LENGTH; /* default key indicator length */
98 static gboolean key_indicator_per_au_flag = DEFAULT_KEY_INDICATOR_PER_AU; /* default key indicator per au */
99 static guint iv_length = DEFAULT_IV_LENGTH; /* default IV length */
100 static guint delta_iv_length = DEFAULT_DELTA_IV_LENGTH; /* default delta IV length */
101 static gboolean pref_user_mode = FALSE; /* preference user mode instead of RFC3640 mode? */
102 static gboolean override_flag = FALSE; /* override use of RTP payload type to deduce ISMACryp version */
106 static guint au_size_length = DEFAULT_AU_SIZE_LENGTH; /* default Au size length */
107 static guint au_index_length = DEFAULT_AU_INDEX_LENGTH; /* default Au index length */
108 static guint au_index_delta_length = DEFAULT_AU_INDEX_DELTA_LENGTH; /* default Au index delta length */
109 static guint cts_delta_length = DEFAULT_CTS_DELTA_LENGTH; /* default CTS delta length */
110 static guint dts_delta_length = DEFAULT_DTS_DELTA_LENGTH; /* default DTS delta length */
111 static gboolean random_access_indication = DEFAULT_RANDOM_ACCESS_INDICATION; /* default random access indication */
112 static guint stream_state_indication = DEFAULT_STREAM_STATE_INDICATION; /* default stream state indication */
113 static gboolean user_mode = FALSE; /* selected user mode instead of RFC3640 mode? */
115 /*static const value_string messagetypenames[] = {}; */
117 /* ismacryp Parameter Types */
118 /*static const value_string parametertypenames[] = {}; */
119 static const value_string modetypenames[] = {
120 { AAC_HBR_MODE, "aac-hbr" },
121 { MPEG4_VIDEO_MODE, "mpeg4-video" },
122 { AVC_VIDEO_MODE, "avc-video" },
125 /* The following hf_* variables are used to hold the Wireshark IDs of
126 * our header fields; they are filled out when we call
127 * proto_register_field_array() in proto_register_ismacryp()
129 /** Kts attempt at defining the protocol */
130 static gint hf_ismacryp = -1;
131 static gint hf_ismacryp_header = -1;
132 static gint hf_ismacryp_au_headers_length = -1;
133 static gint hf_ismacryp_header_length = -1;
134 static gint hf_ismacryp_header_byte = -1;
135 static gint hf_ismacryp_version = -1;
136 static gint hf_ismacryp_length = -1;
137 /* static gint hf_ismacryp_message_type = -1; */
138 static gint hf_ismacryp_message_length = -1;
139 static gint hf_ismacryp_message = -1;
140 static gint hf_ismacryp_parameter = -1;
141 /* static gint hf_ismacryp_parameter_type = -1; */
142 static gint hf_ismacryp_parameter_length = -1;
143 static gint hf_ismacryp_parameter_value = -1;
144 static gint hf_ismacryp_iv = -1;
145 static gint hf_ismacryp_delta_iv = -1;
146 static gint hf_ismacryp_key_indicator = -1;
147 /* static gint hf_ismacryp_delta_iv_length = -1; */
148 static gint hf_ismacryp_au_size = -1;
149 static gint hf_ismacryp_au_index = -1;
150 static gint hf_ismacryp_au_index_delta = -1;
151 static gint hf_ismacryp_cts_delta = -1;
152 static gint hf_ismacryp_cts_flag = -1;
153 static gint hf_ismacryp_dts_flag = -1;
154 static gint hf_ismacryp_dts_delta = -1;
155 static gint hf_ismacryp_rap_flag = -1;
156 static gint hf_ismacryp_au_is_encrypted = -1;
157 static gint hf_ismacryp_slice_start = -1;
158 static gint hf_ismacryp_slice_end = -1;
159 static gint hf_ismacryp_padding_bitcount = -1;
160 static gint hf_ismacryp_padding = -1;
161 static gint hf_ismacryp_reserved_bits = -1;
162 static gint hf_ismacryp_unused_bits = -1;
163 static gint hf_ismacryp_stream_state = -1;
165 /* These are the ids of the subtrees that we may be creating */
166 static gint ett_ismacryp = -1;
167 static gint ett_ismacryp_header = -1;
168 static gint ett_ismacryp_header_byte = -1;
169 static gint ett_ismacryp_message = -1;
171 /* Informative tree structure is shown here:
173 * AU Headers Length (2 bytes) - total length of AU header(s)
175 * HEADER BYTE (if present - 1 byte)
176 * -AU_is_encrypted (1 bit)
177 * -Slice_start (1 bit)
179 * -Padding_bitcount (3 bits)
181 * IV (variable length)
182 * Key Indicator (variable length)
183 * AU size (if present - variable length)
184 * AU index (if present - variable length)
185 * CTS delta (if present - variable length)
186 * DTS delta (if present - variable length)
187 * RAP flag (if present - 1 bit)
188 * Stream State Indication (if present - variable length)
189 * - HEADER2 if 2nd header present (depends on AU headers length)
190 * Header Byte (if present - 1 byte)
191 * -AU_is_encrypted (1 bit)
192 * -Slice_start (1 bit)
194 * -Padding_bitcount (3 bits)
196 * IV (variable length)
197 * Key Indicator (variable length)
198 * AU size (if present - variable length)
199 * AU index delta(if present - variable length)
200 * CTS delta (if present - variable length)
201 * DTS delta (if present - variable length)
202 * RAP flag (if present - 1 bit)
203 * Stream State Indication (if present - variable length)
204 * - more HEADERS if present
207 * End informative tree structure
210 /* Note that check coherence of total AU headers length and that calculated from size of parameters defined by default or preferences.
211 * These are found in SDP and vary e.g. between audio and video and depend on ISMACryp encoding parameters
212 * hence if these values are incorrect displayed values will be strange and can see errors
213 * this could be improved of course
216 /* dissect_ismacryp_v11 gets called if rtp_dyn_payload_type = "enc-mpeg4-generic" i.e. is set via SDP */
217 static void dissect_ismacryp_v11(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
219 /* display ISMACryp version */
220 if (check_col(pinfo->cinfo, COL_PROTOCOL))
221 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ISMACRYP_11);
223 /* display RTP payload type */
224 if ( check_col( pinfo->cinfo, COL_INFO) ) {
225 col_clear(pinfo->cinfo,COL_INFO); /* clear column info */
227 col_append_str(pinfo->cinfo, COL_INFO, "(PT=enc-mpeg4-generic)");
230 dissect_ismacryp_common( tvb, pinfo, tree, V11);
233 /* dissect_ismacryp_v20 gets called if rtp_dyn_payload_type = "enc-isoff-generic" i.e. is set via SDP */
234 static void dissect_ismacryp_v20(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
236 /* display ISMACryp version */
237 if (check_col(pinfo->cinfo, COL_PROTOCOL))
238 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ISMACRYP_20);
240 /* display RTP payload type */
241 if (check_col(pinfo->cinfo, COL_INFO)){
242 col_clear(pinfo->cinfo,COL_INFO); /* clear column info */
243 col_append_str(pinfo->cinfo, COL_INFO, "(PT=enc-isoff-generic)");
246 dissect_ismacryp_common( tvb, pinfo, tree, V20);
249 static void dissect_ismacryp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
251 if (check_col(pinfo->cinfo, COL_INFO)){
252 col_clear(pinfo->cinfo,COL_INFO); /* clear column info */
253 col_append_str(pinfo->cinfo, COL_INFO, "Manual version");
255 dissect_ismacryp_common( tvb, pinfo, tree, version_type); /* Unknown version type: Use preference */
258 static void dissect_ismacryp_common(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, guint ismacryp_version)
260 guint set_version; /* ISMACryp version used during dissection */
261 proto_item *ismacryp_item;
262 proto_tree *ismacryp_tree;
263 proto_tree *ismacryp_message_tree;
265 /* select and display ISMACryp version */
266 if ((ismacryp_version!=version_type) && override_flag){
267 /* override -> use manual preference setting */
268 col_append_str(pinfo->cinfo, COL_INFO, " Manual version");
269 set_version = version_type; /* set to preference value */
272 set_version = ismacryp_version;
275 if (set_version == V11){
276 if (check_col(pinfo->cinfo, COL_PROTOCOL))
277 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ISMACRYP_11);
279 if (pref_user_mode == FALSE){
280 if (check_col( pinfo->cinfo, COL_INFO))
281 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",val_to_str(mode, modetypenames, "user mode"));
283 if (pref_user_mode == TRUE){
284 if ( check_col( pinfo->cinfo, COL_INFO))
285 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s","user mode");
287 user_mode = pref_user_mode;
289 if (set_version == V20){
290 if (check_col(pinfo->cinfo, COL_PROTOCOL))
291 col_set_str(pinfo->cinfo, COL_PROTOCOL, PROTO_TAG_ISMACRYP_20);
294 if (check_col( pinfo->cinfo, COL_INFO))
295 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s","user mode");
297 /* select correct AU values depending on version & selected mode in preferences menu if not in user_mode */
298 if (user_mode == TRUE){ /* use values set in preference menu */
299 au_size_length = pref_au_size_length;
300 au_index_length = pref_au_index_length;
301 au_index_delta_length = pref_au_index_delta_length;
302 cts_delta_length = pref_cts_delta_length;
303 dts_delta_length = pref_dts_delta_length;
304 random_access_indication = pref_random_access_indication;
305 stream_state_indication = pref_stream_state_indication;
306 } /* end if user_mode == TRUE */
307 if (user_mode == FALSE){
312 au_index_delta_length = 3;
313 cts_delta_length = 0;
314 dts_delta_length = 0;
315 random_access_indication = FALSE;
316 stream_state_indication = 0;
318 case MPEG4_VIDEO_MODE:
321 au_index_delta_length = 0;
322 cts_delta_length = 0;
323 dts_delta_length = 22;
324 random_access_indication = TRUE;
325 stream_state_indication = 0;
330 au_index_delta_length = 0;
331 cts_delta_length = 0;
332 dts_delta_length = 22;
333 random_access_indication = TRUE;
334 stream_state_indication = 0;
337 DISSECTOR_ASSERT_NOT_REACHED();
340 } /* end if user_mode == FALSE */
342 /* navigate through buffer */
345 /* we are being asked for details */
347 guint16 au_headers_length = 0; /* total length of AU headers */
348 guint16 totalbits =0; /* keeps track of total number of AU header bits treated (used to determine end of AU headers) */
349 int deltabits = -1; /* keeps track of extra bits per AU header treated (used to determine end of AU heafers ) */
350 guint16 totalbit_offset = 0; /* total offset in bits*/
351 int nbpadding_bits = 0; /* number of padding bits*/
352 offset_struct s_offset;
353 offset_struct* poffset;
354 guint16 nbmessage_bytes = 0; /*nb of message data bytes */
355 s_offset.offset_bytes = 0; /* initialise byte offset */
356 s_offset.offset_bits = 0; /* initialise bit offset */
359 ismacryp_item = proto_tree_add_item(tree, proto_ismacryp, tvb, 0, -1, FALSE);
360 ismacryp_tree = proto_item_add_subtree(ismacryp_item, ett_ismacryp);
361 proto_item_append_text(tree, ", %s", "ismacryp packet"); /* add text to tree */
363 /* ismacryp_tree analysis */
364 /* we are being asked for details */
365 /* get total length of AU headers (first 2 bytes) */
366 ismacryp_item = proto_tree_add_item(ismacryp_tree, hf_ismacryp_au_headers_length,
367 tvb, poffset->offset_bytes, AU_HEADERS_LENGTH_SIZE, FALSE );
368 proto_item_append_text(ismacryp_item, " (bits)"); /* add text to AU Header tree indicating length */
369 au_headers_length=tvb_get_ntohs(tvb,poffset->offset_bytes); /* 2 byte au headers length */
370 poffset->offset_bytes+=AU_HEADERS_LENGTH_SIZE;
371 /* ADD HEADER(S) BRANCH */
374 totalbits=(poffset->offset_bytes*8)+poffset->offset_bits;
375 while( ((totalbits-8*AU_HEADERS_LENGTH_SIZE)<au_headers_length) && deltabits!=0 ) /* subtract AU headers length bits*/
377 poffset=dissect_auheader( tvb, poffset, pinfo, ismacryp_tree, set_version);
378 deltabits=(poffset->offset_bytes*8)+poffset->offset_bits - totalbits; /* if zero this means no actual AU header so exit while loop */
379 totalbits+=deltabits;
381 /* reached end of AU Header(s) */
382 /* sanity check if actual total AU headers length in bits i.e. totalbits is */
383 /* the same as expected AU headers length from 2 bytes at start of buffer */
384 if ( (totalbits-8*AU_HEADERS_LENGTH_SIZE) != au_headers_length) /* something wrong */
386 proto_item_append_text(ismacryp_item,
387 " Error - expected total AU headers size (%d bits) "
388 "does not match calculated size (%d bits) - check parameters!",
389 au_headers_length,(totalbits-8*AU_HEADERS_LENGTH_SIZE));
391 /* add padding if need to byte align */
392 if (poffset->offset_bits!=0)
394 totalbit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
395 nbpadding_bits = (8-poffset->offset_bits); /* number of padding bits for byte alignment */
396 ismacryp_item = proto_tree_add_bits_item(ismacryp_tree, hf_ismacryp_padding,
397 tvb, totalbit_offset, nbpadding_bits , FALSE); /* padding bits */
398 proto_item_append_text(ismacryp_item, ": Length=%d bits",nbpadding_bits); /* add padding info */
399 add_bits(poffset, nbpadding_bits);
401 /* ADD MESSAGE BRANCH */
402 ismacryp_item = proto_tree_add_item( ismacryp_tree, hf_ismacryp_message,
403 tvb, poffset->offset_bytes, -1, FALSE );
404 ismacryp_message_tree = proto_item_add_subtree(ismacryp_item, ett_ismacryp_message);
405 proto_item_append_text(ismacryp_item, ", %s", "Encrypted data"); /* add text to Message tree */
406 nbmessage_bytes = tvb_reported_length_remaining(tvb, poffset->offset_bytes);
407 proto_item_append_text(ismacryp_item, ", Length= %d bytes", nbmessage_bytes ); /* add length of message */
409 /* ismacryp message tree analysis (encrypted AUs) */
410 if (ismacryp_message_tree)
411 { /* we are being asked for details */
412 poffset->offset_bytes+= nbmessage_bytes; /* */
413 } /* end message details */
414 /* end ismacryp tree details */
417 /* AU Header dissection */
418 static offset_struct* dissect_auheader( tvbuff_t *tvb, offset_struct *poffset, packet_info *pinfo, proto_tree *ismacryp_tree, guint set_version )
420 proto_item *ismacryp_item;
421 proto_tree *ismacryp_header_tree;
422 proto_tree *ismacryp_header_byte_tree;
424 guint16 header_len_bytes = 0; /* total length of non-first AU header in bytes (rounded up) */
425 gint header_len = 0; /* length of AU headers in bits */
428 gboolean first_au_flag=FALSE;
431 /*first determine total AU header length */
432 /* calculate each AU header length in bits first */
433 switch (set_version) {
435 if (selective_encryption)
436 header_len+=8; /* add one byte to header length */
439 if (selective_encryption || slice_indication || padding_indication)
440 header_len+=8; /* add one byte to header length */
443 DISSECTOR_ASSERT_NOT_REACHED();
446 header_len+=au_size_length; /* add au size length */
448 if (poffset->offset_bytes==AU_HEADERS_LENGTH_SIZE){ /*first AU */
449 header_len+=8*(iv_length); /* add IV length */
450 header_len+=8*key_indicator_length; /* add key indicator length */
451 header_len+=au_index_length; /* add AU index length */
452 first_au_flag = TRUE;
454 else { /* not the first AU */
455 if (key_indicator_per_au_flag == TRUE)
456 header_len+=8*key_indicator_length; /* add key indicator length */
457 header_len+=8*(delta_iv_length); /* add delta IV length */
458 header_len+=au_index_delta_length; /* add AU delta index length */
460 /* CTS flag is present? */
461 if (cts_delta_length != 0){ /* need to test whether cts_delta_flag is TRUE or FALSE */
462 cts_flag=tvb_get_bits8(tvb, AU_HEADERS_LENGTH_SIZE*8+header_len, 1); /*fetch 1 bit CTS flag */
463 header_len+=1; /* add CTS flag bit */
465 header_len+=cts_delta_length; /* add CTS delta length bits if CTS flag SET */
467 /* DTS flag is present? */
468 if (dts_delta_length != 0){ /* need to test whether dts_delta_flag is TRUE or FALSE */
469 dts_flag=tvb_get_bits8(tvb, AU_HEADERS_LENGTH_SIZE*8+header_len, 1); /*fetch 1 bit DTS flag */
470 header_len+=1; /* add DTS flag bit */
472 header_len+=dts_delta_length; /* add DTS delta length bits if DTS flag SET */
474 /* RAP flag present? */
475 if (random_access_indication != FALSE)
476 header_len+=1; /* add 1 bit RAP flag */
478 /* stream state indication present */
479 if (stream_state_indication !=0)
480 header_len+=stream_state_indication; /* add stream state indication bits */
482 /* convert header_len to bytes (rounded up) */
483 if (header_len% 8!=0)
485 header_len_bytes=((header_len)/8)+1; /*add 1 */
488 header_len_bytes=((header_len)/8);
490 /* add AU header tree */
491 ismacryp_item = proto_tree_add_item(ismacryp_tree, hf_ismacryp_header, tvb, poffset->offset_bytes, header_len_bytes, FALSE );
492 proto_item_append_text(ismacryp_item, ": Length=%d bits", header_len); /* add text to Header tree indicating length */
493 /* sanity check if actual AU header length is zero bits, which indicates an error */
494 if ( header_len == 0) /* something wrong */
496 proto_item_append_text(ismacryp_item, " Error - zero bit AU header size - check parameters!");
498 ismacryp_header_tree = proto_item_add_subtree(ismacryp_item, ett_ismacryp_header);
500 /* ismacryp header analysis */
501 /* we are being asked for details */
503 /* Extra 1 Byte Header? */
505 if ((set_version==V20 && (selective_encryption || slice_indication || padding_indication))
506 || (set_version==V11 && selective_encryption)){
508 /* add header byte tree */
509 ismacryp_item = proto_tree_add_item(ismacryp_header_tree, hf_ismacryp_header_byte,
510 tvb, poffset->offset_bytes, 1, FALSE );
511 proto_item_append_text(ismacryp_item, ": Length=8 bits"); /* add text to Header byte tree indicating length */
512 ismacryp_header_byte_tree = proto_item_add_subtree(ismacryp_item, ett_ismacryp_header_byte);
514 /*ismacryp_header_byte_tree */
515 /* we are being asked for details */
516 /* tvb is network order, so get MSB bits first, so shift 8 bits and work "backwards" */
517 add_bits(poffset,7); /*shift 7 bits to get correct bit */
518 /* AU_is_encrypted bit */
519 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
520 if (selective_encryption){ /* bit used */
521 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_au_is_encrypted,
522 tvb, bit_offset, 1, FALSE); /*fetch 1 bit AU_is_encrypted */
524 else { /* bit unused */
525 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_unused_bits,
526 tvb, bit_offset, 1, FALSE); /*fetch 1 bit unused */
528 switch (set_version){ /* ISMACryp version? */
531 add_bits(poffset, -7); /* move back 7 bits for reserved bits */
532 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
533 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_reserved_bits,
534 tvb, bit_offset, 7, FALSE); /*fetch 7 bits reserved */
535 add_bits(poffset,8); /* offset to next byte */
538 /* Slice_start bit */
539 add_bits(poffset, -1); /* move back 1 bit for slice_start */
540 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
541 if (slice_indication){
542 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_slice_start,
543 tvb, bit_offset, 1, FALSE); /*fetch 1 bit slice_start */
545 else { /* bit unused */
546 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_unused_bits,
547 tvb, bit_offset, 1, FALSE); /*fetch 1 bit unused */
549 add_bits(poffset, -1); /* move back 1 bit for slice_end */
552 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
553 if (slice_indication){
554 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_slice_end,
555 tvb, bit_offset, 1, FALSE); /*fetch 1 bit Slice_end */
557 else { /* bit unused */
558 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_unused_bits,
559 tvb, bit_offset, 1, FALSE); /*fetch 1 bit unused */
561 add_bits(poffset, -3); /* move back 3 bits for padding_bitcount */
563 /* Padding_bitcount bits */
564 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
565 if (padding_indication){
566 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_padding_bitcount,
567 tvb, bit_offset, 3, FALSE); /*fetch 3 bits padding_bitcount */
569 else { /* bits unused */
570 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_unused_bits,
571 tvb, bit_offset, 3, FALSE); /*fetch 3 bits unused */
573 add_bits(poffset, -2); /* move back 2 bits for reserved bits */
576 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
577 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_byte_tree, hf_ismacryp_reserved_bits,
578 tvb, bit_offset, 2, FALSE); /*fetch 2 bits reserved */
579 add_bits(poffset,8); /* offset to next byte */
582 DISSECTOR_ASSERT_NOT_REACHED();
584 } /* end switch set_version */
585 } /* end selective encryption */
587 if (first_au_flag == TRUE && iv_length != 0)
589 ismacryp_item = proto_tree_add_item(ismacryp_header_tree, hf_ismacryp_iv, tvb, poffset->offset_bytes, iv_length, FALSE);
590 proto_item_append_text(ismacryp_item, ": Length=%d bytes",iv_length); /* add IV info */
591 if ( check_col( pinfo->cinfo, COL_INFO) ) {
592 col_append_fstr( pinfo->cinfo, COL_INFO,
593 ", IV=0x%s", tvb_bytes_to_str_punct(tvb, poffset->offset_bytes, iv_length,' '));
595 poffset->offset_bytes+=iv_length; /* add IV length to offset_bytes */
598 if (first_au_flag == FALSE && delta_iv_length != 0)
600 ismacryp_item = proto_tree_add_item(ismacryp_header_tree, hf_ismacryp_delta_iv,
601 tvb, poffset->offset_bytes, delta_iv_length, FALSE);
602 proto_item_append_text(ismacryp_item, ": Length=%d bytes",delta_iv_length); /* add delta IV info */
603 if ( check_col( pinfo->cinfo, COL_INFO) ) {
604 col_append_fstr( pinfo->cinfo, COL_INFO,
605 ", Delta IV=0x%s", tvb_bytes_to_str_punct(tvb, poffset->offset_bytes, delta_iv_length,' '));
607 poffset->offset_bytes+=iv_length; /* add IV length to offset_bytes */
610 if ( key_indicator_length != 0 && ( first_au_flag == TRUE || key_indicator_per_au_flag == TRUE) )
612 /* (first AU or KI for each AU) and non-zero KeyIndicator size */
613 ismacryp_item = proto_tree_add_item(ismacryp_header_tree, hf_ismacryp_key_indicator,
614 tvb, poffset->offset_bytes, key_indicator_length, FALSE);
615 proto_item_append_text(ismacryp_item,": Length=%d bytes",key_indicator_length); /* add KI info */
616 if ( check_col( pinfo->cinfo, COL_INFO) ) {
617 col_append_fstr( pinfo->cinfo, COL_INFO,
618 ", KI=0x%s", tvb_bytes_to_str_punct(tvb, poffset->offset_bytes, key_indicator_length,' '));
620 poffset->offset_bytes+=key_indicator_length; /* add KI length to offset_bytes */
623 if (au_size_length != 0) /* in bits */
625 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
626 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree,hf_ismacryp_au_size,
627 tvb, bit_offset, au_size_length, FALSE);
628 proto_item_append_text(ismacryp_item, " bytes: Length=%d bits",au_size_length); /* add AU size info */
629 bit_offset+=au_size_length;
630 add_bits(poffset, au_size_length);
633 if (first_au_flag == TRUE && au_index_length != 0) /* first AU and non-zero AU size */
635 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
636 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree,hf_ismacryp_au_index,
637 tvb, bit_offset, au_index_length, FALSE);
638 proto_item_append_text(ismacryp_item, " bits: Length=%d bits",au_index_length); /* add AU index info */
639 bit_offset+=au_index_length;
640 add_bits(poffset, au_index_length);
643 if (first_au_flag == FALSE && au_index_delta_length != 0) /* not first AU and non-zero AU delta size */
645 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
646 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree,hf_ismacryp_au_index_delta,
647 tvb, bit_offset, au_index_delta_length, FALSE);
648 proto_item_append_text(ismacryp_item, ": Length=%d bits", au_index_delta_length); /* add AU index info */
649 bit_offset+=au_index_delta_length;
650 add_bits(poffset, au_index_delta_length);
652 /* CTS delta value */
653 if (cts_delta_length != 0)
655 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
656 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree, hf_ismacryp_cts_flag,
657 tvb, bit_offset, 1, FALSE); /* read CTS flag */
658 add_bits(poffset, 1);
661 /* now fetch CTS delta value (remember offset 1 bit due to CTS flag) */
662 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
663 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree, hf_ismacryp_cts_delta,
664 tvb, bit_offset, cts_delta_length, FALSE); /* read CTS delta value */
665 proto_item_append_text(ismacryp_item, ": Length=%d bits",cts_delta_length); /* add CTS delta info */
666 add_bits(poffset, cts_delta_length);
669 /* DTS delta value */
670 if (dts_delta_length != 0)
672 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
673 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree, hf_ismacryp_dts_flag,
674 tvb, bit_offset, 1, FALSE); /* read DTS flag */
675 add_bits(poffset, 1);
677 /* now fetch DTS delta value (remember offset x bits due to DTS flag) */
680 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
681 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree, hf_ismacryp_dts_delta,
682 tvb, bit_offset, dts_delta_length, FALSE); /* read DTS delta value */
683 proto_item_append_text(ismacryp_item, ": Length=%d bits",dts_delta_length); /* add DTS delta info */
684 add_bits(poffset, dts_delta_length);
688 if (random_access_indication != FALSE)
690 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
691 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree, hf_ismacryp_rap_flag,
692 tvb, bit_offset, 1, FALSE); /* read RAP flag */
693 add_bits(poffset, 1);
696 if (stream_state_indication != 0)
698 bit_offset = (poffset->offset_bytes)*8+poffset->offset_bits; /* offset in bits */
699 ismacryp_item = proto_tree_add_bits_item(ismacryp_header_tree, hf_ismacryp_stream_state,
700 tvb, bit_offset, stream_state_indication, FALSE); /* read stream state */
701 add_bits(poffset, stream_state_indication);
703 /* end header details */
707 /* add len_bits to offset bits and bytes, handling bits overflow */
708 static void add_bits(offset_struct* poffset, gint len_bits)
711 nbbitstotal=poffset->offset_bytes*8+(poffset->offset_bits)+len_bits; /* total offset in bits */
712 /* now calculate bytes and bit offsets */
713 poffset->offset_bytes=(nbbitstotal / 8); /* add integer no. of bytes */
714 poffset->offset_bits=(nbbitstotal % 8); /* add remaining bits */
717 void proto_register_ismacryp (void)
719 /* A header field is something you can search/filter on.
721 * We create a structure to register our fields. It consists of an
722 * array of hf_register_info structures, each of which are of the format
723 * {&(field id), {name, abbrev, type, display, strings, bitmask, blurb, HFILL}}.
725 static hf_register_info hf[] = {
727 { "Data", "ismacryp.data", FT_NONE, BASE_NONE, NULL, 0x0,
730 { &hf_ismacryp_length,
731 { "Total Length", "ismacryp.len", FT_UINT16, BASE_DEC, NULL, 0x0, /* length 2 bytes, print as decimal value */
734 { &hf_ismacryp_header,
735 { "AU Header", "ismacryp.header", FT_NONE, BASE_NONE, NULL, 0x0,
738 { &hf_ismacryp_header_length,
739 { "Header Length", "ismacryp.header.length", FT_UINT16, BASE_DEC, NULL, 0x0,
742 { &hf_ismacryp_au_headers_length,
743 { "AU Headers Length", "ismacryp.au_headers.length", FT_UINT16, BASE_DEC, NULL, 0x0,
746 { &hf_ismacryp_header_byte,
747 { "Header Byte", "ismacryp.header.byte", FT_NONE, BASE_NONE, NULL, 0x0, /* 1 byte */
750 { &hf_ismacryp_header_byte,
751 { "Header Byte", "ismacryp.header.byte", FT_NONE, BASE_NONE, NULL, 0x0,
755 { &hf_ismacryp_version,
756 { "Version", "ismacryp.version", FT_UINT8, BASE_HEX, NULL, 0x0, /* version 1 byte */
759 { &hf_ismacryp_message,
760 { "Message", "ismacryp.message", FT_NONE, BASE_NONE, NULL, 0x0,
763 { &hf_ismacryp_message_length,
764 { "Message Length", "ismacryp.message.len", FT_UINT16, BASE_DEC, NULL, 0x0, /* length 2 bytes, print as decimal value */
767 { &hf_ismacryp_parameter,
768 { "Parameter", "ismacryp.parameter", FT_NONE, BASE_NONE, NULL, 0x0,
771 { &hf_ismacryp_parameter_length,
772 { "Parameter Length", "ismacryp.parameter.len", FT_UINT16, BASE_DEC, NULL, 0x0, /* length 2 bytes, print as decimal value */
776 { "IV", "ismacryp.iv", FT_BYTES, BASE_NONE, NULL, 0x0, /* variable length */
779 { &hf_ismacryp_delta_iv,
780 { "Delta IV", "ismacryp.delta_iv", FT_BYTES, BASE_NONE, NULL, 0x0, /* variable length */
783 { &hf_ismacryp_key_indicator,
784 { "Key Indicator", "ismacryp.key_indicator", FT_BYTES, BASE_NONE, NULL, 0x0, /* variable length */
787 { &hf_ismacryp_parameter_value,
788 { "Parameter Value", "ismacryp.parameter.value", FT_NONE, BASE_NONE, NULL, 0x0,
791 { &hf_ismacryp_au_size,
792 { "AU size", "ismacryp.au.size", FT_UINT64, BASE_DEC, NULL, 0x0,
795 { &hf_ismacryp_au_index,
796 { "AU index", "ismacryp.au.index", FT_UINT64, BASE_DEC, NULL, 0x0,
799 { &hf_ismacryp_au_index_delta,
800 { "AU index delta", "ismacryp.au.index_delta", FT_UINT64, BASE_DEC, NULL, 0x0,
803 { &hf_ismacryp_cts_delta,
804 { "CTS delta", "ismacryp.cts_delta", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
807 { &hf_ismacryp_cts_flag,
808 { "CTS flag", "ismacryp.cts_flag", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
811 { &hf_ismacryp_dts_delta,
812 { "DTS delta", "ismacryp.dts_delta", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
815 { &hf_ismacryp_dts_flag,
816 { "DTS flag", "ismacryp.dts_flag", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
819 { &hf_ismacryp_rap_flag,
820 { "RAP flag", "ismacryp.rap_flag", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
823 { &hf_ismacryp_stream_state,
824 { "Stream state", "ismacryp.stream_state", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
827 { &hf_ismacryp_au_is_encrypted,
828 { "AU_is_encrypted flag", "ismacryp.au_is_encrypted", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
831 { &hf_ismacryp_slice_start,
832 { "Slice_start flag", "ismacryp.slice_start", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
835 { &hf_ismacryp_slice_end,
836 { "Slice_end flag", "ismacryp.slice_end", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
839 { &hf_ismacryp_padding_bitcount,
840 { "Padding_bitcount bits", "ismacryp.padding_bitcount", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
843 { &hf_ismacryp_padding,
844 { "Padding bits", "ismacryp.padding", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
847 { &hf_ismacryp_reserved_bits,
848 { "Reserved bits", "ismacryp.reserved", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
851 { &hf_ismacryp_unused_bits,
852 { "Unused bits", "ismacryp.unused", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
859 &ett_ismacryp_header,
860 &ett_ismacryp_header_byte,
861 &ett_ismacryp_message
864 static enum_val_t version_types[] = {
865 {PROTO_TAG_ISMACRYP_11, "ISMACryp v1.1", V11},
866 {PROTO_TAG_ISMACRYP_20, "ISMACryp v2.0", V20},
870 static enum_val_t mode_types[] = {
871 {"aac-hbr", "aac-hbr", AAC_HBR_MODE},
872 {"mpeg4-video", "mpeg4-video", MPEG4_VIDEO_MODE},
873 {"avc-video", "avc-video", AVC_VIDEO_MODE},
877 module_t *ismacryp_module;
879 proto_ismacryp = proto_register_protocol ("ISMACryp Protocol", "ISMACRYP", "ismacryp");
880 proto_register_field_array (proto_ismacryp, hf, array_length (hf));
881 proto_register_subtree_array (ett, array_length (ett));
883 /* Register our configuration options for ismacryp */
884 /* this registers our preferences, function proto_reg_handoff_ismacryp is called when preferences are applied */
885 ismacryp_module = prefs_register_protocol(proto_ismacryp, proto_reg_handoff_ismacryp);
887 prefs_register_uint_preference(ismacryp_module, "dynamic.payload.type",
888 "ISMACryp dynamic payload type",
889 "The dynamic payload type which will be interpreted as ISMACryp",
891 &pref_dynamic_payload_type);
893 prefs_register_enum_preference(ismacryp_module, "version",
896 &version_type, version_types, TRUE);
898 prefs_register_static_text_preference(ismacryp_module, "text_override",
899 "The following option allows the version to be set manually"
900 " and to override the version if detected from RTP payload type:",
901 "The following option allows the version to be set manually"
902 " and to override the version if detected from RTP payload type:");
904 prefs_register_bool_preference(ismacryp_module,
905 "override_rtp_pt","Override RTP payload type for version",
906 "Indicates whether or not the ISMACryp version deduced"
907 " from RTP payload type, if present, is used or whether the"
908 " version above is used",
911 /* ISMACryp v11 parameters */
912 prefs_register_static_text_preference(ismacryp_module,
914 "ISMACryp v1.1 parameters:",
915 "ISMACryp v1.1 parameters declared in SDP");
917 prefs_register_uint_preference(ismacryp_module,
918 "iv_length","ISMACrypIVLength (bytes)",
919 "Set the length of the IV in the ISMACryp AU Header in bytes",
922 prefs_register_uint_preference(ismacryp_module,
923 "delta_iv_length","ISMACrypDeltaIVLength (bytes)",
924 "Set the length of the Delta IV in the ISMACryp AU Header in bytes",
925 10, &delta_iv_length);
927 prefs_register_uint_preference(ismacryp_module,
928 "key_indicator_length","ISMACrypKeyIndicatorLength (bytes)",
929 "Set the length of the Key Indicator in the ISMACryp AU Header in bytes",
930 10, &key_indicator_length);
932 prefs_register_bool_preference(ismacryp_module,
933 "key_indicator_per_au_flag","ISMACrypKeyIndicatorPerAU (T/F)",
934 "Indicates whether or not the Key Indicator is present in all AU Headers (T/F)",
935 &key_indicator_per_au_flag);
937 prefs_register_bool_preference(ismacryp_module,
938 "selective_encryption","ISMACrypSelectiveEncryption (T/F)",
939 "Indicates whether or not selective encryption is enabled (T/F)",
940 &selective_encryption);
942 /* ISMACryp v20 parameters */
943 prefs_register_static_text_preference(ismacryp_module,
945 "ISMACryp v2.0 parameters:",
946 "ISMACryp v2.0 parameters declared in SDP");
948 prefs_register_bool_preference(ismacryp_module,
949 "slice_indication","ISMACrypSliceIndication (T/F)",
950 "Indicates whether or not slice start / end is present (T/F)",
953 prefs_register_bool_preference(ismacryp_module,
954 "padding_indication","ISMACrypPaddingIndication (T/F)",
955 "Indicates whether or not padding information is present (T/F)",
956 &padding_indication);
958 /* RFC3640 mode - ISMACryp v11 */
959 prefs_register_static_text_preference(ismacryp_module,
961 "Codec mode selection (RFC3640 for ISMACryp v1.1 only):",
962 "AU parameters set according to RFC3640 mode or user defined");
964 prefs_register_enum_preference(ismacryp_module,
968 &mode, mode_types, TRUE);
970 /* User defined mode */
971 prefs_register_bool_preference(ismacryp_module,
972 "user_mode","User mode (T/F)",
973 "Indicates use of user mode instead of RFC3640 modes (T/F)",
976 /* following preference values only used if user mode is selected above */
977 prefs_register_static_text_preference(ismacryp_module,
978 "user_defined_modes",
979 "Following parameters only valid and used for user mode:",
980 "AU parameters defined by the user");
982 /* ideally would grey this out or disable this if in user mode */
983 prefs_register_uint_preference(ismacryp_module,
984 "au_size_length","User mode: SizeLength (bits)",
985 "Set the length of the AU size in the AU Header in bits",
986 10, &pref_au_size_length);
988 prefs_register_uint_preference(ismacryp_module,
989 "au_index_length","User mode: IndexLength (bits)",
990 "Set the length of the AU index in the AU Header in bits",
991 10, &pref_au_index_length);
993 prefs_register_uint_preference(ismacryp_module,
994 "au_index_delta_length","User mode: IndexDeltaLength (bits)",
995 "Set the length of the AU delta index in the AU Header in bits",
996 10, &pref_au_index_delta_length);
998 prefs_register_uint_preference(ismacryp_module,
999 "cts_delta_length","User mode: CTSDeltaLength (bits)",
1000 "Set the length of the CTS delta field in the AU Header in bits",
1001 10, &pref_cts_delta_length);
1003 prefs_register_uint_preference(ismacryp_module,
1004 "dts_delta_length","User mode: DTSDeltaLength (bits)",
1005 "Set the length of the DTS delta field in the AU Header in bits",
1006 10, &pref_dts_delta_length);
1008 prefs_register_bool_preference(ismacryp_module,
1009 "random_access_indication","User mode: RandomAccessIndication (T/F)",
1010 "Indicates whether or not the RAP field is present in the AU Header (T/F)",
1011 &pref_random_access_indication);
1013 prefs_register_uint_preference(ismacryp_module,
1014 "stream_state_indication","User mode: StreamStateIndication (number of bits)",
1015 "Indicates the number of bits on which the stream state field is encoded"
1016 " in the AU Header (bits)",
1017 10, &pref_stream_state_indication);
1021 void proto_reg_handoff_ismacryp(void)
1023 static gboolean ismacryp_prefs_initialized=FALSE;
1024 static dissector_handle_t ismacryp_handle;
1025 static guint dynamic_payload_type;
1027 if (!ismacryp_prefs_initialized) {
1028 dissector_handle_t ismacryp_v11_handle;
1029 dissector_handle_t ismacryp_v20_handle;
1030 ismacryp_handle = create_dissector_handle(dissect_ismacryp, proto_ismacryp);
1031 ismacryp_v11_handle = create_dissector_handle(dissect_ismacryp_v11, proto_ismacryp);
1032 ismacryp_v20_handle = create_dissector_handle(dissect_ismacryp_v20, proto_ismacryp);
1033 ismacryp_prefs_initialized = TRUE;
1034 dissector_add_string("rtp_dyn_payload_type", "ISMACRYP", ismacryp_handle);
1035 dissector_add_string("rtp_dyn_payload_type", "enc-mpeg4-generic", ismacryp_v11_handle);
1036 dissector_add_string("rtp_dyn_payload_type", "enc-isoff-generic", ismacryp_v20_handle);
1038 else { /* ismacryp_prefs_initialized = TRUE */
1039 /* delete existing association of ismacryp with payload_type */
1040 if ( dynamic_payload_type > 95 ){
1041 dissector_delete("rtp.pt", dynamic_payload_type, ismacryp_handle);
1044 /* always do the following */
1045 dynamic_payload_type = pref_dynamic_payload_type; /*update payload_type to new value */
1046 if ( dynamic_payload_type > 95 ){
1047 dissector_add("rtp.pt", dynamic_payload_type, ismacryp_handle);