pylibsrtp-0.6.1/0000775000372000037200000000000013426702234014413 5ustar travistravis00000000000000pylibsrtp-0.6.1/docs/0000775000372000037200000000000013426702234015343 5ustar travistravis00000000000000pylibsrtp-0.6.1/docs/index.rst0000664000372000037200000000262313426702212017203 0ustar travistravis00000000000000pylibsrtp ========= |pypi-v| |pypi-pyversions| |pypi-l| |pypi-wheel| |travis| |codecov| .. |pypi-v| image:: https://img.shields.io/pypi/v/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-pyversions| image:: https://img.shields.io/pypi/pyversions/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-l| image:: https://img.shields.io/pypi/l/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-wheel| image:: https://img.shields.io/pypi/wheel/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |travis| image:: https://img.shields.io/travis/com/aiortc/pylibsrtp.svg :target: https://travis-ci.com/aiortc/pylibsrtp .. |codecov| image:: https://img.shields.io/codecov/c/github/aiortc/pylibsrtp.svg :target: https://codecov.io/gh/aiortc/pylibsrtp ``pylibsrtp`` is a Python wrapper around `libsrtp`_, making it possible to encrypt and decrypt Secure Real-time Transport Protocol (SRTP) packets from Python code. SRTP is a profile of the Real-time Transport Protocol (RTP) which provides confidentiality, message authentication, and replay protection. It is defined by `RFC 3711`_. You can install ``pylibsrtp`` with ``pip``: .. code-block:: console $ pip install pylibsrtp .. _libsrtp: https://github.com/cisco/libsrtp .. _RFC 3711: https://tools.ietf.org/html/rfc3711 .. toctree:: :maxdepth: 2 api license pylibsrtp-0.6.1/docs/Makefile0000664000372000037200000000113613426702212017000 0ustar travistravis00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = pylibsrtp SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)pylibsrtp-0.6.1/docs/api.rst0000664000372000037200000000024513426702212016643 0ustar travistravis00000000000000API Reference ============= .. automodule:: pylibsrtp .. autoclass:: Error .. autoclass:: Policy :members: .. autoclass:: Session :members: pylibsrtp-0.6.1/docs/license.rst0000664000372000037200000000006013426702212017507 0ustar travistravis00000000000000License ------- .. literalinclude:: ../LICENSE pylibsrtp-0.6.1/docs/conf.py0000664000372000037200000001254413426702212016644 0ustar travistravis00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # pylibsrtp documentation build configuration file, created by # sphinx-quickstart on Thu Feb 8 17:22:14 2018. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os, sys # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('..')) # Mock out binding class MockLib: ssrc_undefined = 0 ssrc_specific = 1 ssrc_any_inbound = 2 ssrc_any_outbound = 3 def srtp_init(self): pass class MockBinding: ffi = None lib = MockLib() sys.modules.update({'pylibsrtp._binding': MockBinding()}) # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General information about the project. project = 'pylibsrtp' copyright = u'2018, Jeremy Lainé' author = u'Jeremy Lainé' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '' # The full version, including alpha/beta/rc tags. release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = { 'github_button': True, 'github_user': 'aiortc', 'github_repo': 'pylibsrtp', } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # This is required for the alabaster theme # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars html_sidebars = { '**': [ 'relations.html', # needs 'show_related': True theme option to display 'searchbox.html', ] } # -- Options for HTMLHelp output ------------------------------------------ # Output file base name for HTML help builder. htmlhelp_basename = 'pylibsrtpdoc' # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'pylibsrtp.tex', 'pylibsrtp Documentation', u'Jeremy Lainé', 'manual'), ] # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'pylibsrtp', 'pylibsrtp Documentation', [author], 1) ] # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'pylibsrtp', 'pylibsrtp Documentation', author, 'pylibsrtp', 'One line description of project.', 'Miscellaneous'), ] pylibsrtp-0.6.1/README.rst0000664000372000037200000000523313426702212016101 0ustar travistravis00000000000000pylibsrtp ========= |rtd| |pypi-v| |pypi-pyversions| |pypi-l| |pypi-wheel| |travis| |codecov| .. |rtd| image:: https://readthedocs.org/projects/pylibsrtp/badge/?version=latest :target: https://pylibsrtp.readthedocs.io/ .. |pypi-v| image:: https://img.shields.io/pypi/v/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-pyversions| image:: https://img.shields.io/pypi/pyversions/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-l| image:: https://img.shields.io/pypi/l/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-wheel| image:: https://img.shields.io/pypi/wheel/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |travis| image:: https://img.shields.io/travis/com/aiortc/pylibsrtp.svg :target: https://travis-ci.com/aiortc/pylibsrtp .. |codecov| image:: https://img.shields.io/codecov/c/github/aiortc/pylibsrtp.svg :target: https://codecov.io/gh/aiortc/pylibsrtp What is ``pylibsrtp``? ---------------------- ``pylibsrtp`` is a Python wrapper around `libsrtp`_, making it possible to encrypt and decrypt Secure Real-time Transport Protocol (SRTP) packets from Python code. SRTP is a profile of the Real-time Transport Protocol (RTP) which provides confidentiality, message authentication, and replay protection. It is defined by `RFC 3711`_. You can install ``pylibsrtp`` with ``pip``: .. code-block:: console $ pip install pylibsrtp To learn more about ``pylibsrtp`` please `read the documentation`_. .. _libsrtp: https://github.com/cisco/libsrtp .. _RFC 3711: https://tools.ietf.org/html/rfc3711 .. _read the documentation: https://pylibsrtp.readthedocs.io/en/stable/ Example ------- .. code:: python #!/usr/bin/env python from pylibsrtp import Policy, Session key = (b'\x00' * 30) rtp = b'\x80\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + (b'\xd4' * 160) # protect RTP tx_policy = Policy(key=key, ssrc_type=Policy.SSRC_ANY_OUTBOUND) tx_session = Session(policy=tx_policy) srtp = tx_session.protect(rtp) # unprotect RTP rx_policy = Policy(key=key, ssrc_type=Policy.SSRC_ANY_INBOUND) rx_session = Session(policy=rx_policy) rtp2 = rx_session.unprotect(srtp) # check roundtrip worked! assert rtp2 == rtp Building pylibsrtp ------------------ If you wish to build pylibsrtp yourself, you will need libsrtp version 2.0 or better. On Debian/Ubuntu run: .. code-block:: console $ apt install libsrtp2-dev On OS X run: .. code-block:: console $ brew install srtp License ------- ``pylibsrtp`` is released under the `BSD license`_. .. _BSD license: https://pylibsrtp.readthedocs.io/en/stable/license.html pylibsrtp-0.6.1/setup.py0000664000372000037200000000246313426702212016126 0ustar travistravis00000000000000import os.path import sys import setuptools root_dir = os.path.abspath(os.path.dirname(__file__)) readme_file = os.path.join(root_dir, 'README.rst') with open(readme_file, encoding='utf-8') as f: long_description = f.read() if os.environ.get('READTHEDOCS') == 'True': cffi_modules=[] else: cffi_modules=['src/build_srtp.py:ffibuilder'] setuptools.setup( name='pylibsrtp', version='0.6.1', description='Python wrapper around the libsrtp library', long_description=long_description, url='https://github.com/aiortc/pylibsrtp', author='Jeremy Lainé', author_email='jeremy.laine@m4x.org', license='BSD', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Topic :: Communications :: Telephony', 'Topic :: Security :: Cryptography', ], cffi_modules=cffi_modules, packages=['pylibsrtp'], install_requires=['cffi>=1.0.0'], setup_requires=['cffi>=1.0.0'], ) pylibsrtp-0.6.1/LICENSE0000664000372000037200000000274613426702212015425 0ustar travistravis00000000000000Copyright (c) 2018 Jeremy Lainé. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of pylibsrtp nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. pylibsrtp-0.6.1/pylibsrtp.egg-info/0000775000372000037200000000000013426702234020135 5ustar travistravis00000000000000pylibsrtp-0.6.1/pylibsrtp.egg-info/top_level.txt0000664000372000037200000000001213426702234022660 0ustar travistravis00000000000000pylibsrtp pylibsrtp-0.6.1/pylibsrtp.egg-info/requires.txt0000664000372000037200000000001413426702234022530 0ustar travistravis00000000000000cffi>=1.0.0 pylibsrtp-0.6.1/pylibsrtp.egg-info/PKG-INFO0000664000372000037200000001030613426702234021232 0ustar travistravis00000000000000Metadata-Version: 1.1 Name: pylibsrtp Version: 0.6.1 Summary: Python wrapper around the libsrtp library Home-page: https://github.com/aiortc/pylibsrtp Author: Jeremy Lainé Author-email: jeremy.laine@m4x.org License: BSD Description: pylibsrtp ========= |rtd| |pypi-v| |pypi-pyversions| |pypi-l| |pypi-wheel| |travis| |codecov| .. |rtd| image:: https://readthedocs.org/projects/pylibsrtp/badge/?version=latest :target: https://pylibsrtp.readthedocs.io/ .. |pypi-v| image:: https://img.shields.io/pypi/v/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-pyversions| image:: https://img.shields.io/pypi/pyversions/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-l| image:: https://img.shields.io/pypi/l/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-wheel| image:: https://img.shields.io/pypi/wheel/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |travis| image:: https://img.shields.io/travis/com/aiortc/pylibsrtp.svg :target: https://travis-ci.com/aiortc/pylibsrtp .. |codecov| image:: https://img.shields.io/codecov/c/github/aiortc/pylibsrtp.svg :target: https://codecov.io/gh/aiortc/pylibsrtp What is ``pylibsrtp``? ---------------------- ``pylibsrtp`` is a Python wrapper around `libsrtp`_, making it possible to encrypt and decrypt Secure Real-time Transport Protocol (SRTP) packets from Python code. SRTP is a profile of the Real-time Transport Protocol (RTP) which provides confidentiality, message authentication, and replay protection. It is defined by `RFC 3711`_. You can install ``pylibsrtp`` with ``pip``: .. code-block:: console $ pip install pylibsrtp To learn more about ``pylibsrtp`` please `read the documentation`_. .. _libsrtp: https://github.com/cisco/libsrtp .. _RFC 3711: https://tools.ietf.org/html/rfc3711 .. _read the documentation: https://pylibsrtp.readthedocs.io/en/stable/ Example ------- .. code:: python #!/usr/bin/env python from pylibsrtp import Policy, Session key = (b'\x00' * 30) rtp = b'\x80\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + (b'\xd4' * 160) # protect RTP tx_policy = Policy(key=key, ssrc_type=Policy.SSRC_ANY_OUTBOUND) tx_session = Session(policy=tx_policy) srtp = tx_session.protect(rtp) # unprotect RTP rx_policy = Policy(key=key, ssrc_type=Policy.SSRC_ANY_INBOUND) rx_session = Session(policy=rx_policy) rtp2 = rx_session.unprotect(srtp) # check roundtrip worked! assert rtp2 == rtp Building pylibsrtp ------------------ If you wish to build pylibsrtp yourself, you will need libsrtp version 2.0 or better. On Debian/Ubuntu run: .. code-block:: console $ apt install libsrtp2-dev On OS X run: .. code-block:: console $ brew install srtp License ------- ``pylibsrtp`` is released under the `BSD license`_. .. _BSD license: https://pylibsrtp.readthedocs.io/en/stable/license.html Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Communications :: Telephony Classifier: Topic :: Security :: Cryptography pylibsrtp-0.6.1/pylibsrtp.egg-info/dependency_links.txt0000664000372000037200000000000113426702234024203 0ustar travistravis00000000000000 pylibsrtp-0.6.1/pylibsrtp.egg-info/SOURCES.txt0000664000372000037200000000053013426702234022017 0ustar travistravis00000000000000LICENSE MANIFEST.in README.rst setup.cfg setup.py docs/Makefile docs/api.rst docs/conf.py docs/index.rst docs/license.rst pylibsrtp/__init__.py pylibsrtp/tests.py pylibsrtp.egg-info/PKG-INFO pylibsrtp.egg-info/SOURCES.txt pylibsrtp.egg-info/dependency_links.txt pylibsrtp.egg-info/requires.txt pylibsrtp.egg-info/top_level.txt src/build_srtp.pypylibsrtp-0.6.1/pylibsrtp/0000775000372000037200000000000013426702234016443 5ustar travistravis00000000000000pylibsrtp-0.6.1/pylibsrtp/__init__.py0000664000372000037200000001426213426702212020555 0ustar travistravis00000000000000from socket import htonl from ._binding import ffi, lib __all__ = ['Error', 'Policy', 'Session'] ERRORS = [ "nothing to report", "unspecified failure", "unsupported parameter", "couldn't allocate memory", "couldn't deallocate properly", "couldn't initialize", "can't process as much data as requested", "authentication failure", "cipher failure", "replay check failed (bad index)", "replay check failed (index too old)", "algorithm failed test routine", "unsupported operation", "no appropriate context found", "unable to perform desired validation", "can't use key any more", "error in use of socket", "error in use POSIX signals", "nonce check failed", "couldn't read data", "couldn't write data", "error parsing data", "error encoding data", "error while using semaphores", "error while using pfkey", "error MKI present in packet is invalid", "packet index is too old to consider", "packet index advanced, reset needed", ] SRTP_MAX_TRAILER_LEN = 16 + 128 class Error(Exception): """ Error that occurred making a `libsrtp` API call. """ pass def _srtp_assert(rc): if rc != lib.srtp_err_status_ok: raise Error(ERRORS[rc]) class Policy: """ Policy for single SRTP stream. """ #: Indicates an undefined SSRC type SSRC_UNDEFINED = lib.ssrc_undefined #: Indicates a specific SSRC value SSRC_SPECIFIC = lib.ssrc_specific #: Indicates any inbound SSRC value SSRC_ANY_INBOUND = lib.ssrc_any_inbound #: Indicates any inbound SSRC value SSRC_ANY_OUTBOUND = lib.ssrc_any_outbound def __init__(self, key=None, ssrc_type=SSRC_UNDEFINED, ssrc_value=0): self._policy = ffi.new('srtp_policy_t *') lib.srtp_crypto_policy_set_rtp_default( ffi.addressof(self._policy.rtp)) lib.srtp_crypto_policy_set_rtcp_default( ffi.addressof(self._policy.rtcp)) self.key = key self.ssrc_type = ssrc_type self.ssrc_value = ssrc_value @property def allow_repeat_tx(self): """ Whether retransmissions of packets with the same sequence number are allowed. """ return self._policy.allow_repeat_tx == 1 @allow_repeat_tx.setter def allow_repeat_tx(self, allow_repeat_tx): self._policy.allow_repeat_tx = 1 if allow_repeat_tx else 0 @property def key(self): """ The SRTP master key. """ if self.__cdata is None: return None return ffi.buffer(self.__cdata) @key.setter def key(self, key): if key is None: self.__cdata = None self._policy.key = ffi.NULL return if not isinstance(key, bytes): raise TypeError('key must be bytes') self.__cdata = ffi.new('unsigned char[]', len(key)) self.__cdata[0:len(key)] = key self._policy.key = self.__cdata @property def ssrc_type(self): """ The SSRC type. """ return self._policy.ssrc.type @ssrc_type.setter def ssrc_type(self, ssrc_type): self._policy.ssrc.type = ssrc_type @property def ssrc_value(self): """ The SSRC value, if it is not a wildcard. """ return self._policy.ssrc.value @ssrc_value.setter def ssrc_value(self, ssrc_value): self._policy.ssrc.value = ssrc_value @property def window_size(self): """ The window size to use for replay protection. """ return self._policy.window_size @window_size.setter def window_size(self, window_size): self._policy.window_size = window_size class Session: """ SRTP session, which may comprise several streams. If `policy` is not specified, streams should be added later using the :func:`add_stream` method. """ def __init__(self, policy=None): srtp = ffi.new('srtp_t *') if policy is None: _policy = ffi.NULL else: _policy = policy._policy _srtp_assert(lib.srtp_create(srtp, _policy)) self._cdata = ffi.new('char[]', 1500) self._buffer = ffi.buffer(self._cdata) self._srtp = ffi.gc(srtp, lambda x: lib.srtp_dealloc(x[0])) def add_stream(self, policy): """ Add a stream to the SRTP session, applying the given `policy` to the stream. :param policy: :class:`Policy` """ _srtp_assert(lib.srtp_add_stream(self._srtp[0], policy._policy)) def remove_stream(self, ssrc): """ Remove the stream with the given `ssrc` from the SRTP session. :param ssrc: :class:`int` """ _srtp_assert(lib.srtp_remove_stream(self._srtp[0], htonl(ssrc))) def protect(self, packet): """ Apply SRTP protection to the RTP `packet`. :param packet: :class:`bytes` :rtype: :class:`bytes` """ return self.__process(packet, lib.srtp_protect, SRTP_MAX_TRAILER_LEN) def protect_rtcp(self, packet): """ Apply SRTCP protection to the RTCP `packet`. :param packet: :class:`bytes` :rtype: :class:`bytes` """ return self.__process(packet, lib.srtp_protect_rtcp, SRTP_MAX_TRAILER_LEN) def unprotect(self, packet): """ Verify SRTP protection of the SRTP packet. :param packet: :class:`bytes` :rtype: :class:`bytes` """ return self.__process(packet, lib.srtp_unprotect) def unprotect_rtcp(self, packet): """ Verify SRTCP protection of the SRTCP packet. :param packet: :class:`bytes` :rtype: :class:`bytes` """ return self.__process(packet, lib.srtp_unprotect_rtcp) def __process(self, data, func, trailer=0): if not isinstance(data, bytes): raise TypeError('packet must be bytes') if len(data) > len(self._cdata) - trailer: raise ValueError('packet is too long') len_p = ffi.new('int *') len_p[0] = len(data) self._buffer[0:len(data)] = data _srtp_assert(func(self._srtp[0], self._cdata, len_p)) return self._buffer[0:len_p[0]] lib.srtp_init() pylibsrtp-0.6.1/pylibsrtp/tests.py0000664000372000037200000001316313426702212020157 0ustar travistravis00000000000000from unittest import TestCase from pylibsrtp import Error, Policy, Session RTP = ( b'\x80\x08\x00\x00' # version, packet type, sequence number b'\x00\x00\x00\x00' # timestamp b'\x00\x00\x30\x39' # ssrc: 12345 ) + (b'\xd4' * 160) RTCP = ( b'\x80\xc8\x00\x06\xf3\xcb\x20\x01\x83\xab\x03\xa1\xeb\x02\x0b\x3a' b'\x00\x00\x94\x20\x00\x00\x00\x9e\x00\x00\x9b\x88' ) # Set key to predetermined value KEY = ( b'\x00\x01\x02\x03\x04\x05\x06\x07' b'\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' b'\x10\x11\x12\x13\x14\x15\x16\x17' b'\x18\x19\x1a\x1b\x1c\x1d' ) class PolicyTest(TestCase): def test_allow_repeat_tx(self): policy = Policy() self.assertEqual(policy.allow_repeat_tx, False) policy.allow_repeat_tx = True self.assertEqual(policy.allow_repeat_tx, True) policy.allow_repeat_tx = False self.assertEqual(policy.allow_repeat_tx, False) policy.allow_repeat_tx = 1 self.assertEqual(policy.allow_repeat_tx, True) policy.allow_repeat_tx = 0 self.assertEqual(policy.allow_repeat_tx, False) def test_key(self): policy = Policy() self.assertEqual(policy.key, None) policy.key = KEY self.assertEqual(policy.key, KEY) policy.key = None self.assertEqual(policy.key, None) with self.assertRaises(TypeError) as cm: policy.key = 1234 self.assertEqual(policy.key, None) self.assertEqual(str(cm.exception), 'key must be bytes') def test_ssrc_type(self): policy = Policy() self.assertEqual(policy.ssrc_type, Policy.SSRC_UNDEFINED) policy.ssrc_type = Policy.SSRC_ANY_INBOUND self.assertEqual(policy.ssrc_type, Policy.SSRC_ANY_INBOUND) def test_ssrc_value(self): policy = Policy() self.assertEqual(policy.ssrc_value, 0) policy.ssrc_value = 12345 self.assertEqual(policy.ssrc_value, 12345) def test_window_size(self): policy = Policy() self.assertEqual(policy.window_size, 0) policy.window_size = 1024 self.assertEqual(policy.window_size, 1024) class SessionTest(TestCase): def test_no_key(self): policy = Policy(ssrc_type=Policy.SSRC_ANY_OUTBOUND) with self.assertRaises(Error) as cm: Session(policy=policy) self.assertEqual(str(cm.exception), 'unsupported parameter') def test_add_remove_stream(self): # protect RTP tx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_SPECIFIC, ssrc_value=12345)) protected = tx_session.protect(RTP) self.assertEqual(len(protected), 182) # add stream and unprotect RTP rx_session = Session() rx_session.add_stream(Policy( key=KEY, ssrc_type=Policy.SSRC_SPECIFIC, ssrc_value=12345)) unprotected = rx_session.unprotect(protected) self.assertEqual(len(unprotected), 172) self.assertEqual(unprotected, RTP) # remove stream rx_session.remove_stream(12345) # try removing stream again with self.assertRaises(Error) as cm: rx_session.remove_stream(12345) self.assertEqual(str(cm.exception), 'no appropriate context found') def test_rtp_any_ssrc(self): # protect RTP tx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_ANY_OUTBOUND)) protected = tx_session.protect(RTP) self.assertEqual(len(protected), 182) # bad type with self.assertRaises(TypeError) as cm: tx_session.protect(4567) self.assertEqual(str(cm.exception), 'packet must be bytes') # bad length with self.assertRaises(ValueError) as cm: tx_session.protect(b'0' * 1500) self.assertEqual(str(cm.exception), 'packet is too long') # unprotect RTP rx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_ANY_INBOUND)) unprotected = rx_session.unprotect(protected) self.assertEqual(len(unprotected), 172) self.assertEqual(unprotected, RTP) def test_rtcp_any_ssrc(self): # protect RCTP tx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_ANY_OUTBOUND)) protected = tx_session.protect_rtcp(RTCP) self.assertEqual(len(protected), 42) # bad type with self.assertRaises(TypeError) as cm: tx_session.protect_rtcp(4567) self.assertEqual(str(cm.exception), 'packet must be bytes') # bad length with self.assertRaises(ValueError) as cm: tx_session.protect_rtcp(b'0' * 1500) self.assertEqual(str(cm.exception), 'packet is too long') # unprotect RTCP rx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_ANY_INBOUND)) unprotected = rx_session.unprotect_rtcp(protected) self.assertEqual(len(unprotected), 28) self.assertEqual(unprotected, RTCP) def test_rtp_specific_ssrc(self): # protect RTP tx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_SPECIFIC, ssrc_value=12345)) protected = tx_session.protect(RTP) self.assertEqual(len(protected), 182) # unprotect RTP rx_session = Session(policy=Policy( key=KEY, ssrc_type=Policy.SSRC_SPECIFIC, ssrc_value=12345)) unprotected = rx_session.unprotect(protected) self.assertEqual(len(unprotected), 172) self.assertEqual(unprotected, RTP) pylibsrtp-0.6.1/setup.cfg0000664000372000037200000000010613426702234016231 0ustar travistravis00000000000000[flake8] max-line-length = 100 [egg_info] tag_build = tag_date = 0 pylibsrtp-0.6.1/MANIFEST.in0000664000372000037200000000012613426702212016144 0ustar travistravis00000000000000include LICENSE recursive-include docs *.py *.rst Makefile recursive-include src *.py pylibsrtp-0.6.1/PKG-INFO0000664000372000037200000001030613426702234015510 0ustar travistravis00000000000000Metadata-Version: 1.1 Name: pylibsrtp Version: 0.6.1 Summary: Python wrapper around the libsrtp library Home-page: https://github.com/aiortc/pylibsrtp Author: Jeremy Lainé Author-email: jeremy.laine@m4x.org License: BSD Description: pylibsrtp ========= |rtd| |pypi-v| |pypi-pyversions| |pypi-l| |pypi-wheel| |travis| |codecov| .. |rtd| image:: https://readthedocs.org/projects/pylibsrtp/badge/?version=latest :target: https://pylibsrtp.readthedocs.io/ .. |pypi-v| image:: https://img.shields.io/pypi/v/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-pyversions| image:: https://img.shields.io/pypi/pyversions/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-l| image:: https://img.shields.io/pypi/l/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |pypi-wheel| image:: https://img.shields.io/pypi/wheel/pylibsrtp.svg :target: https://pypi.python.org/pypi/pylibsrtp .. |travis| image:: https://img.shields.io/travis/com/aiortc/pylibsrtp.svg :target: https://travis-ci.com/aiortc/pylibsrtp .. |codecov| image:: https://img.shields.io/codecov/c/github/aiortc/pylibsrtp.svg :target: https://codecov.io/gh/aiortc/pylibsrtp What is ``pylibsrtp``? ---------------------- ``pylibsrtp`` is a Python wrapper around `libsrtp`_, making it possible to encrypt and decrypt Secure Real-time Transport Protocol (SRTP) packets from Python code. SRTP is a profile of the Real-time Transport Protocol (RTP) which provides confidentiality, message authentication, and replay protection. It is defined by `RFC 3711`_. You can install ``pylibsrtp`` with ``pip``: .. code-block:: console $ pip install pylibsrtp To learn more about ``pylibsrtp`` please `read the documentation`_. .. _libsrtp: https://github.com/cisco/libsrtp .. _RFC 3711: https://tools.ietf.org/html/rfc3711 .. _read the documentation: https://pylibsrtp.readthedocs.io/en/stable/ Example ------- .. code:: python #!/usr/bin/env python from pylibsrtp import Policy, Session key = (b'\x00' * 30) rtp = b'\x80\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' + (b'\xd4' * 160) # protect RTP tx_policy = Policy(key=key, ssrc_type=Policy.SSRC_ANY_OUTBOUND) tx_session = Session(policy=tx_policy) srtp = tx_session.protect(rtp) # unprotect RTP rx_policy = Policy(key=key, ssrc_type=Policy.SSRC_ANY_INBOUND) rx_session = Session(policy=rx_policy) rtp2 = rx_session.unprotect(srtp) # check roundtrip worked! assert rtp2 == rtp Building pylibsrtp ------------------ If you wish to build pylibsrtp yourself, you will need libsrtp version 2.0 or better. On Debian/Ubuntu run: .. code-block:: console $ apt install libsrtp2-dev On OS X run: .. code-block:: console $ brew install srtp License ------- ``pylibsrtp`` is released under the `BSD license`_. .. _BSD license: https://pylibsrtp.readthedocs.io/en/stable/license.html Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Communications :: Telephony Classifier: Topic :: Security :: Cryptography pylibsrtp-0.6.1/src/0000775000372000037200000000000013426702234015202 5ustar travistravis00000000000000pylibsrtp-0.6.1/src/build_srtp.py0000664000372000037200000000324713426702212017725 0ustar travistravis00000000000000import sys from cffi import FFI libraries = ['srtp2'] if sys.platform == 'win32': libraries += ['ws2_32'] ffibuilder = FFI() ffibuilder.set_source('pylibsrtp._binding', '#include ', libraries=libraries) ffibuilder.cdef(""" typedef enum { srtp_err_status_ok = 0, ... } srtp_err_status_t; typedef enum { ssrc_undefined = 0, ssrc_specific = 1, ssrc_any_inbound = 2, ssrc_any_outbound = 3 } srtp_ssrc_type_t; typedef struct srtp_crypto_policy_t { ...; } srtp_crypto_policy_t; typedef struct { srtp_ssrc_type_t type; unsigned int value; } srtp_ssrc_t; typedef struct srtp_ctx_t_ srtp_ctx_t; typedef srtp_ctx_t *srtp_t; typedef struct srtp_policy_t { srtp_ssrc_t ssrc; srtp_crypto_policy_t rtp; srtp_crypto_policy_t rtcp; unsigned char *key; unsigned long window_size; int allow_repeat_tx; ...; } srtp_policy_t; srtp_err_status_t srtp_init(void); srtp_err_status_t srtp_create(srtp_t *session, const srtp_policy_t *policy); srtp_err_status_t srtp_dealloc(srtp_t s); void srtp_crypto_policy_set_rtp_default(srtp_crypto_policy_t *p); void srtp_crypto_policy_set_rtcp_default(srtp_crypto_policy_t *p); srtp_err_status_t srtp_add_stream(srtp_t session, const srtp_policy_t *policy); srtp_err_status_t srtp_remove_stream(srtp_t session, unsigned int ssrc); srtp_err_status_t srtp_protect(srtp_t ctx, void *rtp_hdr, int *len_ptr); srtp_err_status_t srtp_protect_rtcp(srtp_t ctx, void *rtcp_hdr, int *pkt_octet_len); srtp_err_status_t srtp_unprotect(srtp_t ctx, void *srtp_hdr, int *len_ptr); srtp_err_status_t srtp_unprotect_rtcp(srtp_t ctx, void *srtcp_hdr, int *pkt_octet_len); """) if __name__ == "__main__": ffibuilder.compile(verbose=True)