pax_global_header00006660000000000000000000000064140364170660014521gustar00rootroot0000000000000052 comment=345f4b8d74f4123b97198e10a383f485f80946d8 PGPy-0.5.4/000077500000000000000000000000001403641706600123465ustar00rootroot00000000000000PGPy-0.5.4/.coveragerc000066400000000000000000000005141403641706600144670ustar00rootroot00000000000000[run] branch = False [report] exclude_lines = # keep the standard pragma pragma: no cover # skip abstract methods @(abc\.)?abstract # Python 2.x compatibility stuff if six.PY2: if six.PY3: def __nonzero__ # debug-only code def __repr__ # defensive code raise NotImplementedError PGPy-0.5.4/.editorconfig000066400000000000000000000002141403641706600150200ustar00rootroot00000000000000root = true [*] charset = utf-8 indent_style = space indent_size = 4 insert_final_newline = true end_of_line = lf [*.yml] indent_size = 2 PGPy-0.5.4/.github/000077500000000000000000000000001403641706600137065ustar00rootroot00000000000000PGPy-0.5.4/.github/workflows/000077500000000000000000000000001403641706600157435ustar00rootroot00000000000000PGPy-0.5.4/.github/workflows/tests.yml000066400000000000000000000052461403641706600176370ustar00rootroot00000000000000name: Tox Tests on: [push, pull_request] jobs: unit-tests: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-18.04] python-version: [2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Install Tox run: pip3 install tox - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install requirements run: | sed -i -e 's/^/#/' tests/gnupghome/gpg-agent.conf if [ "$(uname)" = "Darwin" ]; then ./install_dependencies.osx.sh; else ./install_dependencies.linux.sh; fi pip install tox 'PyYAML==5.2; python_version == "3.4"' - name: Run Tox run: ./tox.sh -e py # do some tests with LC_ALL=C to check for locale variance c-locale-test: runs-on: ubuntu-18.04 strategy: matrix: python-version: [2.7, 3.6] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install requirements run: | sed -i -e 's/^/#/' tests/gnupghome/gpg-agent.conf ./install_dependencies.linux.sh pip install tox 'PyYAML==5.2; python_version == "3.4"' - name: Run Tox run: ./tox.sh -e py env: LC_ALL: C # test setup.py using each tested version test-setup: runs-on: ubuntu-18.04 strategy: matrix: include: - python-version: 2.7 env: py27-setup - python-version: 3.4 env: py34-setup - python-version: 3.5 env: py35-setup - python-version: 3.6 env: py36-setup - python-version: 3.7 env: py37-setup - python-version: 3.8 env: py38-setup - python-version: 3.9 env: py39-setup steps: - uses: actions/checkout@v2 - name: Install tox run: pip3 install tox - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Run tox run: tox -e ${{ matrix.env }} # add a pep8 test pep8: runs-on: ubuntu-18.04 continue-on-error: true # pep8 failures shouldn't be considered fatal steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: 3.6 - name: Install tox run: pip install tox - name: Run tox run: tox -e pep8 PGPy-0.5.4/.gitignore000066400000000000000000000011651403641706600143410ustar00rootroot00000000000000# Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] # C extensions *.so # Distribution / packaging .Python env/ bin/ build/ develop-eggs/ dist/ eggs/ lib/ lib64/ parts/ sdist/ var/ *.egg-info/ .installed.cfg *.egg # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .coverage .cache nosetests.xml coverage.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject # Rope .ropeproject # Django stuff: *.log *.pot # Sphinx documentation docs/_build/ .idea random_seed /tests/gnupghome/private-keys-v1.d/* /tests/gnupghome/pubring.kbx* PGPy-0.5.4/.travis.yml000066400000000000000000000030461403641706600144620ustar00rootroot00000000000000dist: xenial os: - linux # - osx language: python python: - "3.9" - "3.8" - "3.7" - "3.6" - "3.5" - "3.4" - "2.7" - "pypy" - "pypy3" jobs: include: # add a pep8 test - python: 3.6 env: TOXENV=pep8 # test setup.py using each tested version - python: 3.9 env: TOXENV=py39-setup - python: 3.8 env: TOXENV=py38-setup - python: 3.7 env: TOXENV=py37-setup - python: 3.6 env: TOXENV=py36-setup - python: 3.5 env: TOXENV=py35-setup - python: 3.4 env: TOXENV=py34-setup - python: 2.7 env: TOXENV=py27-setup # do some tests with LC_ALL=C to check for locale variance - python: 3.6 env: LC_ALL=C - python: 2.7 env: LC_ALL=C allow_failures: # pep8 failures shouldn't be considered fatal - env: TOXENV=pep8 # pypy and pypy3 tests are just for fun - python: "pypy" - python: "pypy3" # osx, until it's working # - os: osx # install requirements install: - sed -i -e 's/^/#/' tests/gnupghome/gpg-agent.conf - ./install_dependencies.${TRAVIS_OS_NAME}.sh # ensure tox and coveralls are installed. pin PyYAML until we drop Python 3.4 - pip install tox 'PyYAML==5.2; python_version == "3.4"' # set TOXENV if it isn't yet before_script: - if [[ -z "$TOXENV" ]]; then export TOXENV=py${TRAVIS_PYTHON_VERSION//.}; fi - if [[ "${TRAVIS_PYTHON_VERSION}" == 'pypy' ]]; then export TOXENV=pypy; fi - if [[ "${TRAVIS_PYTHON_VERSION}" == 'pypy3' ]]; then export TOXENV=pypy3; fi # run tox script: - ./tox.sh PGPy-0.5.4/Brewfile000066400000000000000000000001271403641706600140300ustar00rootroot00000000000000brew "libffi" brew "gnupg2" brew "pgpdump" brew "openssl@1.1" brew "gpgme" brew "swig" PGPy-0.5.4/LICENSE000066400000000000000000000027401403641706600133560ustar00rootroot00000000000000Copyright (c) 2014-2021 Security Innovation, Inc 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 the {organization} 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. PGPy-0.5.4/MANIFEST.in000066400000000000000000000003771403641706600141130ustar00rootroot00000000000000include LICENSE include README.rst include requirements.txt include requirements-test.txt include requirements-rtd.txt recursive-include docs/ * recursive-include tests/ * recursive-exclude docs/build/ * recursive-exclude * *.pyc global-exclude .DS_Store PGPy-0.5.4/README.rst000066400000000000000000000040361403641706600140400ustar00rootroot00000000000000PGPy: Pretty Good Privacy for Python ==================================== .. image:: https://badge.fury.io/py/PGPy.svg :target: https://badge.fury.io/py/PGPy :alt: Latest stable version .. image:: https://travis-ci.com/SecurityInnovation/PGPy.svg?branch=master :target: https://travis-ci.com/SecurityInnovation/PGPy?branch=master :alt: Travis-CI .. image:: https://coveralls.io/repos/github/SecurityInnovation/PGPy/badge.svg?branch=master :target: https://coveralls.io/github/SecurityInnovation/PGPy?branch=master :alt: Coveralls .. image:: https://readthedocs.org/projects/pgpy/badge/?version=latest :target: https://pgpy.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status `PGPy` is a Python (2 and 3) library for implementing Pretty Good Privacy into Python programs, conforming to the OpenPGP specification per RFC 4880. Features -------- Currently, PGPy can load keys and signatures of all kinds in both ASCII armored and binary formats. It can create and verify RSA, DSA, and ECDSA signatures, at the moment. It can also encrypt and decrypt messages using RSA and ECDH. Installation ------------ To install PGPy, simply: .. code-block:: bash $ pip install PGPy Documentation ------------- `PGPy Documentation `_ on Read the Docs Discussion ---------- Please report any bugs found on the `issue tracker `_ You can also join ``#pgpy`` on Freenode to ask questions or get involved Requirements ------------ - Python 3 >= 3.4; Python 2 >= 2.7 Tested with: 3.7, 3.6, 3.5, 3.4, 2.7 - `Cryptography `_ - `enum34 `_ - `singledispatch `_ - `pyasn1 `_ - `six `_ License ------- BSD 3-Clause licensed. See the bundled `LICENSE `_ file for more details. PGPy-0.5.4/docs/000077500000000000000000000000001403641706600132765ustar00rootroot00000000000000PGPy-0.5.4/docs/Makefile000066400000000000000000000151531403641706600147430ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PGPy.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PGPy.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/PGPy" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PGPy" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." PGPy-0.5.4/docs/source/000077500000000000000000000000001403641706600145765ustar00rootroot00000000000000PGPy-0.5.4/docs/source/_ext/000077500000000000000000000000001403641706600155355ustar00rootroot00000000000000PGPy-0.5.4/docs/source/_ext/__init__.py000066400000000000000000000001331403641706600176430ustar00rootroot00000000000000""" Just a placeholder so _ext.js_progress can be used as the extension name in conf.py """PGPy-0.5.4/docs/source/_ext/progress.py000066400000000000000000000114601403641706600177550ustar00rootroot00000000000000__author__ = 'magreene' import collections import re from docutils import nodes from docutils.parsers.rst import Directive from docutils.statemachine import StringList class progress(nodes.General, nodes.Element): tagname = 'progress' class ProgressTable(Directive): has_content = True required_arguments = 1 final_argument_whitespace = True option_spec = {'text': str} def create_headrow(self, label="Progress", classes=('prog-top-label',)): hrow = nodes.row() hrow += nodes.entry('', nodes.paragraph(text=label), classes=['head'] + list(classes)) hrow += nodes.entry('', nodes.paragraph(text='PLACEHOLDER'), classes=['PLACEHOLDER']) return hrow def create_progtable(self, **attrs): _attrs = { 'classes': ['progress', 'outer', 'docutils', 'field-list'], 'colwidths': [20, 80] } _attrs.update(attrs) # create container elements node = nodes.table(classes=_attrs['classes']) tgroup = nodes.tgroup(cols=2) thead = thead = nodes.thead() thead += self.create_headrow() tbody = nodes.tbody() # tgroup gets: # - colspec # - thead # - tbody for w in _attrs['colwidths']: tgroup += nodes.colspec(colwidth=w) # assemble the hierarchy tgroup += thead tgroup += tbody node += tgroup # return the table return node def add_progbar(self, row, val, max): entry = nodes.entry(classes=['progcell', 'field-value']) pbar = progress(value=val, max=max) entry += pbar row.replace(row.children[-1], entry) def run(self): secid = [self.arguments[0].lower().replace(' ', '-')] section = nodes.section(ids=secid) section.document = self.state.document section += nodes.title(text=self.arguments[0]) # parse the 'text' option into the section, as a paragraph. self.state.nested_parse(StringList([self.options['text']], parent=self), 0, section) node = self.create_progtable() section.children[-1] += node head = node.children[0].children[-2].children[0] body = node.children[0].children[-1] comps = collections.OrderedDict() cur = "" for line in self.content: # new list nl = re.match(r'^:(?P.+):$', line) if nl is not None: if cur != "": # finish up shrow self.add_progbar(shrow, len([c for c in comps[cur] if c is True]), len(comps[cur])) cur = nl.groupdict()['component'] if cur not in comps: comps[cur] = [] # shrow is the section header row shrow = self.create_headrow(cur, classes=['field-name']) body += shrow continue nl = re.match(r'^\s+- (?P[^,]+),\s+(?P(True|False))(, (?P.+)$)?', line) if nl is not None: nl = nl.groupdict() comps[cur].append(True if nl['value'] == "True" else False) tr = nodes.row() tr += nodes.description('', nodes.inline(text="\u2713" if comps[cur][-1] else " "), classes=['field-name', 'progress-checkbox']) text_description = nodes.inline() self.state.nested_parse(StringList(['{:s}'.format(nl['description'].lstrip() if nl['description'] is not None else ' ')], parent=self), 0, text_description) tr += nodes.description('', nodes.strong(text='{:s} '.format(nl['item'])), text_description, classes=['field-value']) body += tr if self.content: # finish up the final hrow self.add_progbar(shrow, len([c for c in comps[cur] if c == True]), len(comps[cur])) # and fill in the end of mrow self.add_progbar(head, len([c for r in comps.values() for c in r if c == True]), len([c for r in comps.values() for c in r])) return [section] def visit_progress(self, node): attrs = {'value': 0, 'max': 0} for a in attrs.keys(): if a in node.attributes: attrs[a] = node.attributes[a] self.body.append(''.format(attrs['value'], attrs['max'])) self.body.append(self.starttag(node, node.tagname, **attrs)) self.body.append('') def depart_progress(self, node): pass def setup(app): app.add_stylesheet('progress.css') app.add_node(progress, html=(visit_progress, depart_progress)) app.add_directive('progress', ProgressTable) PGPy-0.5.4/docs/source/_static/000077500000000000000000000000001403641706600162245ustar00rootroot00000000000000PGPy-0.5.4/docs/source/_static/pgpy_better.css000066400000000000000000000001311403641706600212550ustar00rootroot00000000000000header#pageheader, footer#pagefooter, div.related, div.document { max-width: 75rem; }PGPy-0.5.4/docs/source/_static/progress.css000066400000000000000000000050341403641706600206040ustar00rootroot00000000000000progress { width: 100%; height: 22px; -webkit-appearance: none; border: none; } /* webkit */ progress::-webkit-progress-bar { background: #999; border-radius: 6px; padding: 2px; box-shadow: 0 1px 1px 0 rgba(255, 255, 255, 0.2); } progress::-webkit-progress-value { border-radius: 5px; /* top shadow is white, bottom shadow is black */ box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1px 1px 0 rgba(0, 0, 0, 0.3); background: -webkit-linear-gradient(45deg, transparent, transparent 33%, rgba(0, 0, 0, 0.1) 33%, rgba(0, 0, 0, 0.1) 66%, transparent 66%), -webkit-linear-gradient(top, rgba(255, 255, 255, 0.25), rgba(0, 0, 0, 0.2)), -webkit-linear-gradient(left, #4070A0, #6292C2); background-size: 25px 17px, 100% 100%, 100% 100%; -webkit-animation: move 5s linear 0 infinite; animation: move 5s linear 0 infinite; } /* firefox */ progress, progress[role][aria-valuenow]::-moz-progress-bar { height: 17px; background: #999 !important; border-radius: 6px; padding: 2px; box-shadow: 0 1px 1px 0 rgba(255, 255, 255, 0.2); } progress::-moz-progress-bar { border-radius: 5px; /*top shadow is white, bottom shadow is black*/ box-shadow: inset 0 1px 1px 0 rgba(255, 255, 255, 0.3), inset 0 -1px 1px 0 rgba(0, 0, 0, 0.3); background: -moz-linear-gradient(45deg, transparent, transparent 33%, rgba(0, 0, 0, 0.1) 33%, rgba(0, 0, 0, 0.1) 66%, transparent 66%), -moz-linear-gradient(top, rgba(255, 255, 255, 0.25), rgba(0, 0, 0, 0.2)), -moz-linear-gradient(left, #4070A0, #6292C2); background-size: 25px 17px, 100% 100%, 100% 100%; /* firefox apparently won't animate this :( */ animation: move 5s linear 0 infinite; } @-webkit-keyframes move { from { background-position: 0 0; } to { background-position: -100px 0; } } @keyframes move { from { background-position: 0 0; } to { background-position: -100px 0; } } th.progcell, td.progcell { position: relative; } th.progcell > label, td.progcell > label { position: absolute; display: inline-block; left: 50%; width: 40px; line-height: 22px; margin-left: -40px; text-align: center; vertical-align: middle; font-weight: 600; text-shadow: 0 0 0.15em #fff, 1px 1px 2px #000; } .prog-top-label { text-align: center !important; vertical-align: bottom !important; font-weight: bold; } .progress-checkbox { text-align: right !important; text-shadow: 2px 2px 1px #fff; } PGPy-0.5.4/docs/source/api.rst000066400000000000000000000001731403641706600161020ustar00rootroot00000000000000******** PGPy API ******** .. include:: api/exceptions.rst .. include:: api/constants.rst .. include:: api/classes.rst PGPy-0.5.4/docs/source/api/000077500000000000000000000000001403641706600153475ustar00rootroot00000000000000PGPy-0.5.4/docs/source/api/classes.rst000066400000000000000000000122201403641706600175330ustar00rootroot00000000000000Classes ======= .. py:currentmodule:: pgpy :py:class:`PGPKey` ------------------ .. autoclass:: PGPKey :members: .. py:attribute:: ascii_headers :annotation: An :py:obj:`~collections.OrderedDict` of headers that appear, in order, in the ASCII-armored form of this object. .. py:classmethod:: from_file(filename) Create a new :py:obj:`PGPKey` object, with contents loaded from a file. May be binary or ASCII armored. :param filename: The path to the file to load. :type filename: ``str`` :raises: :py:exc:`ValueError` if a properly formed PGP block was not found in the file at ``filename`` :raises: :py:exc:`~exceptions.PGPError` if de-armoring or parsing failed :returns: A two element ``tuple`` of :py:obj:`PGPKey`, :py:obj:`~collections.OrderedDict`. The :py:obj:`~collections.OrderedDict` has the following format:: key, others = PGPKey.from_file('path/to/keyfile') # others: { (Fingerprint, bool(key.is_public)): PGPKey } .. py:classmethod:: from_blob(blob) Create a new :py:obj:`PGPKey` object, with contents loaded from a blob. May be binary or ASCII armored. :param blob: The data to load. :type blob: ``str``, ``bytes``, ``unicode``, ``bytearray`` :raises: :py:exc:`TypeError` if blob is not in the expected types above :raises: :py:exc:`ValueError` if a properly formed PGP block was not found in ``blob`` :raises: :py:exc:`~exceptions.PGPError` if de-armoring or parsing failed :returns: A two element ``tuple`` of :py:obj:`PGPKey`, :py:obj:`~collections.OrderedDict`. The :py:obj:`~collections.OrderedDict` has the following format:: key, others = PGPKey.from_file('path/to/keyfile') # others: { (Fingerprint, bool(key.is_public)): PGPKey } :py:class:`PGPKeyring` ---------------------- .. autoclass:: PGPKeyring() :members: .. py:attribute:: ascii_headers An :py:obj:`~collections.OrderedDict` of headers that appear, in order, in the ASCII-armored form of this object. :py:class:`PGPMessage` ---------------------- .. autoclass:: PGPMessage :members: .. py:attribute:: ascii_headers An :py:obj:`~collections.OrderedDict` of headers that appear, in order, in the ASCII-armored form of this object. .. py:classmethod:: from_file(filename) Create a new :py:obj:`PGPMessage` object, with contents loaded from a file. May be binary or ASCII armored. :param filename: The path to the file to load. :type filename: ``str`` :raises: :py:exc:`ValueError` if a properly formed PGP block was not found in the file at ``filename`` :raises: :py:exc:`~exceptions.PGPError` if de-armoring or parsing failed :returns: :py:obj:`PGPMessage` .. py:classmethod:: from_blob(blob) Create a new :py:obj:`PGPMessage` object, with contents loaded from a blob. May be binary or ASCII armored. :param blob: The data to load. :type blob: ``str``, ``bytes``, ``unicode``, ``bytearray`` :raises: :py:exc:`TypeError` if blob is not in the expected types above :raises: :py:exc:`ValueError` if a properly formed PGP block was not found in ``blob`` :raises: :py:exc:`~exceptions.PGPError` if de-armoring or parsing failed :returns: :py:obj:`PGPMessage` :py:class:`PGPSignature` ------------------------ .. autoclass:: PGPSignature :members: .. py:attribute:: ascii_headers An :py:obj:`~collections.OrderedDict` of headers that appear, in order, in the ASCII-armored form of this object. .. py:classmethod:: from_file(filename) Create a new :py:obj:`PGPSignature` object, with contents loaded from a file. May be binary or ASCII armored. :param filename: The path to the file to load. :type filename: ``str`` :raises: :py:exc:`ValueError` if a properly formed PGP block was not found in the file at ``filename`` :raises: :py:exc:`~exceptions.PGPError` if de-armoring or parsing failed :returns: :py:obj:`PGPSignature` .. py:classmethod:: from_blob(blob) Create a new :py:obj:`PGPSignature` object, with contents loaded from a blob. May be binary or ASCII armored. :param blob: The data to load. :type blob: ``str``, ``bytes``, ``unicode``, ``bytearray`` :raises: :py:exc:`TypeError` if blob is not in the expected types above :raises: :py:exc:`ValueError` if a properly formed PGP block was not found in ``blob`` :raises: :py:exc:`~exceptions.PGPError` if de-armoring or parsing failed :returns: :py:obj:`PGPSignature` :py:class:`PGPUID` ------------------ .. autoclass:: PGPUID :members: Other Objects ============= .. py:currentmodule:: pgpy.types These are objects that are returned during certain operations, but are probably not useful to instantiate directly. :py:class:`~types.SignatureVerification` ---------------------------------------- .. autoclass:: SignatureVerification :members: :py:class:`~types.Fingerprint` ------------------------------ .. autoclass:: Fingerprint :members: PGPy-0.5.4/docs/source/api/constants.rst000066400000000000000000000105151403641706600201170ustar00rootroot00000000000000Constants ========= .. py:currentmodule:: pgpy.constants :py:class:`PubKeyAlgorithm` --------------------------- .. autoclass:: PubKeyAlgorithm :no-members: .. autoattribute:: RSAEncryptOrSign :annotation: .. autoattribute:: DSA :annotation: .. autoattribute:: ElGamal :annotation: .. autoattribute:: ECDH :annotation: .. autoattribute:: ECDSA :annotation: :py:class:`EllipticCurveOID` ---------------------------- .. autoclass:: EllipticCurveOID :no-members: .. autoattribute:: Curve25519 :annotation: .. autoattribute:: Ed25519 :annotation: .. autoattribute:: NIST_P256 :annotation: .. autoattribute:: NIST_P384 :annotation: .. autoattribute:: NIST_P521 :annotation: .. autoattribute:: Brainpool_P256 :annotation: .. autoattribute:: Brainpool_P384 :annotation: .. autoattribute:: Brainpool_P512 :annotation: .. autoattribute:: SECP256K1 :annotation: :py:class:`SymmetricKeyAlgorithm` --------------------------------- .. autoclass:: SymmetricKeyAlgorithm :no-members: .. autoattribute:: IDEA :annotation: .. autoattribute:: TripleDES :annotation: .. autoattribute:: CAST5 :annotation: .. autoattribute:: Blowfish :annotation: .. autoattribute:: AES128 :annotation: .. autoattribute:: AES192 :annotation: .. autoattribute:: AES256 :annotation: .. autoattribute:: Camellia128 :annotation: .. autoattribute:: Camellia192 :annotation: .. autoattribute:: Camellia256 :annotation: :py:class:`CompressionAlgorithm` -------------------------------- .. autoclass:: CompressionAlgorithm :no-members: .. autoattribute:: Uncompressed :annotation: .. autoattribute:: ZIP :annotation: .. autoattribute:: ZLIB :annotation: .. autoattribute:: BZ2 :annotation: :py:class:`HashAlgorithm` ------------------------- .. autoclass:: HashAlgorithm() :no-members: .. autoattribute:: MD5 :annotation: .. autoattribute:: SHA1 :annotation: .. autoattribute:: RIPEMD160 :annotation: .. autoattribute:: SHA256 :annotation: .. autoattribute:: SHA384 :annotation: .. autoattribute:: SHA512 :annotation: .. autoattribute:: SHA224 :annotation: :py:class:`SignatureType` ------------------------- .. autoclass:: SignatureType :no-members: .. autoattribute:: BinaryDocument :annotation: .. autoattribute:: CanonicalDocument :annotation: .. autoattribute:: Standalone :annotation: .. autoattribute:: Generic_Cert :annotation: .. autoattribute:: Persona_Cert :annotation: .. autoattribute:: Casual_Cert :annotation: .. autoattribute:: Positive_Cert :annotation: .. autoattribute:: Attestation :annotation: .. autoattribute:: Subkey_Binding :annotation: .. autoattribute:: PrimaryKey_Binding :annotation: .. autoattribute:: DirectlyOnKey :annotation: .. autoattribute:: KeyRevocation :annotation: .. autoattribute:: SubkeyRevocation :annotation: .. autoattribute:: CertRevocation :annotation: .. autoattribute:: Timestamp :annotation: .. autoattribute:: ThirdParty_Confirmation :annotation: :py:class:`KeyFlags` -------------------- .. autoclass:: KeyFlags :no-members: .. autoattribute:: Certify :annotation: .. autoattribute:: Sign :annotation: .. autoattribute:: EncryptCommunications :annotation: .. autoattribute:: EncryptStorage :annotation: .. autoattribute:: Split :annotation: .. autoattribute:: Authentication :annotation: .. autoattribute:: MultiPerson :annotation: :py:class:`RevocationReason` ---------------------------- .. autoclass:: RevocationReason :no-members: .. autoattribute:: NotSpecified :annotation: .. autoattribute:: Superseded :annotation: .. autoattribute:: Compromised :annotation: .. autoattribute:: Retired :annotation: .. autoattribute:: UserID :annotation: PGPy-0.5.4/docs/source/api/exceptions.rst000066400000000000000000000012341403641706600202620ustar00rootroot00000000000000Exceptions ========== .. py:currentmodule:: pgpy.errors :py:class:`PGPError` -------------------- .. autoexception:: PGPError :py:class:`PGPEncryptionError` ------------------------------ .. autoexception:: PGPEncryptionError :py:class:`PGPDecryptionError` ------------------------------ .. autoexception:: PGPDecryptionError :py:class:`PGPOpenSSLCipherNotSupported` ---------------------------------------- .. autoexception:: PGPOpenSSLCipherNotSupported :py:class:`PGPInsecureCipher` ----------------------------- .. autoexception:: PGPInsecureCipher :py:class:`WontImplementError` ------------------------------ .. autoexception:: WontImplementError PGPy-0.5.4/docs/source/changelog.rst000066400000000000000000000247201403641706600172640ustar00rootroot00000000000000:tocdepth: 2 ********* Changelog ********* v0.5.4 ====== Released: April 16, 2021 .. note:: PGPy v0.5.x is still compatible with Python 2.7 and 3.4. Support for those versions will be dropped in PGPy v0.6.0. Bugs Fixed ---------- * Fixed compatibility break with Python < 3.8 (#368) * Fixed importing ABCs from ``collections`` (#328) Other Changes ------------- * Documentation updates v0.5.3 ====== Released: October 6, 2020 .. warning:: This is the last release that will support Python 2.7 and 3.4. Future releases will require Python 3.5 or greater. Bugs fixed ---------- * Passphrases are now encoded as utf-8 instead of latin-1 (#294) * PGPUIDs without a selfsig no longer cause crashes (#315) * Fixed dash un-escaping to be applied unconditionally (#341, #342) * Fix the ordering of one-pass signatures (#302) Other Changes ------------- * Updated unit tests to use `gpg 1.10 `_ * Lots of documentation updates and cleanup v0.5.2 ====== Released: August 1, 2019 Bugs Fixed ---------- * Signature subpackets of type 0 cause an infinite parse loop (#252) v0.5.0 ====== Released: August 1, 2019 New Features ------------ * Add support for Curve25519 * Greatly improved Elliptic Curve Point format handling code (special thanks @rot42) * Add support for IssuerFingerprint subpackets (thanks @J08nY) * Add support for Key Revocation signatures Bugs Fixed ---------- * PGPy now correctly resynchronizes the block cipher stream when decrypting EncryptedDataPackets (the ones without MDC). (#160) * PGPy now correctly defaults to SHA256 for keys that have no hash preferences set Other Changes ------------- * updated library dependencies and unit tests v0.4.3 ====== Released: August 16, 2017 Bugs Fixed ---------- * Private key checksum calculations were not getting stored for ECDSA keys; this has been fixed. * The test suite gpg wrappers have been replaced with use of the `gpg `_ package. (#171) v0.4.2 ====== Released: August 9, 2017 New Features ------------ * Packets with partial body lengths can now be parsed. For now, these packets are converted to have definite lengths instead. (#95) (#208) Bugs Fixed ---------- * Private key checksums are now calculated correctly (#172) * PGPKey.decrypt was mistakenly using message.issuers instead of message.encrypters when determining whether or not the key was eligible to attempt decrypting the message (#183) * Fixed an issue with parsing some cleartext messages (#184) * Fixed signing already-encrypted messages (encrypt-then-sign) (#186) (#191) * PGP*.from_blob now correctly raises an exception if given zero-length input (#199) (#200) * Fixed an issue where PGPKey.decrypt would fail with an arcane traceback if the key is passphrase-protected and not unlocked. (#204) v0.4.1 ====== Released: April 13, 2017 Bugs Fixed ---------- * Fixed an issue with dearmoring ASCII-armored PGP blocks with windows-style newlines (#156) * Improved the robustness of the code that tunes the hash count for deriving symmetric encryption keys (#157) * Fixed an issue with how public keys are created from private keys that was causing exports to become malformed (#168) * Added explicit support for Python 3.6 (#166) New Features ------------ * Added support for Brainpool Standard curves for users who have OpenSSL 1.0.2 available v0.4.0 ====== Released: April 21, 2016 Bugs Fixed ---------- * Armorable.from_blob was incorrectly not accepting bytes objects; this has been fixed (#140) * Fixed an issue where string-formatting PGPUID objects would sometimes raise an exception (#142) * Occasionally, the ASN.1 encoding of DSA signatures was being built in a way that although GPG could parse and verify them, it was incorrect, and PGPy incorrectly failed to verify them. (#143) * Fixed an issue where keys with expiration dates set would have the wrong value returned from the ``key.is_expired`` property (#151) * Fixed an issue where PGPy would try to incorrectly coerce non-ASCII-compatible characters to ASCII-compatible bytes, potentially resulting in mojibake. (#154) New Features ------------ * ECDSA and ECDH keys can now be loaded (#109, #110) * Keys can be generated with the following algorithms: - RSA - DSA - ECDSA - ECDH * Keys can now be passphrase-protected. It is also possible to change the passphrase on a key that is already protected. (#149) * ECDSA keys can now be used to sign and verify (#111) * ECDH keys can now be used to encrypt and decrypt * It is now possible to recover a public key from a private key (#92) * Marker packets are now understood Other Changes ------------- * Removed support for Python 3.2, as multiple dependency libraries have already done so * Added explicit support for Python 3.5 * Updated library dependencies where required or useful * Reworked some IO-intensive routines to be less IO-intensive, and therefore faster v0.3.0 ====== Released: November 19, 2014 PGPy v0.3.0 is a major feature release. .. warning:: The API changed significantly in this version. It is likely that anything using a previous version will need to be updated to work correctly with PGPy 0.3.0 or later. Bugs Fixed ---------- * When keys are exported, any certification signatures that are marked as being non-exportable are now skipped (#101) * When the wrong key is used to validate a signature, the error message in the raised exception now makes that clear (#106) New Features ------------ * Standalone sigantures can now be generated * Can now specify which User ID to use when signing things (#121) * Can now create new User IDs and User Attributes (#118) * Can now add new User IDs and User Attributes to keys (#119) * Timestamp signatures can now be generated * Can now sign keys, user ids, and user attributes (#104) * Can now create new PGPMessages (#114) * Key flags are now respected by PGPKey objects (#99) * Multiple signatures can now be validated at once in cases where that makes sense, such as when validating self-signatures on keys/user ids (#120) * Message signatures can now be verified (#117) * Messages can now be encrypted/decrypted using a passphrase (#113) * Cleartext messages can now be created and signed (#26) * Cleartext messages with inline sigantures can now be verified (#27) * Messages can now be loaded (#102) * Messages can now be compressed (#100) Other Changes ------------- * CRC24 computation is now much faster than previous versions (#68) * PGPKey and PGPKeyring APIs have changed significantly (#76) * String2Key computation is now much faster than previous versions (#94) * key material parts are now stored as integers (or ``long`` on Python 2.x) (#94) v0.2.3 ====== Released: July 31, 2014 PGPy v0.2.3 is a bugfix release Bugs Fixed ---------- * Fixed an issue where explicitly selecting a key and then trying to validate with it would erroneously raise an exception as though the wrong key were selected. v0.2.2 ====== Released: July 31, 2014 PGPy v0.2.2 is primarily a bugfix release. Bugs Fixed ---------- * Fixed a typo that would cause TypeError to be raised as bytecode was being generated (#85) * Fixed an issue where unicode input on Python 2.7 could result in unexpected UnicodeDecodeError exceptions being raised New Features ------------ * Switched the main parse loop to use a bytearray instead of slicing a bytes, resulting in a ~160x speedup in parsing large blocks of pasing. (#87) v0.2.1 ====== Released: July 31, 2014 PGPy v0.2.1 is primarily a bugfix release. Bugs Fixed ---------- * Critical bit on signature subpackets was being ignored, and when set, causing a ValueError to be raised when trying to parse it. The critical bit is now being parsed and masked out correctly. (#81) * No longer raises exceptions on unrecognized subpackets; instead, it now treats them as opaque. * No longer raises exceptions on unrecognized packets; instead, it now treats them as opaque. This also applies to signature and key packets with versions other than v4. * Fixed an issue where a User ID packet that lacked both a comment and an email address was failing to be found by the uid regex in KeyCollection. * Fixed an issue where an old-format packet header with a length_type set longer than needed was resulting in the packet getting truncated. * Fixed an issue where parsing a subpacket with a 2-byte length was erroneously being parsed as a 5-byte length. * Fixed an issue where parsing a subpacket with a 5-byte length where the value was < 8434 was causing an error * Fixed an issue where a packet or subpacket reporting a value marked reserved in RFC 4880 would cause ValueError to be raised during parsing. * Key material marked as public key algorithm 20 (Reserved - Formerly ElGamal Encrypt or Sign) is now parsed as ElGamal key material. * Fixed an issue where parsing a new-format packet header length where the first octet was 223 was erroneously reported as being malformed. New Features ------------ * Added support for parsing the 'Preferred Key Server' signature subpacket * Added support for loading unsupported or unrecognized signature subpackets. * Added support for loading unsupported or unrecognized packets. v0.2.0 ====== Released: July 20, 2014 Starting with v0.2.0, PGPy is now using the BSD 3-Clause license. v0.1.0 used the MIT license. New Features ------------ * Subkeys can now be accessed and used for actions supported by PGPKeyring (#67) * DSA: - Signing of binary documents now works (#16) - Verification of signatures of binary documents now works (#15) * Can now decrypt secret key material that was encrypted using: - Camellia128 (#36) - Camellia192 (#37) - Camellia256 (#38) - AES128 (#32) - AES192 (#33) - AES256 (#34) - Blowfish (#31) - Triple-DES (#30) - IDEA (#29) * PGP packets generated by PGPy now exclusively use new-style header lengths (#47) * GPG Trust Packets are now understood and fully parsed (#14) * Lots more packet types are now fully parsed Known Issues ------------ * Signing with 1024-bit DSA keys does not work with OpenSSL 0.9.8 (#48) - this primarily affects Mac OS X. * Verifying signatures signed with any DSA key length other than 2048-bits does not work with OpenSSL 0.9.8 - this primarily affects Mac OS X. Bugs Fixed ---------- * PGP blocks loaded from ASCII armored blocks now retain their ASCII headers (#54) * PGP new-style packet headers were not being properly parsed in all cases * Many unit test enhancements v0.1.0 ====== Released: May 02, 2014 * Initial release. PGPy-0.5.4/docs/source/conf.py000066400000000000000000000217671403641706600161120ustar00rootroot00000000000000#!/usr/bin/env python3 # -*- coding: utf-8 -*- # # PGPy documentation build configuration file, created by # sphinx-quickstart on Thu May 1 18:03:51 2014. # # 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 sys import os # this needs sphinx-better-theme from better import better_theme_path from setuptools.config import read_configuration # 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. _docsrcdir = os.path.dirname(os.path.abspath(__file__)) sys.path.insert(0, _docsrcdir) sys.path.insert(0, os.path.dirname(os.path.dirname(_docsrcdir))) __version__ = read_configuration(os.path.join('..', '..', 'setup.cfg'))['metadata']['version'] # -- 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', 'sphinx.ext.autosummary', 'sphinx.ext.todo', '_ext.progress', # 'sphinx.ext.doctest', # 'sphinx.ext.coverage', # 'sphinx.ext.mathjax', # 'sphinx.ext.viewcode', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'PGPy' copyright = '2014-2021, Security Innovation, Inc' # 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 = __version__ # The full version, including alpha/beta/rc tags. release = __version__ # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [ 'api/*', 'examples/*' ] # The reST default role (used for this markup: `text`) to use for all # documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. #keep_warnings = False # -- Options for ext.autodoc ---------------------------------------------- autoclass_content = 'init' autodoc_member_order = 'bysource' autodoc_default_flags = ['members'] # -- Options for ext.autosummary ------------------------------------------ numpydoc_show_class_members = 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 = 'default' html_theme = 'better' html_theme_path = [better_theme_path] # 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. if html_theme == 'better': html_theme_options = { 'cssfiles': ['_static/pgpy_better.css'], 'sidebarwidth': '19rem', } # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # 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'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. #html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'PGPydoc' # -- 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': '', } # 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 = [ # ('index', 'PGPy.tex', 'PGPy Documentation', # 'Michael Greene', 'manual'), # ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'pgpy', 'PGPy Documentation', ['Michael Greene'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- 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 = [ # ('index', 'PGPy', 'PGPy Documentation', # 'Michael Greene', 'PGPy', 'One line description of project.', # 'Miscellaneous'), # ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False PGPy-0.5.4/docs/source/examples.rst000066400000000000000000000002471403641706600171510ustar00rootroot00000000000000******** Examples ******** .. include:: examples/keys.rst .. include:: examples/messages.rst .. include:: examples/actions.rst .. include:: examples/exporting.rst PGPy-0.5.4/docs/source/examples/000077500000000000000000000000001403641706600164145ustar00rootroot00000000000000PGPy-0.5.4/docs/source/examples/actions.rst000066400000000000000000000110661403641706600206120ustar00rootroot00000000000000Actions ======= Signing Things -------------- One of the things you may want to do with PGPKeys is to sign things. This is split into several categories in order to keep the method signatures relatively simple. Remember that signing requires a private key. Text/Messages/Other ^^^^^^^^^^^^^^^^^^^ Text and messages can be signed using the .sign method:: # sign some text sig = sec.sign("I have just signed this text!") # sign a message # the bitwise OR operator '|' is used to add a signature to a PGPMessage. message |= sec.sign(message) # timestamp signatures can also be generated, like so. # Note that GnuPG seems to have no idea what to do with this timesig = sec.sign(None) # if optional parameters are supplied, then a standalone signature is created # instead of a timestamp signature. Effectively, they are equivalent, except # that the standalone signature has more information in it. lone_sig = sec.sign(None, notation={"cheese status": "standing alone"}) Keys/User IDs ^^^^^^^^^^^^^ Keys and User IDs can be signed using the .certify method:: # Sign a key - this creates a Signature Directly On A Key. # GnuPG only partially supports this type of signature. someones_pubkey |= mykey.certify(someones_pubkey) # Sign the primary User ID - this creates the usual certification signature # that is best supported by other popular OpenPGP implementations. # As above, the bitwise OR operator '|' is used to add a signature to a PGPUID. cert = mykey.certify(someones_pubkey.userids[0], level=SignatureType.Persona_Cert) someones_pubkey.userids[0] |= cert # If you want to sign all of their User IDs, that can be done easily in a loop. # This is equivalent to GnuPG's default behavior when signing someone's public key. # As above, the bitwise OR operator '|' is used to add a signature to a PGPKey. for uid in someones_pubkey.userids: uid |= mykey.certify(uid) Verifying Things ---------------- Although signing things uses multiple methods, there is only one method to remember for verifying signatures:: # verify a detached signature pub.verify("I have just signed this text!", sig) # verify signatures in a message pub.verify(message) # verify signatures on a userid for uid in someones_pubkey.userids: pub.verify(uid) # or, better yet, verify all applicable signatures on a key in one go pub.verify(someones_pubkey) Encryption ---------- Another thing you may want to do is encrypt or decrypt messages. Encrypting/Decrypting Messages With a Public Key ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Encryption using keys requires a public key, while decryption requires a private key. PGPy currently only supports asymmetric encryption/decryption using RSA or ECDH:: # this returns a new PGPMessage that contains an encrypted form of the # unencrypted message encrypted_message = pubkey.encrypt(message) Encrypting Messages to Multiple Recipients """""""""""""""""""""""""""""""""""""""""" .. warning:: Care must be taken when doing this to delete the session key as soon as possible after encrypting the message. Messages can also be encrypted to multiple recipients by pre-generating the session key:: # The symmetric cipher should be specified, in case the first preferred cipher is not # the same for all recipients' public keys cipher = pgpy.constants.SymmetricKeyAlgorithm.AES256 sessionkey = cipher.gen_key() # encrypt the message to multiple recipients # A decryption passphrase can be added at any point as well, as long as cipher # and sessionkey are also provided to enc_msg.encrypt enc_msg = pubkey1.encrypt(message, cipher=cipher, sessionkey=sessionkey) enc_msg = pubkey2.encrypt(enc_msg, cipher=cipher, sessionkey=sessionkey) # do at least this as soon as possible after encrypting to the final recipient del sessionkey Encrypting/Decrypting Messages With a Passphrase ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ There are some situations where encrypting a message with a passphrase may be more desirable than doing so with someone else's public key. That can be done like so:: # the .encrypt method returns a new PGPMessage object which contains the encrypted # contents of the old message enc_message = message.encrypt("S00per_Sekr3t") # message.is_encrypted is False # enc_message.is_encrypted is True # a message that was encrypted using a passphrase can also be decrypted using # that same passphrase dec_message = enc_message.decrypt("S00per_Sekr3t") PGPy-0.5.4/docs/source/examples/exporting.rst000066400000000000000000000011221403641706600211610ustar00rootroot00000000000000Exporting PGP* Objects ====================== PGPKey, PGPMessage, and PGPSignature objects can all be exported to OpenPGP-compatible binary and ASCII-armored formats. To export in ASCII-armored format:: # This works in both Python 2.x and 3.x # ASCII-armored format # cleartext PGPMessages will also have properly canonicalized and dash-escaped # message text pgpstr = str(pgpobj) To export to binary format in Python 3:: # binary format pgpbytes = bytes(pgpobj) To export to binary format in Python 2:: # binary format pgpbytes = pgpobj.__bytes__() PGPy-0.5.4/docs/source/examples/keys.rst000066400000000000000000000140131403641706600201200ustar00rootroot00000000000000Keys ==== Generating Keys --------------- PGPy can generate most types keys as defined in the standard. Generating Primary Keys ^^^^^^^^^^^^^^^^^^^^^^^ It is possible to generate most types of keys with PGPy now. The process is mostly straightforward:: from pgpy.constants import PubKeyAlgorithm, KeyFlags, HashAlgorithm, SymmetricKeyAlgorithm, CompressionAlgorithm # we can start by generating a primary key. For this example, we'll use RSA, but it could be DSA or ECDSA as well key = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) # we now have some key material, but our new key doesn't have a user ID yet, and therefore is not yet usable! uid = pgpy.PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='abraham.lincoln@whitehouse.gov') # now we must add the new user id to the key. We'll need to specify all of our preferences at this point # because PGPy doesn't have any built-in key preference defaults at this time # this example is similar to GnuPG 2.1.x defaults, with no expiration or preferred keyserver key.add_uid(uid, usage={KeyFlags.Sign, KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}, hashes=[HashAlgorithm.SHA256, HashAlgorithm.SHA384, HashAlgorithm.SHA512, HashAlgorithm.SHA224], ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.AES192, SymmetricKeyAlgorithm.AES128], compression=[CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZ2, CompressionAlgorithm.ZIP, CompressionAlgorithm.Uncompressed]) Specifying key expiration can be done using the ``key_expiration`` keyword when adding the user id. Expiration can be specified using a :py:obj:`datetime.datetime` or a :py:obj:`datetime.timedelta` object:: from datetime import timedelta # in this example, we'll use fewer preferences for the sake of brevity, and set the key to expire in 1 year key = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) uid = pgpy.PGPUID.new('Nikola Tesla') # comment and email are optional # the key_expires keyword accepts a :py:obj:`datetime.datetime` key.add_uid(uid, usage={KeyFlags.Sign}, hashes=[HashAlgorithm.SHA512, HashAlgorithm.SHA256], ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.Camellia256], compression=[CompressionAlgorithm.BZ2, CompressionAlgorithm.Uncompressed], key_expiration=timedelta(days=365)) Generating Sub Keys ^^^^^^^^^^^^^^^^^^^ Generating a subkey is similar to the process above, except that it requires an existing primary key:: # assuming we already have a primary key, we can generate a new key and add it as a subkey thusly: subkey = pgpy.PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 4096) # preferences that are specific to the subkey can be chosen here # any preference(s) needed for actions by this subkey that not specified here # will seamlessly "inherit" from those specified on the selected User ID key.add_subkey(subkey, usage={KeyFlags.Authentication}) Loading Keys ------------ There are two ways to load keys: individually, or in a keyring. Loading Keys Individually ^^^^^^^^^^^^^^^^^^^^^^^^^ Keys can be loaded individually into PGPKey objects:: # A new, empty PGPkey object can be instantiated, but this is not very useful # by itself. # ASCII or binary data can be parsed into an empty PGPKey object with the .parse() # method empty_key = pgpy.PGPKey() empty_key.parse(keyblob) # A key can be loaded from a file, like so: key, _ = pgpy.PGPKey.from_file('path/to/key.asc') # or from a text or binary string/bytes/bytearray that has already been read in: key, _ = pgpy.PGPKey.from_blob(keyblob) Loading Keys Into a Keyring ^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you intend to maintain multiple keys in memory for extended periods, using a PGPKeyring may be more appropriate:: # These two methods are mostly equivalent kr = pgpy.PGPKeyring(glob.glob(os.path.expanduser('~/.gnupg/*ring.gpg'))) # the only advantage to doing it this way, is the .load method returns a set containing # the fingerprints of all keys and subkeys that were loaded this time kr = pgpy.PGPKeyring() loaded = kr.load(glob.glob(os.path.expanduser('~/.gnupg/*ring.gpg'))) Key Operations -------------- Once you have one or more keys generated or loaded, there are some things you may need or want to do before they can be used. Passphrase Protecting Secret Keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It is usually recommended to passphrase-protect private keys. Adding a passphrase to a key is simple:: # key.is_public is False # key.is_protected is False key.protect("C0rrectPassphr@se", SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256) # key.is_protected is now True Unlocking Protected Secret Keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If you have a key that is protected with a passphrase, you will need to unlock it first. PGPy handles this using a context manager block, which also removes the unprotected key material from the object once execution exits that block. Key unlocking is quite simple:: # enc_key.is_public is False # enc_key.is_protected is True # enc_key.is_unlocked is False # Note that this context manager yields self, so while you can supply `as cvar`, it isn't strictly required # If the passphrase given is incorrect, this will raise PGPDecryptionError with enc_key.unlock("C0rrectPassphr@se"): # enc_key.is_unlocked is now True ... # This form works equivalently, but may be more semantically clear in some cases: with enc_key.unlock("C0rrectPassphr@se") as ukey: # ukey is just a reference to enc_key in this case ... Exporting Keys ^^^^^^^^^^^^^^ Keys can be exported in OpenPGP compliant binary or ASCII-armored formats. In Python 3:: # binary keybytes = bytes(key) # ASCII armored private key keystr = str(key) # ASCII armored public key keystr = str(key.pubkey) in Python 2:: # binary keybytes = key.__bytes__() # ASCII armored keystr = str(key) PGPy-0.5.4/docs/source/examples/messages.rst000066400000000000000000000040301403641706600207520ustar00rootroot00000000000000Messages ======== Other than plaintext, you may want to be able to form PGP Messages. These can be signed and then encrypted to one or more recipients. Creating New Messages --------------------- New messages can be created quite easily:: # this creates a standard message from text # it will also be compressed, by default with ZIP DEFLATE, unless otherwise specified text_message = pgpy.PGPMessage.new("This is a brand spankin' new message!") # if you'd like to pack a file into a message instead, you can do so # PGPMessage will store the basename of the file and the time it was last modified. file_message = pgpy.PGPMessage.new("path/to/a/file", file=True) # or, if you want to create a *cleartext* message, which is what you may know as a # canonicalized text document with an inline signature block, that is done by setting # cleartext=True. You can load the contents of a file as above, as well. ct_message = pgpy.PGPMessage.new("This is a shiny new cleartext document. Hooray!", cleartext=True) Loading Existing Messages ------------------------- Existing messages can also be loaded very simply. This is nearly identical to loading keys, except that it only returns the new message object, instead of a tuple:: # PGPMessage will automatically determine if this is a cleartext message or not message_from_file = pgpy.PGPMessage.from_file("path/to/a/message") message_from_blob = pgpy.PGPMessage.from_blob(msg_blob) Exporting Messages ------------------ Messages can be exported in OpenPGP compliant binary or ASCII-armored formats. In Python 3:: # binary msgbytes = bytes(message) # ASCII armored # if message is cleartext, this will also properly canonicalize and dash-escape # the message text msgstr = str(message) in Python 2:: # binary msgbytes = message.__bytes__() # ASCII armored # if message is cleartext, this will also properly canonicalize and dash-escape # the message text msgstr = str(message) PGPy-0.5.4/docs/source/index.rst000066400000000000000000000006701403641706600164420ustar00rootroot00000000000000################## PGPy Documentation ################## ``PGPy`` is a Python (2 and 3) implementation of the OpenPGP specification, as described in :rfc:`4880`. It aims to be easy to use above all else, but also to eventually embody a complete, compliant implementation of the specification. Contents: .. toctree:: :maxdepth: 2 installation examples API progress changelog .. include:: installation.rst PGPy-0.5.4/docs/source/installation.rst000066400000000000000000000037171403641706600200410ustar00rootroot00000000000000************ Installation ************ .. highlight:: console Platform Specific Notes ======================= Windows ------- PGPy has not been formally tested on Windows. I see no reason why it wouldn't work, but your mileage may vary. If you try it out and run into any issues, please submit bug reports on the `issue tracker `_! Linux ----- Debian ^^^^^^ PGPy is now in `Debian Testing `_, and can be installed simply:: $ sudo apt install python3-pgpy Arch Linux ^^^^^^^^^^ PGPy is available on the `AUR `_ Gentoo ^^^^^^ There are gentoo ebuilds available in the `gentoo branch `_ RedHat/CentOS ^^^^^^^^^^^^^ Coming Soon! Other Linux ^^^^^^^^^^^ Building PGPy on Linux requires a C compiler, headers for Python, headers for OpenSSL, and libffi, to support building Cryptography. For Debian/Ubuntu, these requirements can be installed like so:: $ sudo apt install build-essential libssl-dev libffi-dev python-dev For Alpine linux, the build requirements can be installed like so:: $ apk add build-base libressl-dev libffi-dev python-dev You may need to install ``python3-dev`` if you are using PGPy on Python 3. For Fedora/RHEL derivatives, the build requirements can be installed like so:: $ sudo yum install gcc libffi-devel python-devel openssl-devel Mac OS X -------- If you are on Mac OS, you may experience more limited functionality without installing a more capable version of OpenSSL. You may refer to Cryptography's documentation on `Building cryptography on macOS `_ for information on how to do so. Installation ============ Once you have the prerequisites specified above, PGPy can be installed from PyPI using pip, like so:: $ pip install PGPy PGPy-0.5.4/docs/source/progress.rst000066400000000000000000000340241403641706600171770ustar00rootroot00000000000000******************************* OpenPGP Implementation Progress ******************************* OpenPGP RFCs ============ PGPy is focused on eventually reaching complete OpenPGP implementation, adhering to the base OpenPGP message format specification, and its extension RFCs. .. progress:: RFC 4880 :text: PGPy is currently focused on achieving :rfc:`4880` compliance for OpenPGP, which is the latest complete OpenPGP Message Format specification. It supersedes RFC 1991 and RFC 2440. :Versioned Packets, v1: - Tag 18, True, Symetrically Encrypted and Integrity Protected Data Packet :Versioned Packets, v3: - Tag 1, True, Public-Key Encrypted Session Key Packets - Tag 2, False, Signature Packet - Tag 4, True, One-Pass Signature Packet - Tag 5, False, Secret-Key Packet - Tag 6, False, Public-Key Packet - Tag 7, False, Secret-Subkey Packet - Tag 14, False, Public-SubKey Packet :Versioned Packets, v4: - Tag 2, True, Signature Packet - Tag 3, True, Symmetric-Key Encrypted Session Key Packet - Tag 5, True, Secret-Key Packet - Tag 6, True, Public-Key Packet - Tag 7, True, Secret-Subkey Packet - Tag 14, True, Public-SubKey Packet :Unversioned Packets: - Tag 8, True, Compressed Data Packet - Tag 9, True, Symetrically Encrypted Data Packet - Tag 10, True, Marker Packet - Tag 11, True, Literal Data Packet - Tag 12, True, Trust Packet - Tag 13, True, User ID Packet - Tag 17, True, User Attribute Packet - Tag 19, True, Modification Detection Code Packet :Signature Subpackets: - 0x02, True, Signature Creation Time - 0x03, True, Signature Expiration Time - 0x04, True, Exportable Certification - 0x05, True, Trust Signature - 0x06, True, Regular Expression - 0x07, True, Revocable - 0x09, True, Key Expiration Time - 0x0B, True, Preferred Symmetric Algorithms - 0x0C, True, Revocation Key - 0x10, True, Issuer - 0x14, True, Notation Data - 0x15, True, Preferred Hash Algorithms - 0x16, True, Preferred Compression Algorithms - 0x17, True, Key Server Preferences - 0x18, True, Preferred Key Server - 0x19, True, Primary User ID - 0x1A, True, Policy URI - 0x1B, True, Key Flags - 0x1C, True, Signer's User ID - 0x1D, True, Reason For Revocation - 0x1E, True, Features - 0x1F, False, Signature Target - 0x20, True, Embedded Signature :User Attribute Subpackets: - 0x01, True, Image :Storage Formats: - ASCII, True, ASCII armored PGP blocks - binary, True, binary PGP packets - GPG, True, GPG <= 2.0.x keyrings - KBX, False, GPG >= 2.1.x keyboxes :Other Sources: - Retrieve, False, Retrieve from HKP key servers - Upload, False, Submit to HKP key servers :Key Types: - RSA, True, RSA - DSA, True, DSA - ElGamal, True, ElGamal :Key Actions: - Protect, True, Protect private keys encryped with CAST5 - Protect, True, Protect private keys encryped with Blowfish - Protect, True, Protect private keys encryped with AES - Protect, False, Protect private keys encryped with Twofish - Unprotect, True, Unprotect private keys encrypted with IDEA [1]_ - Unprotect, True, Unprotect private keys encrypted with Triple-DES - Unprotect, True, Unprotect private keys encrypted with CAST5 - Unprotect, True, Unprotect private keys encrypted with Blowfish - Unprotect, True, Unprotect private keys encrypted with AES - Unprotect, False, Unprotect private keys encrypted with Twofish :RSA Key Actions: - Load, True, Load Keys - Generate, True, Generate Keys - Generate, True, Generate Subkeys - Sign, True, Generate detached signatures of binary documents - Sign, True, Generate inline signatures of canonical documents - Sign, True, Sign messages - Sign, True, Sign keys - Sign, True, Certify User IDs - Sign, True, Certify User Attributes - Sign, True, Generate key binding signatures - Sign, True, Revoke certifications - Sign, True, Revoke keys - Sign, True, Revoke subkeys - Sign, True, Generate timestamp signatures - Sign, True, Generate standalone signatures - Sign, False, Generate third party confirmation signatures - Verify, True, Verify detached signatures - Verify, True, Verify inline signatures of canonical documents - Verify, True, Verify messages - Verify, True, Verify key signatures - Verify, True, Verify User ID certification signatures - Verify, True, Verify User Attribute certification signatures - Verify, True, Verify key binding signatures - Verify, True, Verify key revocation signatures - Verify, True, Verify subkey revocation signatures - Verify, True, Verify certification revocation signatures - Verify, True, Verify timestamp signatures - Verify, True, Verify standalone signatures - Verify, False, Verify third party confirmation signatures - Revocation, True, Designate Revocation Key - Revocation, True, Revoke (Sub)Key with Self Signature - Revocation, False, Revoke (Sub)Key using Designated Revocation Key - Encryption, True, Encrypt data/messages - Decryption, True, Decrypt data/messages :DSA Key Actions: - Load, True, Load Keys - Generate, True, Generate Keys - Generate, True, Generate Subkeys - Sign, True, Generate detached signatures of binary documents - Sign, True, Generate inline signatures of canonical documents - Sign, True, One-Pass Sign messages - Sign, True, Sign messages - Sign, True, Sign keys - Sign, True, Certify User IDs - Sign, True, Certify User Attributes - Sign, True, Generate key binding signatures - Sign, True, Revoke certifications - Sign, True, Revoke keys - Sign, True, Revoke subkeys - Sign, True, Generate timestamp signatures - Sign, True, Generate standalone signatures - Sign, False, Generate third party confirmation signatures - Verify, True, Verify detached signatures - Verify, True, Verify inline signatures of canonical documents - Verify, True, Verify messages - Verify, True, Verify key signatures - Verify, True, Verify User ID certification signatures - Verify, True, Verify User Attribute certification signatures - Verify, True, Verify key binding signatures - Verify, True, Verify key revocation signatures - Verify, True, Verify subkey revocation signatures - Verify, True, Verify certification revocation signatures - Verify, True, Verify timestamp signatures - Verify, True, Verify standalone signatures - Verify, False, Verify third party confirmation signatures - Revocation, True, Designate Revocation Key - Revocation, True, Revoke (Sub)Key with Self Signature - Revocation, False, Revoke (Sub)Key using Designated Revocation Key :ElGamal Key Actions: - Load, True, Load Keys - Generate, False, Generate Keys - Generate, False, Generate Subkeys - Encryption, False, Encrypt data/messages - Decryption, False, Decrypt data/messages :Other Actions: - Encryption, True, Encrypt data/messages using symmetric ciphers with passphrases - Decryption, True, Decrypt data/messages using symmetric ciphers with passphrases .. progress:: RFC 4398 :text: :rfc:`4398` covers publishing and retrieving PGP public keys via DNS CERT records. :Key Sources: - DNS CERT, False, Look up and retrieve keys stored in Content-based DNS CERT records - DNS CERT, False, Look up and retrieve keys stored in Purpose-based DNS CERT records .. progress:: RFC 5581 :text: :rfc:`5581` extends RFC 4880 to officially add support for the Camellia cipher :Actions: - Encryption, True, Camellia [1]_ - Decryption, True, Camellia [1]_ .. progress:: RFC 6637 :text: :rfc:`6637` extends OpenPGP to officially add support for elliptic curve cryptography :Key Types: - ECDH, True, Elliptic Curve Diffie-Hellman - ECDSA, True, Elliptic Curve Digital Signature Algorithm :Curves: - Curve, True, NIST P-256 - Curve, True, NIST P-386 - Curve, True, NIST P-521 :ECDH Key Actions: - Load, True, Load Keys - Generate, True, Generate Keys - Generate, True, Generate Subkeys - KDF, True, Encode KDF data for encryption - KDF, True, Decode KDF data for decryption :ECDSA Key Actions: - Load, True, Load Keys - Generate, True, Generate Keys - Generate, True, Generate Subkeys - Sign, True, Generate detached signatures of binary documents - Sign, True, Generate inline signatures of canonical documents - Sign, True, One-Pass Sign messages - Sign, True, Sign messages - Sign, True, Sign keys - Sign, True, Certify User IDs - Sign, True, Certify User Attributes - Sign, True, Generate key binding signatures - Sign, True, Revoke certifications - Sign, True, Revoke keys - Sign, True, Revoke subkeys - Sign, True, Generate timestamp signatures - Sign, True, Generate standalone signatures - Sign, False, Generate third party confirmation signatures - Verify, True, Verify detached signatures - Verify, True, Verify inline signatures of canonical documents - Verify, True, Verify messages - Verify, True, Verify key signatures - Verify, True, Verify Use r ID certification signatures - Verify, True, Verify User Attribute certification signatures - Verify, True, Verify key binding signatures - Verify, True, Verify key revocation signatures - Verify, True, Verify subkey revocation signatures - Verify, True, Verify certification revocation signatures - Verify, True, Verify timestamp signatures - Verify, True, Verify standalone signatures - Verify, False, Verify third party confirmation signatures - Revocation, True, Designate Revocation Key - Revocation, True, Revoke (Sub)Key with Self Signature - Revocation, False, Revoke (Sub)Key using Designated Revocation Key Non-RFC Extensions ================== This section covers things that are considered extensions to PGP, but are not codified in the form of an RFC. .. progress:: DNS PKA :text: Publishing OpenPGP keys in DNS :Other Sources: - DNS PKA, False, Look up and retrieve keys stored in DNS PKA records. .. progress:: OpenPGP HTTP Keyserver Protocol (HKP) :text: The protocol is specified in `Marc Horowitz's thesis paper`_, and an expired RFC draft by David Shaw, `draft-shaw-openpgp-hkp-00`_. :HKP: - Discovery, False, Round robin DNS and SRV lookups (section 7. Locating a HKP Keyserver) - Index, False, Look up keys on key server, with multiple possible matches (section 3.1.2.2. The "index" Operation) - Get, False, Retrieve keys from key server, single fingerprint fetch (section 3.1.2.1. The "get" operation) - Post, False, Send keys to key server (section 4. Submitting Keys To A Keyserver) .. progress:: OpenPGP Web Key Service (WKS) :text: LocatesOpenPGP keys by mail address using a Web service and the HTTPS protocol. Protocol specified in an in-progress RFC draft by Werner Koch, `draft-koch-openpgp-webkey-service`_ :WKS: - Discovery, False, Fetches keys matching a UID from the server, using DNS and SRV lookups (section 3.1. Key Discovery) - Update, False, Update keys on the WKS (section 4. Web Key Directory Update Protocol) .. progress:: EdDSA for OpenPGP :text: Use of Ed25519 with ECDSA and ECDH in OpenPGP is currently specified in an in-progress RFC draft by Werner Koch, `draft-ietf-openpgp-rfc4880bis`_. :Curves: - Curve, True, Ed25519 - Curve, True, X25519 .. progress:: Additional Curves for OpenPGP :text: Some additional curves that can be used with ECDSA/ECDH that are not explicitly called out in :rfc:`6637`, but have standardized OIDs and are implemented in other software. :Curves: - Curve, True, Brainpool P-256 - Curve, True, Brainpool P-384 - Curve, True, Brainpool P-512 - Curve, True, Curve25519 [1]_ - Curve, True, SECP256K1 .. note:: Use of Brainpool curves with ECDSA/ECDH Although these curves are not explicitly mentioned in an RFC for OpenPGP at this point, GnuPG 2.1.x+ does support using them. As such, they have been included here. .. [1] Cipher availability depends on the currently installed OpenSSL being compiled with support for it .. _`Marc Horowitz's thesis paper`: http://www.mit.edu/afs/net.mit.edu/project/pks/thesis/paper/thesis.html .. _`draft-shaw-openpgp-hkp-00`: https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00 .. _`draft-koch-openpgp-webkey-service`: https://tools.ietf.org/html/draft-koch-openpgp-webkey-service-04 .. _`draft-ietf-openpgp-rfc4880bis`: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis PGPy-0.5.4/gentoo/000077500000000000000000000000001403641706600136415ustar00rootroot00000000000000PGPy-0.5.4/gentoo/pgpy-0.4.0.ebuild000066400000000000000000000017331403641706600164470ustar00rootroot00000000000000# Copyright 2014 Michael Greene # Distributed under the terms of the BSD 3-Clause License # $HEADER: $ EAPI=5 PYTHON_COMPAT=( python{2_7,3_3,3_4,3_5} ) inherit distutils-r1 DESCRIPTION="Pretty Good Privacy for Python - a pure Python OpenPGP implementation." HOMEPAGE="https://github.com/SecurityInnovation/PGPy" SRC_URI="https://pypi.python.org/packages/0a/2c/bfe57ac97d31fcd7172df43770d68bab1fbd38d629448ec8013f4714e779/PGPy-0.4.0a.tar.gz" LICENSE="BSD" SLOT="0" KEYWORDS="~amd64" IUSE="" DEPEND="dev-python/setuptools[${PYTHON_USEDEP}]" RDEPEND="dev-python/singledispatch[${PYTHON_USEDEP}] dev-python/pyasn1[${PYTHON_USEDEP}] >=dev-python/six-1.9.0[${PYTHON_USEDEP}] >=dev-python/cryptography-1.1.0[${PYTHON_USEDEP}] $(python_gen_cond_dep 'dev-python/enum34[${PYTHON_USEDEP}]' python2_7 python3_3)" DOCS=( README.rst ) src_unpack() { if [ "${A}" != "" ]; then unpack ${A} fi cd "${WORKDIR}" mv PGPy-${PV} pgpy-${PV} } PGPy-0.5.4/install_dependencies.linux.sh000077500000000000000000000013701403641706600202200ustar00rootroot00000000000000#!/bin/bash sudo apt-get -y update sudo apt-get -y install libffi-dev gnupg2 if [ -z "${TOXENV}" ]; then sudo apt-get -y install gpgsm libassuan-dev libgpg-error-dev swig # build/install gpgme 1.8.0 manually wget https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-1.7.0.tar.bz2 tar -xvf gpgme-1.7.0.tar.bz2 pushd gpgme-1.7.0 ./configure \ --prefix=/usr \ --disable-fd-passing \ --disable-static \ --disable-gpgsm-test \ --infodir=/usr/share/info \ --with-gpg=/usr/bin/gpg \ --with-gpgsm=/usr/bin/gpgsm \ --with-gpgconf=/usr/bin/gpgconf make sudo make install sudo ldconfig popd gpgconf --kill gpg-agent gpg-agent --daemon --homedir tests/gnupghome fi PGPy-0.5.4/install_dependencies.osx.sh000077500000000000000000000001341403641706600176670ustar00rootroot00000000000000#!/bin/bash brew unlink python@3.9 && brew link --overwrite python@3.9 brew bundle install PGPy-0.5.4/pgpy/000077500000000000000000000000001403641706600133255ustar00rootroot00000000000000PGPy-0.5.4/pgpy/__init__.py000066400000000000000000000005351403641706600154410ustar00rootroot00000000000000""" PGPy :: Pretty Good Privacy for Python """ from .pgp import PGPKey from .pgp import PGPKeyring from .pgp import PGPMessage from .pgp import PGPSignature from .pgp import PGPUID __all__ = ['constants', 'errors', 'PGPKey', 'PGPKeyring', 'PGPMessage', 'PGPSignature', 'PGPUID', ] PGPy-0.5.4/pgpy/_curves.py000066400000000000000000000041741403641706600153530ustar00rootroot00000000000000""" _curves.py specify some additional curves that OpenSSL provides but cryptography doesn't explicitly expose """ from cryptography import utils from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.bindings.openssl.binding import Binding __all__ = tuple() # TODO: investigate defining additional curves using EC_GROUP_new_curve # https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography#Defining_Curves def _openssl_get_supported_curves(): if hasattr(_openssl_get_supported_curves, '_curves'): return _openssl_get_supported_curves._curves # use cryptography's cffi bindings to get an array of curve names b = Binding() cn = b.lib.EC_get_builtin_curves(b.ffi.NULL, 0) cs = b.ffi.new('EC_builtin_curve[]', cn) b.lib.EC_get_builtin_curves(cs, cn) # store the result so we don't have to do all of this every time curves = { b.ffi.string(b.lib.OBJ_nid2sn(c.nid)).decode('utf-8') for c in cs } # Ed25519 and X25519 are always present in cryptography>=2.6 # The python cryptography lib provides a different interface for these curves, # so they are handled differently in the ECDHPriv/Pub and EdDSAPriv/Pub classes curves |= {'X25519', 'ed25519'} _openssl_get_supported_curves._curves = curves return curves @utils.register_interface(ec.EllipticCurve) class BrainpoolP256R1(object): name = 'brainpoolP256r1' key_size = 256 @utils.register_interface(ec.EllipticCurve) class BrainpoolP384R1(object): name = 'brainpoolP384r1' key_size = 384 @utils.register_interface(ec.EllipticCurve) class BrainpoolP512R1(object): name = 'brainpoolP512r1' key_size = 512 @utils.register_interface(ec.EllipticCurve) class X25519(object): name = 'X25519' key_size = 256 @utils.register_interface(ec.EllipticCurve) class Ed25519(object): name = 'ed25519' key_size = 256 # add these curves to the _CURVE_TYPES list for curve in [BrainpoolP256R1, BrainpoolP384R1, BrainpoolP512R1, X25519, Ed25519]: if curve.name not in ec._CURVE_TYPES and curve.name in _openssl_get_supported_curves(): ec._CURVE_TYPES[curve.name] = curve PGPy-0.5.4/pgpy/constants.py000066400000000000000000000413021403641706600157130ustar00rootroot00000000000000""" constants.py """ import bz2 import hashlib import imghdr import os import time import zlib from collections import namedtuple from enum import Enum from enum import IntEnum from pyasn1.type.univ import ObjectIdentifier import six from cryptography.hazmat.backends import openssl from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.ciphers import algorithms from .decorators import classproperty from .types import FlagEnum from ._curves import BrainpoolP256R1, BrainpoolP384R1, BrainpoolP512R1, X25519, Ed25519 __all__ = ['Backend', 'EllipticCurveOID', 'ECPointFormat', 'PacketTag', 'SymmetricKeyAlgorithm', 'PubKeyAlgorithm', 'CompressionAlgorithm', 'HashAlgorithm', 'RevocationReason', 'ImageEncoding', 'SignatureType', 'KeyServerPreferences', 'S2KGNUExtension', 'String2KeyType', 'TrustLevel', 'KeyFlags', 'Features', 'RevocationKeyClass', 'NotationDataFlags', 'TrustFlags'] # this is 50 KiB _hashtunedata = bytearray([10, 11, 12, 13, 14, 15, 16, 17] * 128 * 50) class Backend(Enum): OpenSSL = openssl.backend class EllipticCurveOID(Enum): """OIDs for supported elliptic curves.""" # these are specified as: # id = (oid, curve) Invalid = ('', ) #: DJB's fast elliptic curve Curve25519 = ('1.3.6.1.4.1.3029.1.5.1', X25519) #: Twisted Edwards variant of Curve25519 Ed25519 = ('1.3.6.1.4.1.11591.15.1', Ed25519) #: NIST P-256, also known as SECG curve secp256r1 NIST_P256 = ('1.2.840.10045.3.1.7', ec.SECP256R1) #: NIST P-384, also known as SECG curve secp384r1 NIST_P384 = ('1.3.132.0.34', ec.SECP384R1) #: NIST P-521, also known as SECG curve secp521r1 NIST_P521 = ('1.3.132.0.35', ec.SECP521R1) #: Brainpool Standard Curve, 256-bit #: #: .. note:: #: Requires OpenSSL >= 1.0.2 Brainpool_P256 = ('1.3.36.3.3.2.8.1.1.7', BrainpoolP256R1) #: Brainpool Standard Curve, 384-bit #: #: .. note:: #: Requires OpenSSL >= 1.0.2 Brainpool_P384 = ('1.3.36.3.3.2.8.1.1.11', BrainpoolP384R1) #: Brainpool Standard Curve, 512-bit #: #: .. note:: #: Requires OpenSSL >= 1.0.2 Brainpool_P512 = ('1.3.36.3.3.2.8.1.1.13', BrainpoolP512R1) #: SECG curve secp256k1 SECP256K1 = ('1.3.132.0.10', ec.SECP256K1) def __new__(cls, oid, curve=None): # preprocessing stage for enum members: # - set enum_member.value to ObjectIdentifier(oid) # - if curve is not None and curve.name is in ec._CURVE_TYPES, set enum_member.curve to curve # - otherwise, set enum_member.curve to None obj = object.__new__(cls) obj._value_ = ObjectIdentifier(oid) obj.curve = None if curve is not None and curve.name in ec._CURVE_TYPES: obj.curve = curve return obj @property def can_gen(self): return self.curve is not None @property def key_size(self): if self.curve is not None: return self.curve.key_size @property def kdf_halg(self): # return the hash algorithm to specify in the KDF fields when generating a key algs = {256: HashAlgorithm.SHA256, 384: HashAlgorithm.SHA384, 512: HashAlgorithm.SHA512, 521: HashAlgorithm.SHA512} return algs.get(self.key_size, None) @property def kek_alg(self): # return the AES algorithm to specify in the KDF fields when generating a key algs = {256: SymmetricKeyAlgorithm.AES128, 384: SymmetricKeyAlgorithm.AES192, 512: SymmetricKeyAlgorithm.AES256, 521: SymmetricKeyAlgorithm.AES256} return algs.get(self.key_size, None) class ECPointFormat(IntEnum): # https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-07#appendix-B Standard = 0x04 Native = 0x40 OnlyX = 0x41 OnlyY = 0x42 class PacketTag(IntEnum): Invalid = 0 PublicKeyEncryptedSessionKey = 1 Signature = 2 SymmetricKeyEncryptedSessionKey = 3 OnePassSignature = 4 SecretKey = 5 PublicKey = 6 SecretSubKey = 7 CompressedData = 8 SymmetricallyEncryptedData = 9 Marker = 10 LiteralData = 11 Trust = 12 UserID = 13 PublicSubKey = 14 UserAttribute = 17 SymmetricallyEncryptedIntegrityProtectedData = 18 ModificationDetectionCode = 19 class SymmetricKeyAlgorithm(IntEnum): """Supported symmetric key algorithms.""" Plaintext = 0x00 #: .. warning:: IDEA is insecure. PGPy only allows it to be used for decryption, not encryption! IDEA = 0x01 #: Triple-DES with 168-bit key derived from 192 TripleDES = 0x02 #: CAST5 (or CAST-128) with 128-bit key CAST5 = 0x03 #: Blowfish with 128-bit key and 16 rounds Blowfish = 0x04 #: AES with 128-bit key AES128 = 0x07 #: AES with 192-bit key AES192 = 0x08 #: AES with 256-bit key AES256 = 0x09 # Twofish with 256-bit key - not currently supported Twofish256 = 0x0A #: Camellia with 128-bit key Camellia128 = 0x0B #: Camellia with 192-bit key Camellia192 = 0x0C #: Camellia with 256-bit key Camellia256 = 0x0D @property def cipher(self): bs = {SymmetricKeyAlgorithm.IDEA: algorithms.IDEA, SymmetricKeyAlgorithm.TripleDES: algorithms.TripleDES, SymmetricKeyAlgorithm.CAST5: algorithms.CAST5, SymmetricKeyAlgorithm.Blowfish: algorithms.Blowfish, SymmetricKeyAlgorithm.AES128: algorithms.AES, SymmetricKeyAlgorithm.AES192: algorithms.AES, SymmetricKeyAlgorithm.AES256: algorithms.AES, SymmetricKeyAlgorithm.Twofish256: namedtuple('Twofish256', ['block_size'])(block_size=128), SymmetricKeyAlgorithm.Camellia128: algorithms.Camellia, SymmetricKeyAlgorithm.Camellia192: algorithms.Camellia, SymmetricKeyAlgorithm.Camellia256: algorithms.Camellia} if self in bs: return bs[self] raise NotImplementedError(repr(self)) @property def is_supported(self): return callable(self.cipher) @property def is_insecure(self): insecure_ciphers = {SymmetricKeyAlgorithm.IDEA} return self in insecure_ciphers @property def block_size(self): return self.cipher.block_size @property def key_size(self): ks = {SymmetricKeyAlgorithm.IDEA: 128, SymmetricKeyAlgorithm.TripleDES: 192, SymmetricKeyAlgorithm.CAST5: 128, SymmetricKeyAlgorithm.Blowfish: 128, SymmetricKeyAlgorithm.AES128: 128, SymmetricKeyAlgorithm.AES192: 192, SymmetricKeyAlgorithm.AES256: 256, SymmetricKeyAlgorithm.Twofish256: 256, SymmetricKeyAlgorithm.Camellia128: 128, SymmetricKeyAlgorithm.Camellia192: 192, SymmetricKeyAlgorithm.Camellia256: 256} if self in ks: return ks[self] raise NotImplementedError(repr(self)) def gen_iv(self): return os.urandom(self.block_size // 8) def gen_key(self): return os.urandom(self.key_size // 8) class PubKeyAlgorithm(IntEnum): """Supported public key algorithms.""" Invalid = 0x00 #: Signifies that a key is an RSA key. RSAEncryptOrSign = 0x01 RSAEncrypt = 0x02 # deprecated RSASign = 0x03 # deprecated #: Signifies that a key is an ElGamal key. ElGamal = 0x10 #: Signifies that a key is a DSA key. DSA = 0x11 #: Signifies that a key is an ECDH key. ECDH = 0x12 #: Signifies that a key is an ECDSA key. ECDSA = 0x13 FormerlyElGamalEncryptOrSign = 0x14 # deprecated - do not generate DiffieHellman = 0x15 # X9.42 EdDSA = 0x16 # https://tools.ietf.org/html/draft-koch-eddsa-for-openpgp-04 @property def can_gen(self): return self in {PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.DSA, PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.ECDH, PubKeyAlgorithm.EdDSA} @property def can_encrypt(self): # pragma: no cover return self in {PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.ElGamal, PubKeyAlgorithm.ECDH} @property def can_sign(self): return self in {PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.DSA, PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.EdDSA} @property def deprecated(self): return self in {PubKeyAlgorithm.RSAEncrypt, PubKeyAlgorithm.RSASign, PubKeyAlgorithm.FormerlyElGamalEncryptOrSign} class CompressionAlgorithm(IntEnum): """Supported compression algorithms.""" #: No compression Uncompressed = 0x00 #: ZIP DEFLATE ZIP = 0x01 #: ZIP DEFLATE with zlib headers ZLIB = 0x02 #: Bzip2 BZ2 = 0x03 def compress(self, data): if self is CompressionAlgorithm.Uncompressed: return data if self is CompressionAlgorithm.ZIP: return zlib.compress(data)[2:-4] if self is CompressionAlgorithm.ZLIB: return zlib.compress(data) if self is CompressionAlgorithm.BZ2: return bz2.compress(data) raise NotImplementedError(self) def decompress(self, data): if six.PY2: data = bytes(data) if self is CompressionAlgorithm.Uncompressed: return data if self is CompressionAlgorithm.ZIP: return zlib.decompress(data, -15) if self is CompressionAlgorithm.ZLIB: return zlib.decompress(data) if self is CompressionAlgorithm.BZ2: return bz2.decompress(data) raise NotImplementedError(self) class HashAlgorithm(IntEnum): """Supported hash algorithms.""" Invalid = 0x00 MD5 = 0x01 SHA1 = 0x02 RIPEMD160 = 0x03 _reserved_1 = 0x04 _reserved_2 = 0x05 _reserved_3 = 0x06 _reserved_4 = 0x07 SHA256 = 0x08 SHA384 = 0x09 SHA512 = 0x0A SHA224 = 0x0B def __init__(self, *args): super(self.__class__, self).__init__() self._tuned_count = 255 @property def hasher(self): return hashlib.new(self.name) @property def digest_size(self): return self.hasher.digest_size @property def tuned_count(self): return self._tuned_count @property def is_supported(self): return True class RevocationReason(IntEnum): """Reasons explaining why a key or certificate was revoked.""" #: No reason was specified. This is the default reason. NotSpecified = 0x00 #: The key was superseded by a new key. Only meaningful when revoking a key. Superseded = 0x01 #: Key material has been compromised. Only meaningful when revoking a key. Compromised = 0x02 #: Key is retired and no longer used. Only meaningful when revoking a key. Retired = 0x03 #: User ID information is no longer valid. Only meaningful when revoking a certification of a user id. UserID = 0x20 class ImageEncoding(IntEnum): Unknown = 0x00 JPEG = 0x01 @classmethod def encodingof(cls, imagebytes): type = imghdr.what(None, h=imagebytes) if type == 'jpeg': return ImageEncoding.JPEG return ImageEncoding.Unknown # pragma: no cover class SignatureType(IntEnum): """Types of signatures that can be found in a Signature packet.""" #: The signer either owns this document, created it, or certifies that it #: has not been modified. BinaryDocument = 0x00 #: The signer either owns this document, created it, or certifies that it #: has not been modified. The signature is calculated over the text #: data with its line endings converted to ````. CanonicalDocument = 0x01 #: This signature is a signature of only its own subpacket contents. #: It is calculated identically to a signature over a zero-length #: ``BinaryDocument``. Standalone = 0x02 #: The issuer of this certification does not make any particular #: claim as to how well the certifier has checked that the owner #: of the key is in fact the person described by the User ID. Generic_Cert = 0x10 #: The issuer of this certification has not done any verification of #: the claim that the owner of this key is the User ID specified. Persona_Cert = 0x11 #: The issuer of this certification has done some casual #: verification of the claim of identity. Casual_Cert = 0x12 #: The issuer of this certification has done substantial #: verification of the claim of identity. Positive_Cert = 0x13 #: This signature is issued by the primary key over itself and its user ID (or user attribute). #: See `draft-ietf-openpgp-rfc4880bis-08 `_ Attestation = 0x16 #: This signature is a statement by the top-level signing key that #: indicates that it owns the subkey. This signature is calculated #: directly on the primary key and subkey, and not on any User ID or #: other packets. Subkey_Binding = 0x18 #: This signature is a statement by a signing subkey, indicating #: that it is owned by the primary key and subkey. This signature #: is calculated the same way as a ``Subkey_Binding`` signature. PrimaryKey_Binding = 0x19 #: A signature calculated directly on a key. It binds the #: information in the Signature subpackets to the key, and is #: appropriate to be used for subpackets that provide information #: about the key, such as the Revocation Key subpacket. It is also #: appropriate for statements that non-self certifiers want to make #: about the key itself, rather than the binding between a key and a #: name. DirectlyOnKey = 0x1F #: A signature calculated directly on the key being revoked. #: Only revocation signatures by the key being revoked, or by an #: authorized revocation key, should be considered valid revocation signatures. KeyRevocation = 0x20 #: A signature calculated directly on the subkey being revoked. #: Only revocation signatures by the top-level signature key that is bound to this subkey, #: or by an authorized revocation key, should be considered valid revocation signatures. SubkeyRevocation = 0x28 #: This signature revokes an earlier User ID certification signature or direct-key signature. #: It should be issued by the same key that issued the revoked signature or an authorized revocation key. #: The signature is computed over the same data as the certificate that it revokes. CertRevocation = 0x30 #: This signature is only meaningful for the timestamp contained in it. Timestamp = 0x40 #: This signature is a signature over some other OpenPGP Signature #: packet(s). It is analogous to a notary seal on the signed data. ThirdParty_Confirmation = 0x50 class KeyServerPreferences(FlagEnum): NoModify = 0x80 class String2KeyType(IntEnum): Simple = 0 Salted = 1 Reserved = 2 Iterated = 3 GNUExtension = 101 class S2KGNUExtension(IntEnum): NoSecret = 1 Smartcard = 2 class TrustLevel(IntEnum): Unknown = 0 Expired = 1 Undefined = 2 Never = 3 Marginal = 4 Fully = 5 Ultimate = 6 class KeyFlags(FlagEnum): """Flags that determine a key's capabilities.""" #: Signifies that a key may be used to certify keys and user ids. Primary keys always have this, even if it is not specified. Certify = 0x01 #: Signifies that a key may be used to sign messages and documents. Sign = 0x02 #: Signifies that a key may be used to encrypt messages. EncryptCommunications = 0x04 #: Signifies that a key may be used to encrypt storage. Currently equivalent to :py:obj:`~pgpy.constants.EncryptCommunications`. EncryptStorage = 0x08 #: Signifies that the private component of a given key may have been split by a secret-sharing mechanism. Split #: keys are not currently supported by PGPy. Split = 0x10 #: Signifies that a key may be used for authentication. Authentication = 0x20 #: Signifies that the private component of a key may be in the possession of more than one person. MultiPerson = 0x80 class Features(FlagEnum): ModificationDetection = 0x01 @classproperty def pgpy_features(cls): return Features.ModificationDetection class RevocationKeyClass(FlagEnum): Sensitive = 0x40 Normal = 0x80 class NotationDataFlags(FlagEnum): HumanReadable = 0x80 class TrustFlags(FlagEnum): Revoked = 0x20 SubRevoked = 0x40 Disabled = 0x80 PendingCheck = 0x100 PGPy-0.5.4/pgpy/decorators.py000066400000000000000000000076451403641706600160600ustar00rootroot00000000000000""" decorators.py """ import contextlib import functools import six import logging try: from singledispatch import singledispatch except ImportError: # pragma: no cover from functools import singledispatch from .errors import PGPError __all__ = ['classproperty', 'sdmethod', 'sdproperty', 'KeyAction'] def classproperty(fget): class ClassProperty(object): def __init__(self, fget): self.fget = fget self.__doc__ = fget.__doc__ def __get__(self, cls, owner): return self.fget(owner) def __set__(self, obj, value): # pragma: no cover raise AttributeError("Read-only attribute") def __delete__(self, obj): # pragma: no cover raise AttributeError("Read-only attribute") return ClassProperty(fget) def sdmethod(meth): """ This is a hack to monkey patch sdproperty to work as expected with instance methods. """ sd = singledispatch(meth) def wrapper(obj, *args, **kwargs): return sd.dispatch(args[0].__class__)(obj, *args, **kwargs) wrapper.register = sd.register wrapper.dispatch = sd.dispatch wrapper.registry = sd.registry wrapper._clear_cache = sd._clear_cache functools.update_wrapper(wrapper, meth) return wrapper def sdproperty(fget): def defset(obj, val): # pragma: no cover raise TypeError(str(val.__class__)) class SDProperty(property): def register(self, cls=None, fset=None): return self.fset.register(cls, fset) def setter(self, fset): self.register(object, fset) return type(self)(self.fget, self.fset, self.fdel, self.__doc__) return SDProperty(fget, sdmethod(defset)) class KeyAction(object): def __init__(self, *usage, **conditions): super(KeyAction, self).__init__() self.flags = set(usage) self.conditions = conditions @contextlib.contextmanager def usage(self, key, user): def _preiter(first, iterable): yield first for item in iterable: yield item em = {} em['keyid'] = key.fingerprint.keyid em['flags'] = ', '.join(flag.name for flag in self.flags) if len(self.flags): for _key in _preiter(key, key.subkeys.values()): if self.flags & set(_key._get_key_flags(user)): break else: # pragma: no cover raise PGPError("Key {keyid:s} does not have the required usage flag {flags:s}".format(**em)) else: _key = key if _key is not key: em['subkeyid'] = _key.fingerprint.keyid logging.debug("Key {keyid:s} does not have the required usage flag {flags:s}; using subkey {subkeyid:s}" "".format(**em)) # TODO: consider adding stacklevel=4 when we only support Python >= 3.8 yield _key def check_attributes(self, key): for attr, expected in self.conditions.items(): if getattr(key, attr) != expected: raise PGPError("Expected: {attr:s} == {eval:s}. Got: {got:s}" "".format(attr=attr, eval=str(expected), got=str(getattr(key, attr)))) def __call__(self, action): # @functools.wraps(action) @six.wraps(action) def _action(key, *args, **kwargs): if key._key is None: raise PGPError("No key!") # if a key is in the process of being created, it needs to be allowed to certify its own user id if len(key._uids) == 0 and key.is_primary and action is not key.certify.__wrapped__: raise PGPError("Key is not complete - please add a User ID!") with self.usage(key, kwargs.get('user', None)) as _key: self.check_attributes(key) # do the thing return action(_key, *args, **kwargs) return _action PGPy-0.5.4/pgpy/errors.py000066400000000000000000000020411403641706600152100ustar00rootroot00000000000000""" errors.py """ __all__ = ('PGPError', 'PGPEncryptionError', 'PGPDecryptionError', 'PGPIncompatibleECPointFormat', 'PGPOpenSSLCipherNotSupported', 'PGPInsecureCipher', 'WontImplementError',) class PGPError(Exception): """Raised as a general error in PGPy""" pass class PGPEncryptionError(Exception): """Raised when encryption fails""" pass class PGPDecryptionError(Exception): """Raised when decryption fails""" pass class PGPIncompatibleECPointFormat(Exception): """Raised when the point format is incompatible with the elliptic curve""" pass class PGPOpenSSLCipherNotSupported(Exception): """Raised when OpenSSL does not support the requested cipher""" pass class PGPInsecureCipher(Exception): """Raised when a cipher known to be insecure is attempted to be used to encrypt data""" pass class WontImplementError(NotImplementedError): """Raised when something that is not implemented, will not be implemented""" pass PGPy-0.5.4/pgpy/memoryview.py000066400000000000000000000105621403641706600161060ustar00rootroot00000000000000""" util.py """ import six __all__ = ('memoryview', ) memoryview = memoryview if six.PY2: # because Python2's memoryview can't be released directly, nor can it be used as a context manager # this wrapper object should hopefully make the behavior more uniform to python 3's import __builtin__ import functools # this decorator will raise a ValueError if the wrapped memoryview object has been "released" def notreleased(meth): @functools.wraps(meth) def _inner(self, *args, **kwargs): if self._mem is None: raise ValueError("operation forbidden on released memoryview object") return meth(self, *args, **kwargs) return _inner class memoryview(object): # flake8: noqa @property @notreleased def obj(self): """The underlying object of the memoryview.""" return self._obj @property @notreleased def nbytes(self): # nbytes == product(shape) * itemsize == len(m.tobytes()) nb = 1 for dim in self.shape: nb *= dim return nb * self.itemsize # TODO: c_contiguous -> (self.ndim == 0 or ???) # TODO: f_contiguous -> (self.ndim == 0 or ???) # TODO: contiguous -> return self.c_contiguous or self.f_contiguous def __new__(cls, obj, parent=None): memview = object.__new__(cls) memview._obj = obj if parent is None else parent.obj return memview def __init__(self, obj): if not hasattr(self, '_mem'): if not isinstance(obj, __builtin__.memoryview): obj = __builtin__.memoryview(obj) self._mem = obj def __dir__(self): # so dir(...) looks like a memoryview object, and also # contains our additional methods and properties, but not our instance members return sorted(set(self.__class__.__dict__) | set(dir(self._mem))) @notreleased def __getitem__(self, item): # if this is a slice, it'll return another real memoryview object # we'll need to wrap that subview in another memoryview wrapper if isinstance(item, slice): return memoryview(self._mem.__getitem__(item)) return self._mem.__getitem__(item) @notreleased def __setitem__(self, key, value): self._mem.__setitem__(key, value) @notreleased def __delitem__(self, key): raise TypeError("cannot delete memory") def __getattribute__(self, item): try: return object.__getattribute__(self, item) except AttributeError: if object.__getattribute__(self, '_mem') is None: raise ValueError("operation forbidden on released memoryview object") return object.__getattribute__(self, '_mem').__getattribute__(item) def __setattr__(self, key, value): if key not in self.__dict__ and hasattr(__builtin__.memoryview, key): # there are no writable attributes on memoryview objects # changing indexed values is handled by __setitem__ raise AttributeError("attribute '{}' of 'memoryview' objects is not writable".format(key)) else: object.__setattr__(self, key, value) @notreleased def __len__(self): return len(self._mem) def __eq__(self, other): if isinstance(other, memoryview): return self._mem == other._mem return self._mem == other @notreleased def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): self.release() def __repr__(self): return '<{}memory at 0x{:02X}>'.format('' if self._mem else 'released ', id(self)) def release(self): """Release the underlying buffer exposed by the memoryview object""" # this should effectively do the same job as memoryview.release() in Python 3 self._mem = None self._obj = None @notreleased def hex(self): """Return the data in the buffer as a string of hexadecimal numbers.""" return ''.join(('{:02X}'.format(ord(c)) for c in self._mem)) # TODO: cast PGPy-0.5.4/pgpy/packet/000077500000000000000000000000001403641706600145745ustar00rootroot00000000000000PGPy-0.5.4/pgpy/packet/__init__.py000066400000000000000000000004401403641706600167030ustar00rootroot00000000000000from .types import Key from .types import Opaque from .types import Packet from .types import Primary from .types import Private from .types import Public from .types import Sub from .packets import * # NOQA __all__ = ['Key', 'Opaque', 'Packet', 'Primary', 'Private', 'Public', 'Sub'] PGPy-0.5.4/pgpy/packet/fields.py000066400000000000000000001600041403641706600164150ustar00rootroot00000000000000""" fields.py """ from __future__ import absolute_import, division import abc import binascii import collections import copy import hashlib import itertools import math import os try: import collections.abc as collections_abc except ImportError: collections_abc = collections from pyasn1.codec.der import decoder from pyasn1.codec.der import encoder from pyasn1.type.univ import Integer from pyasn1.type.univ import Sequence from pyasn1.type.namedtype import NamedTypes, NamedType from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import dsa from cryptography.hazmat.primitives.asymmetric import ec from cryptography.hazmat.primitives.asymmetric import ed25519 from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric import x25519 from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash from cryptography.hazmat.primitives.keywrap import aes_key_wrap from cryptography.hazmat.primitives.keywrap import aes_key_unwrap from cryptography.hazmat.primitives.padding import PKCS7 from .subpackets import Signature as SignatureSP from .subpackets import UserAttribute from .subpackets import signature from .subpackets import userattribute from .types import MPI from .types import MPIs from ..constants import EllipticCurveOID from ..constants import ECPointFormat from ..constants import HashAlgorithm from ..constants import PubKeyAlgorithm from ..constants import String2KeyType from ..constants import S2KGNUExtension from ..constants import SymmetricKeyAlgorithm from ..decorators import sdproperty from ..errors import PGPDecryptionError from ..errors import PGPError from ..errors import PGPIncompatibleECPointFormat from ..symenc import _decrypt from ..symenc import _encrypt from ..types import Field __all__ = ['SubPackets', 'UserAttributeSubPackets', 'Signature', 'OpaqueSignature', 'RSASignature', 'DSASignature', 'ECDSASignature', 'EdDSASignature', 'PubKey', 'OpaquePubKey', 'RSAPub', 'DSAPub', 'ElGPub', 'ECPoint', 'ECDSAPub', 'EdDSAPub', 'ECDHPub', 'String2Key', 'ECKDF', 'PrivKey', 'OpaquePrivKey', 'RSAPriv', 'DSAPriv', 'ElGPriv', 'ECDSAPriv', 'EdDSAPriv', 'ECDHPriv', 'CipherText', 'RSACipherText', 'ElGCipherText', 'ECDHCipherText', ] class SubPackets(collections_abc.MutableMapping, Field): _spmodule = signature def __init__(self): super(SubPackets, self).__init__() self._hashed_sp = collections.OrderedDict() self._unhashed_sp = collections.OrderedDict() def __bytearray__(self): _bytes = bytearray() _bytes += self.__hashbytearray__() _bytes += self.__unhashbytearray__() return _bytes def __hashbytearray__(self): _bytes = bytearray() _bytes += self.int_to_bytes(sum(len(sp) for sp in self._hashed_sp.values()), 2) for hsp in self._hashed_sp.values(): _bytes += hsp.__bytearray__() return _bytes def __unhashbytearray__(self): _bytes = bytearray() _bytes += self.int_to_bytes(sum(len(sp) for sp in self._unhashed_sp.values()), 2) for uhsp in self._unhashed_sp.values(): _bytes += uhsp.__bytearray__() return _bytes def __len__(self): # pragma: no cover return sum(sp.header.length for sp in itertools.chain(self._hashed_sp.values(), self._unhashed_sp.values())) + 4 def __iter__(self): for sp in itertools.chain(self._hashed_sp.values(), self._unhashed_sp.values()): yield sp def __setitem__(self, key, val): # the key provided should always be the classname for the subpacket # but, there can be multiple subpackets of the same type # so, it should be stored in the format: [h_]_ # where: # - is the classname of val # - is a sequence id, starting at 0, for a given classname i = 0 if isinstance(key, tuple): # pragma: no cover key, i = key d = self._unhashed_sp if key.startswith('h_'): d, key = self._hashed_sp, key[2:] while (key, i) in d: i += 1 d[(key, i)] = val def __getitem__(self, key): if isinstance(key, tuple): # pragma: no cover return self._hashed_sp.get(key, self._unhashed_sp.get(key)) if key.startswith('h_'): return [v for k, v in self._hashed_sp.items() if key[2:] == k[0]] else: return [v for k, v in itertools.chain(self._hashed_sp.items(), self._unhashed_sp.items()) if key == k[0]] def __delitem__(self, key): ##TODO: this raise NotImplementedError def __contains__(self, key): return key in set(k for k, _ in itertools.chain(self._hashed_sp, self._unhashed_sp)) def __copy__(self): sp = SubPackets() sp._hashed_sp = self._hashed_sp.copy() sp._unhashed_sp = self._unhashed_sp.copy() return sp def addnew(self, spname, hashed=False, **kwargs): nsp = getattr(self._spmodule, spname)() for p, v in kwargs.items(): if hasattr(nsp, p): setattr(nsp, p, v) nsp.update_hlen() if hashed: self['h_' + spname] = nsp else: self[spname] = nsp def update_hlen(self): for sp in self: sp.update_hlen() def parse(self, packet): hl = self.bytes_to_int(packet[:2]) del packet[:2] # we do it this way because we can't ensure that subpacket headers are sized appropriately # for their contents, but we can at least output that correctly # so instead of tracking how many bytes we can now output, we track how many bytes have we parsed so far plen = len(packet) while plen - len(packet) < hl: sp = SignatureSP(packet) self['h_' + sp.__class__.__name__] = sp uhl = self.bytes_to_int(packet[:2]) del packet[:2] plen = len(packet) while plen - len(packet) < uhl: sp = SignatureSP(packet) self[sp.__class__.__name__] = sp class UserAttributeSubPackets(SubPackets): """ This is nearly the same as just the unhashed subpackets from above, except that there isn't a length specifier. So, parse will only parse one packet, appending that one packet to self.__unhashed_sp. """ _spmodule = userattribute def __bytearray__(self): _bytes = bytearray() for uhsp in self._unhashed_sp.values(): _bytes += uhsp.__bytearray__() return _bytes def __len__(self): # pragma: no cover return sum(len(sp) for sp in self._unhashed_sp.values()) def parse(self, packet): # parse just one packet and add it to the unhashed subpacket ordereddict # I actually have yet to come across a User Attribute packet with more than one subpacket # which makes sense, given that there is only one defined subpacket sp = UserAttribute(packet) self[sp.__class__.__name__] = sp class Signature(MPIs): def __init__(self): for i in self.__mpis__: setattr(self, i, MPI(0)) def __bytearray__(self): _bytes = bytearray() for i in self: _bytes += i.to_mpibytes() return _bytes @abc.abstractproperty def __sig__(self): """return the signature bytes in a format that can be understood by the signature verifier""" @abc.abstractmethod def from_signer(self, sig): """create and parse a concrete Signature class instance""" class OpaqueSignature(Signature): def __init__(self): super(OpaqueSignature, self).__init__() self.data = bytearray() def __bytearray__(self): return self.data def __sig__(self): return self.data def parse(self, packet): self.data = packet def from_signer(self, sig): self.data = bytearray(sig) class RSASignature(Signature): __mpis__ = ('md_mod_n', ) def __sig__(self): return self.md_mod_n.to_mpibytes()[2:] def parse(self, packet): self.md_mod_n = MPI(packet) def from_signer(self, sig): self.md_mod_n = MPI(self.bytes_to_int(sig)) class DSASignature(Signature): __mpis__ = ('r', 's') def __sig__(self): # return the signature data into an ASN.1 sequence of integers in DER format seq = Sequence(componentType=NamedTypes(*[NamedType(n, Integer()) for n in self.__mpis__])) for n in self.__mpis__: seq.setComponentByName(n, getattr(self, n)) return encoder.encode(seq) def from_signer(self, sig): ##TODO: just use pyasn1 for this def _der_intf(_asn): if _asn[0] != 0x02: # pragma: no cover raise ValueError("Expected: Integer (0x02). Got: 0x{:02X}".format(_asn[0])) del _asn[0] if _asn[0] & 0x80: # pragma: no cover llen = _asn[0] & 0x7F del _asn[0] flen = self.bytes_to_int(_asn[:llen]) del _asn[:llen] else: flen = _asn[0] & 0x7F del _asn[0] i = self.bytes_to_int(_asn[:flen]) del _asn[:flen] return i if isinstance(sig, bytes): sig = bytearray(sig) # this is a very limited asn1 decoder - it is only intended to decode a DER encoded sequence of integers if not sig[0] == 0x30: raise NotImplementedError("Expected: Sequence (0x30). Got: 0x{:02X}".format(sig[0])) del sig[0] # skip the sequence length field if sig[0] & 0x80: # pragma: no cover llen = sig[0] & 0x7F del sig[:llen + 1] else: del sig[0] self.r = MPI(_der_intf(sig)) self.s = MPI(_der_intf(sig)) def parse(self, packet): self.r = MPI(packet) self.s = MPI(packet) class ECDSASignature(DSASignature): def from_signer(self, sig): seq, _ = decoder.decode(sig) self.r = MPI(seq[0]) self.s = MPI(seq[1]) class EdDSASignature(DSASignature): def from_signer(self, sig): lsig = len(sig) if lsig % 2 != 0: raise PGPError("malformed EdDSA signature") split = lsig // 2 self.r = MPI(self.bytes_to_int(sig[:split])) self.s = MPI(self.bytes_to_int(sig[split:])) def __sig__(self): # TODO: change this length when EdDSA can be used with another curve (Ed448) l = (EllipticCurveOID.Ed25519.key_size + 7) // 8 return self.int_to_bytes(self.r, l) + self.int_to_bytes(self.s, l) class PubKey(MPIs): __pubfields__ = () @property def __mpis__(self): for i in self.__pubfields__: yield i def __init__(self): super(PubKey, self).__init__() for field in self.__pubfields__: if isinstance(field, tuple): # pragma: no cover field, val = field else: val = MPI(0) setattr(self, field, val) @abc.abstractmethod def __pubkey__(self): """return the requisite *PublicKey class from the cryptography library""" def __len__(self): return sum(len(getattr(self, i)) for i in self.__pubfields__) def __bytearray__(self): _bytes = bytearray() for field in self.__pubfields__: _bytes += getattr(self, field).to_mpibytes() return _bytes def publen(self): return len(self) def verify(self, subj, sigbytes, hash_alg): return NotImplemented # pragma: no cover class OpaquePubKey(PubKey): # pragma: no cover def __init__(self): super(OpaquePubKey, self).__init__() self.data = bytearray() def __iter__(self): yield self.data def __pubkey__(self): return NotImplemented def __bytearray__(self): return self.data def parse(self, packet): ##TODO: this needs to be length-bounded to the end of the packet self.data = packet class RSAPub(PubKey): __pubfields__ = ('n', 'e') def __pubkey__(self): return rsa.RSAPublicNumbers(self.e, self.n).public_key(default_backend()) def verify(self, subj, sigbytes, hash_alg): # zero-pad sigbytes if necessary sigbytes = (b'\x00' * (self.n.byte_length() - len(sigbytes))) + sigbytes try: self.__pubkey__().verify(sigbytes, subj, padding.PKCS1v15(), hash_alg) except InvalidSignature: return False return True def parse(self, packet): self.n = MPI(packet) self.e = MPI(packet) class DSAPub(PubKey): __pubfields__ = ('p', 'q', 'g', 'y') def __pubkey__(self): params = dsa.DSAParameterNumbers(self.p, self.q, self.g) return dsa.DSAPublicNumbers(self.y, params).public_key(default_backend()) def verify(self, subj, sigbytes, hash_alg): try: self.__pubkey__().verify(sigbytes, subj, hash_alg) except InvalidSignature: return False return True def parse(self, packet): self.p = MPI(packet) self.q = MPI(packet) self.g = MPI(packet) self.y = MPI(packet) class ElGPub(PubKey): __pubfields__ = ('p', 'g', 'y') def __pubkey__(self): raise NotImplementedError() def parse(self, packet): self.p = MPI(packet) self.g = MPI(packet) self.y = MPI(packet) class ECPoint: def __init__(self, packet=None): if packet is None: return xy = bytearray(MPI(packet).to_mpibytes()[2:]) self.format = ECPointFormat(xy[0]) del xy[0] if self.format == ECPointFormat.Standard: xylen = len(xy) if xylen % 2 != 0: raise PGPError("malformed EC point") self.bytelen = xylen // 2 self.x = MPI(MPIs.bytes_to_int(xy[:self.bytelen])) self.y = MPI(MPIs.bytes_to_int(xy[self.bytelen:])) elif self.format == ECPointFormat.Native: self.bytelen = 0 # dummy value for copy self.x = bytes(xy) self.y = None else: raise NotImplementedError("No curve is supposed to use only X or Y coordinates") @classmethod def from_values(cls, bitlen, pform, x, y=None): ct = cls() ct.bytelen = (bitlen + 7) // 8 ct.format = pform ct.x = x ct.y = y return ct def __len__(self): """ Returns length of MPI encoded point """ if self.format == ECPointFormat.Standard: return 2 * self.bytelen + 3 elif self.format == ECPointFormat.Native: return len(self.x) + 3 else: raise NotImplementedError("No curve is supposed to use only X or Y coordinates") def to_mpibytes(self): """ Returns MPI encoded point as it should be written in packet """ b = bytearray() b.append(self.format) if self.format == ECPointFormat.Standard: b += MPIs.int_to_bytes(self.x, self.bytelen) b += MPIs.int_to_bytes(self.y, self.bytelen) elif self.format == ECPointFormat.Native: b += self.x else: raise NotImplementedError("No curve is supposed to use only X or Y coordinates") return MPI(MPIs.bytes_to_int(b)).to_mpibytes() def __bytearray__(self): return self.to_mpibytes() def __copy__(self): pk = self.__class__() pk.bytelen = self.bytelen pk.format = self.format pk.x = copy.copy(self.x) pk.y = copy.copy(self.y) return pk class ECDSAPub(PubKey): __pubfields__ = ('p',) def __init__(self): super(ECDSAPub, self).__init__() self.oid = None def __len__(self): return len(self.p) + len(encoder.encode(self.oid.value)) - 1 def __pubkey__(self): return ec.EllipticCurvePublicNumbers(self.p.x, self.p.y, self.oid.curve()).public_key(default_backend()) def __bytearray__(self): _b = bytearray() _b += encoder.encode(self.oid.value)[1:] _b += self.p.to_mpibytes() return _b def __copy__(self): pkt = super(ECDSAPub, self).__copy__() pkt.oid = self.oid return pkt def verify(self, subj, sigbytes, hash_alg): try: self.__pubkey__().verify(sigbytes, subj, ec.ECDSA(hash_alg)) except InvalidSignature: return False return True def parse(self, packet): oidlen = packet[0] del packet[0] _oid = bytearray(b'\x06') _oid.append(oidlen) _oid += bytearray(packet[:oidlen]) oid, _ = decoder.decode(bytes(_oid)) self.oid = EllipticCurveOID(oid) del packet[:oidlen] self.p = ECPoint(packet) if self.p.format != ECPointFormat.Standard: raise PGPIncompatibleECPointFormat("Only Standard format is valid for ECDSA") class EdDSAPub(PubKey): __pubfields__ = ('p', ) def __init__(self): super(EdDSAPub, self).__init__() self.oid = None def __len__(self): return len(self.p) + len(encoder.encode(self.oid.value)) - 1 def __bytearray__(self): _b = bytearray() _b += encoder.encode(self.oid.value)[1:] _b += self.p.to_mpibytes() return _b def __pubkey__(self): return ed25519.Ed25519PublicKey.from_public_bytes(self.p.x) def __copy__(self): pkt = super(EdDSAPub, self).__copy__() pkt.oid = self.oid return pkt def verify(self, subj, sigbytes, hash_alg): # GnuPG requires a pre-hashing with EdDSA # https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-06#section-14.8 digest = hashes.Hash(hash_alg, backend=default_backend()) digest.update(subj) subj = digest.finalize() try: self.__pubkey__().verify(sigbytes, subj) except InvalidSignature: return False return True def parse(self, packet): oidlen = packet[0] del packet[0] _oid = bytearray(b'\x06') _oid.append(oidlen) _oid += bytearray(packet[:oidlen]) oid, _ = decoder.decode(bytes(_oid)) self.oid = EllipticCurveOID(oid) del packet[:oidlen] self.p = ECPoint(packet) if self.p.format != ECPointFormat.Native: raise PGPIncompatibleECPointFormat("Only Native format is valid for EdDSA") class ECDHPub(PubKey): __pubfields__ = ('p',) def __init__(self): super(ECDHPub, self).__init__() self.oid = None self.kdf = ECKDF() def __len__(self): return len(self.p) + len(self.kdf) + len(encoder.encode(self.oid.value)) - 1 def __pubkey__(self): if self.oid == EllipticCurveOID.Curve25519: return x25519.X25519PublicKey.from_public_bytes(self.p.x) else: return ec.EllipticCurvePublicNumbers(self.p.x, self.p.y, self.oid.curve()).public_key(default_backend()) def __bytearray__(self): _b = bytearray() _b += encoder.encode(self.oid.value)[1:] _b += self.p.to_mpibytes() _b += self.kdf.__bytearray__() return _b def __copy__(self): pkt = super(ECDHPub, self).__copy__() pkt.oid = self.oid pkt.kdf = copy.copy(self.kdf) return pkt def parse(self, packet): """ Algorithm-Specific Fields for ECDH keys: o a variable-length field containing a curve OID, formatted as follows: - a one-octet size of the following field; values 0 and 0xFF are reserved for future extensions - the octets representing a curve OID, defined in Section 11 - MPI of an EC point representing a public key o a variable-length field containing KDF parameters, formatted as follows: - a one-octet size of the following fields; values 0 and 0xff are reserved for future extensions - a one-octet value 01, reserved for future extensions - a one-octet hash function ID used with a KDF - a one-octet algorithm ID for the symmetric algorithm used to wrap the symmetric key used for the message encryption; see Section 8 for details """ oidlen = packet[0] del packet[0] _oid = bytearray(b'\x06') _oid.append(oidlen) _oid += bytearray(packet[:oidlen]) oid, _ = decoder.decode(bytes(_oid)) self.oid = EllipticCurveOID(oid) del packet[:oidlen] self.p = ECPoint(packet) if self.oid == EllipticCurveOID.Curve25519: if self.p.format != ECPointFormat.Native: raise PGPIncompatibleECPointFormat("Only Native format is valid for Curve25519") elif self.p.format != ECPointFormat.Standard: raise PGPIncompatibleECPointFormat("Only Standard format is valid for this curve") self.kdf.parse(packet) class String2Key(Field): """ 3.7. String-to-Key (S2K) Specifiers String-to-key (S2K) specifiers are used to convert passphrase strings into symmetric-key encryption/decryption keys. They are used in two places, currently: to encrypt the secret part of private keys in the private keyring, and to convert passphrases to encryption keys for symmetrically encrypted messages. 3.7.1. String-to-Key (S2K) Specifier Types There are three types of S2K specifiers currently supported, and some reserved values: ID S2K Type -- -------- 0 Simple S2K 1 Salted S2K 2 Reserved value 3 Iterated and Salted S2K 100 to 110 Private/Experimental S2K These are described in Sections 3.7.1.1 - 3.7.1.3. 3.7.1.1. Simple S2K This directly hashes the string to produce the key data. See below for how this hashing is done. Octet 0: 0x00 Octet 1: hash algorithm Simple S2K hashes the passphrase to produce the session key. The manner in which this is done depends on the size of the session key (which will depend on the cipher used) and the size of the hash algorithm's output. If the hash size is greater than the session key size, the high-order (leftmost) octets of the hash are used as the key. If the hash size is less than the key size, multiple instances of the hash context are created -- enough to produce the required key data. These instances are preloaded with 0, 1, 2, ... octets of zeros (that is to say, the first instance has no preloading, the second gets preloaded with 1 octet of zero, the third is preloaded with two octets of zeros, and so forth). As the data is hashed, it is given independently to each hash context. Since the contexts have been initialized differently, they will each produce different hash output. Once the passphrase is hashed, the output data from the multiple hashes is concatenated, first hash leftmost, to produce the key data, with any excess octets on the right discarded. 3.7.1.2. Salted S2K This includes a "salt" value in the S2K specifier -- some arbitrary data -- that gets hashed along with the passphrase string, to help prevent dictionary attacks. Octet 0: 0x01 Octet 1: hash algorithm Octets 2-9: 8-octet salt value Salted S2K is exactly like Simple S2K, except that the input to the hash function(s) consists of the 8 octets of salt from the S2K specifier, followed by the passphrase. 3.7.1.3. Iterated and Salted S2K This includes both a salt and an octet count. The salt is combined with the passphrase and the resulting value is hashed repeatedly. This further increases the amount of work an attacker must do to try dictionary attacks. Octet 0: 0x03 Octet 1: hash algorithm Octets 2-9: 8-octet salt value Octet 10: count, a one-octet, coded value The count is coded into a one-octet number using the following formula: #define EXPBIAS 6 count = ((Int32)16 + (c & 15)) << ((c >> 4) + EXPBIAS); The above formula is in C, where "Int32" is a type for a 32-bit integer, and the variable "c" is the coded count, Octet 10. Iterated-Salted S2K hashes the passphrase and salt data multiple times. The total number of octets to be hashed is specified in the encoded count in the S2K specifier. Note that the resulting count value is an octet count of how many octets will be hashed, not an iteration count. Initially, one or more hash contexts are set up as with the other S2K algorithms, depending on how many octets of key data are needed. Then the salt, followed by the passphrase data, is repeatedly hashed until the number of octets specified by the octet count has been hashed. The one exception is that if the octet count is less than the size of the salt plus passphrase, the full salt plus passphrase will be hashed even though that is greater than the octet count. After the hashing is done, the data is unloaded from the hash context(s) as with the other S2K algorithms. """ @sdproperty def encalg(self): return self._encalg @encalg.register(int) @encalg.register(SymmetricKeyAlgorithm) def encalg_int(self, val): self._encalg = SymmetricKeyAlgorithm(val) @sdproperty def specifier(self): return self._specifier @specifier.register(int) @specifier.register(String2KeyType) def specifier_int(self, val): self._specifier = String2KeyType(val) @sdproperty def gnuext(self): return self._gnuext @gnuext.register(int) @gnuext.register(S2KGNUExtension) def gnuext_int(self, val): self._gnuext = S2KGNUExtension(val) @sdproperty def halg(self): return self._halg @halg.register(int) @halg.register(HashAlgorithm) def halg_int(self, val): self._halg = HashAlgorithm(val) @sdproperty def count(self): return (16 + (self._count & 15)) << ((self._count >> 4) + 6) @count.register(int) def count_int(self, val): if val < 0 or val > 255: # pragma: no cover raise ValueError("count must be between 0 and 256") self._count = val def __init__(self): super(String2Key, self).__init__() self.usage = 0 self.encalg = 0 self.specifier = 0 self.iv = None # specifier-specific fields # simple, salted, iterated self.halg = 0 # salted, iterated self.salt = bytearray() # iterated self.count = 0 # GNU extension default type: ignored if specifier != GNUExtension self.gnuext = 1 # GNU extension smartcard self.scserial = None def __bytearray__(self): _bytes = bytearray() _bytes.append(self.usage) if bool(self): _bytes.append(self.encalg) _bytes.append(self.specifier) if self.specifier == String2KeyType.GNUExtension: return self._experimental_bytearray(_bytes) if self.specifier >= String2KeyType.Simple: _bytes.append(self.halg) if self.specifier >= String2KeyType.Salted: _bytes += self.salt if self.specifier == String2KeyType.Iterated: _bytes.append(self._count) if self.iv is not None: _bytes += self.iv return _bytes def _experimental_bytearray(self, _bytes): if self.specifier == String2KeyType.GNUExtension: _bytes += b'\x00GNU' _bytes.append(self.gnuext) if self.scserial: _bytes.append(len(self.scserial)) _bytes += self.scserial return _bytes def __len__(self): return len(self.__bytearray__()) def __bool__(self): return self.usage in [254, 255] def __nonzero__(self): return self.__bool__() def __copy__(self): s2k = String2Key() s2k.usage = self.usage s2k.encalg = self.encalg s2k.specifier = self.specifier s2k.gnuext = self.gnuext s2k.iv = self.iv s2k.halg = self.halg s2k.salt = copy.copy(self.salt) s2k.count = self._count s2k.scserial = self.scserial return s2k def parse(self, packet, iv=True): self.usage = packet[0] del packet[0] if bool(self): self.encalg = packet[0] del packet[0] self.specifier = packet[0] del packet[0] if self.specifier == String2KeyType.GNUExtension: return self._experimental_parse(packet, iv) if self.specifier >= String2KeyType.Simple: # this will always be true self.halg = packet[0] del packet[0] if self.specifier >= String2KeyType.Salted: self.salt = packet[:8] del packet[:8] if self.specifier == String2KeyType.Iterated: self.count = packet[0] del packet[0] if iv: self.iv = packet[:(self.encalg.block_size // 8)] del packet[:(self.encalg.block_size // 8)] def _experimental_parse(self, packet, iv=True): """ https://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=doc/DETAILS;h=3046523da62c576cf6a765a8b0829876cfdc6b3b;hb=b0f0791e4ade845b2a0e2a94dbda4f3bf1ceb039#l1346 GNU extensions to the S2K algorithm 1 octet - S2K Usage: either 254 or 255. 1 octet - S2K Cipher Algo: 0 1 octet - S2K Specifier: 101 4 octets - "\x00GNU" 1 octet - GNU S2K Extension Number. If such a GNU extension is used neither an IV nor any kind of checksum is used. The defined GNU S2K Extension Numbers are: - 1 :: Do not store the secret part at all. No specific data follows. - 2 :: A stub to access smartcards. This data follows: - One octet with the length of the following serial number. - The serial number. Regardless of what the length octet indicates no more than 16 octets are stored. """ if self.specifier == String2KeyType.GNUExtension: if packet[:4] != b'\x00GNU': raise PGPError("Invalid S2K GNU extension magic value") del packet[:4] self.gnuext = packet[0] del packet[0] if self.gnuext == S2KGNUExtension.Smartcard: slen = min(packet[0], 16) del packet[0] self.scserial = packet[:slen] del packet[:slen] def derive_key(self, passphrase): ##TODO: raise an exception if self.usage is not 254 or 255 keylen = self.encalg.key_size hashlen = self.halg.digest_size * 8 ctx = int(math.ceil((keylen / hashlen))) # Simple S2K - always done hsalt = b'' ##TODO: we could accept a passphrase that is optionally already `bytes` hpass = passphrase.encode('utf-8') # salted, iterated S2K if self.specifier >= String2KeyType.Salted: hsalt = bytes(self.salt) count = len(hsalt + hpass) if self.specifier == String2KeyType.Iterated and self.count > len(hsalt + hpass): count = self.count hcount = (count // len(hsalt + hpass)) hleft = count - (hcount * len(hsalt + hpass)) hashdata = ((hsalt + hpass) * hcount) + (hsalt + hpass)[:hleft] h = [] for i in range(0, ctx): _h = self.halg.hasher _h.update(b'\x00' * i) _h.update(hashdata) h.append(_h) # GC some stuff del hsalt del hpass del hashdata # and return the key! return b''.join(hc.digest() for hc in h)[:(keylen // 8)] class ECKDF(Field): """ o a variable-length field containing KDF parameters, formatted as follows: - a one-octet size of the following fields; values 0 and 0xff are reserved for future extensions - a one-octet value 01, reserved for future extensions - a one-octet hash function ID used with a KDF - a one-octet algorithm ID for the symmetric algorithm used to wrap the symmetric key used for the message encryption; see Section 8 for details """ @sdproperty def halg(self): return self._halg @halg.register(int) @halg.register(HashAlgorithm) def halg_int(self, val): self._halg = HashAlgorithm(val) @sdproperty def encalg(self): return self._encalg @encalg.register(int) @encalg.register(SymmetricKeyAlgorithm) def encalg_int(self, val): self._encalg = SymmetricKeyAlgorithm(val) def __init__(self): super(ECKDF, self).__init__() self.halg = 0 self.encalg = 0 def __bytearray__(self): _bytes = bytearray() _bytes.append(len(self) - 1) _bytes.append(0x01) _bytes.append(self.halg) _bytes.append(self.encalg) return _bytes def __len__(self): return 4 def parse(self, packet): # packet[0] should always be 3 # packet[1] should always be 1 # TODO: this assert is likely not necessary, but we should raise some kind of exception # if parsing fails due to these fields being incorrect assert packet[:2] == b'\x03\x01' del packet[:2] self.halg = packet[0] del packet[0] self.encalg = packet[0] del packet[0] def derive_key(self, s, curve, pkalg, fingerprint): # wrapper around the Concatenation KDF method provided by cryptography # assemble the additional data as defined in RFC 6637: # Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous data = bytearray() data += encoder.encode(curve.value)[1:] data.append(pkalg) data += b'\x03\x01' data.append(self.halg) data.append(self.encalg) data += b'Anonymous Sender ' data += binascii.unhexlify(fingerprint.replace(' ', '')) ckdf = ConcatKDFHash(algorithm=getattr(hashes, self.halg.name)(), length=self.encalg.key_size // 8, otherinfo=bytes(data), backend=default_backend()) return ckdf.derive(s) class PrivKey(PubKey): __privfields__ = () @property def __mpis__(self): for i in super(PrivKey, self).__mpis__: yield i for i in self.__privfields__: yield i def __init__(self): super(PrivKey, self).__init__() self.s2k = String2Key() self.encbytes = bytearray() self.chksum = bytearray() for field in self.__privfields__: setattr(self, field, MPI(0)) def __bytearray__(self): _bytes = bytearray() _bytes += super(PrivKey, self).__bytearray__() _bytes += self.s2k.__bytearray__() if self.s2k: _bytes += self.encbytes else: for field in self.__privfields__: _bytes += getattr(self, field).to_mpibytes() if self.s2k.usage == 0: _bytes += self.chksum return _bytes def __len__(self): l = super(PrivKey, self).__len__() + len(self.s2k) + len(self.chksum) if self.s2k: l += len(self.encbytes) else: l += sum(len(getattr(self, i)) for i in self.__privfields__) return l def __copy__(self): pk = super(PrivKey, self).__copy__() pk.s2k = copy.copy(self.s2k) pk.encbytes = copy.copy(self.encbytes) pk.chksum = copy.copy(self.chksum) return pk @abc.abstractmethod def __privkey__(self): """return the requisite *PrivateKey class from the cryptography library""" @abc.abstractmethod def _generate(self, key_size): """Generate a new PrivKey""" def _compute_chksum(self): "Calculate the key checksum" def publen(self): return super(PrivKey, self).__len__() def encrypt_keyblob(self, passphrase, enc_alg, hash_alg): # PGPy will only ever use iterated and salted S2k mode self.s2k.usage = 254 self.s2k.encalg = enc_alg self.s2k.specifier = String2KeyType.Iterated self.s2k.iv = enc_alg.gen_iv() self.s2k.halg = hash_alg self.s2k.salt = bytearray(os.urandom(8)) self.s2k.count = hash_alg.tuned_count # now that String-to-Key is ready to go, derive sessionkey from passphrase # and then unreference passphrase sessionkey = self.s2k.derive_key(passphrase) del passphrase pt = bytearray() for pf in self.__privfields__: pt += getattr(self, pf).to_mpibytes() # append a SHA-1 hash of the plaintext so far to the plaintext pt += hashlib.new('sha1', pt).digest() # encrypt self.encbytes = bytearray(_encrypt(bytes(pt), bytes(sessionkey), enc_alg, bytes(self.s2k.iv))) # delete pt and clear self del pt self.clear() @abc.abstractmethod def decrypt_keyblob(self, passphrase): if not self.s2k: # pragma: no cover # not encrypted return # Encryption/decryption of the secret data is done in CFB mode using # the key created from the passphrase and the Initial Vector from the # packet. A different mode is used with V3 keys (which are only RSA) # than with other key formats. (...) # # With V4 keys, a simpler method is used. All secret MPI values are # encrypted in CFB mode, including the MPI bitcount prefix. # derive the session key from our passphrase, and then unreference passphrase sessionkey = self.s2k.derive_key(passphrase) del passphrase # attempt to decrypt this key pt = _decrypt(bytes(self.encbytes), bytes(sessionkey), self.s2k.encalg, bytes(self.s2k.iv)) # check the hash to see if we decrypted successfully or not if self.s2k.usage == 254 and not pt[-20:] == hashlib.new('sha1', pt[:-20]).digest(): # if the usage byte is 254, key material is followed by a 20-octet sha-1 hash of the rest # of the key material block raise PGPDecryptionError("Passphrase was incorrect!") if self.s2k.usage == 255 and not self.bytes_to_int(pt[-2:]) == (sum(bytearray(pt[:-2])) % 65536): # pragma: no cover # if the usage byte is 255, key material is followed by a 2-octet checksum of the rest # of the key material block raise PGPDecryptionError("Passphrase was incorrect!") return bytearray(pt) def sign(self, sigdata, hash_alg): return NotImplemented # pragma: no cover def clear(self): """delete and re-initialize all private components to zero""" for field in self.__privfields__: delattr(self, field) setattr(self, field, MPI(0)) class OpaquePrivKey(PrivKey, OpaquePubKey): # pragma: no cover def __privkey__(self): return NotImplemented def _generate(self, key_size): # return NotImplemented raise NotImplementedError() def decrypt_keyblob(self, passphrase): return NotImplemented class RSAPriv(PrivKey, RSAPub): __privfields__ = ('d', 'p', 'q', 'u') def __privkey__(self): return rsa.RSAPrivateNumbers(self.p, self.q, self.d, rsa.rsa_crt_dmp1(self.d, self.p), rsa.rsa_crt_dmq1(self.d, self.q), rsa.rsa_crt_iqmp(self.p, self.q), rsa.RSAPublicNumbers(self.e, self.n)).private_key(default_backend()) def _compute_chksum(self): chs = sum(sum(bytearray(c.to_mpibytes())) for c in (self.d, self.p, self.q, self.u)) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) def _generate(self, key_size): if any(c != 0 for c in self): # pragma: no cover raise PGPError("key is already populated") # generate some big numbers! pk = rsa.generate_private_key(65537, key_size, default_backend()) pkn = pk.private_numbers() self.n = MPI(pkn.public_numbers.n) self.e = MPI(pkn.public_numbers.e) self.d = MPI(pkn.d) self.p = MPI(pkn.p) self.q = MPI(pkn.q) # from the RFC: # "- MPI of u, the multiplicative inverse of p, mod q." # or, simply, p^-1 mod p # rsa.rsa_crt_iqmp(p, q) normally computes q^-1 mod p, # so if we swap the values around we get the answer we want self.u = MPI(rsa.rsa_crt_iqmp(pkn.q, pkn.p)) del pkn del pk self._compute_chksum() def parse(self, packet): super(RSAPriv, self).parse(packet) self.s2k.parse(packet) if not self.s2k: self.d = MPI(packet) self.p = MPI(packet) self.q = MPI(packet) self.u = MPI(packet) if self.s2k.usage == 0: self.chksum = packet[:2] del packet[:2] else: ##TODO: this needs to be bounded to the length of the encrypted key material self.encbytes = packet def decrypt_keyblob(self, passphrase): kb = super(RSAPriv, self).decrypt_keyblob(passphrase) del passphrase self.d = MPI(kb) self.p = MPI(kb) self.q = MPI(kb) self.u = MPI(kb) if self.s2k.usage in [254, 255]: self.chksum = kb del kb def sign(self, sigdata, hash_alg): return self.__privkey__().sign(sigdata, padding.PKCS1v15(), hash_alg) class DSAPriv(PrivKey, DSAPub): __privfields__ = ('x',) def __privkey__(self): params = dsa.DSAParameterNumbers(self.p, self.q, self.g) pn = dsa.DSAPublicNumbers(self.y, params) return dsa.DSAPrivateNumbers(self.x, pn).private_key(default_backend()) def _compute_chksum(self): chs = sum(bytearray(self.x.to_mpibytes())) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) def _generate(self, key_size): if any(c != 0 for c in self): # pragma: no cover raise PGPError("key is already populated") # generate some big numbers! pk = dsa.generate_private_key(key_size, default_backend()) pkn = pk.private_numbers() self.p = MPI(pkn.public_numbers.parameter_numbers.p) self.q = MPI(pkn.public_numbers.parameter_numbers.q) self.g = MPI(pkn.public_numbers.parameter_numbers.g) self.y = MPI(pkn.public_numbers.y) self.x = MPI(pkn.x) del pkn del pk self._compute_chksum() def parse(self, packet): super(DSAPriv, self).parse(packet) self.s2k.parse(packet) if not self.s2k: self.x = MPI(packet) else: self.encbytes = packet if self.s2k.usage in [0, 255]: self.chksum = packet[:2] del packet[:2] def decrypt_keyblob(self, passphrase): kb = super(DSAPriv, self).decrypt_keyblob(passphrase) del passphrase self.x = MPI(kb) if self.s2k.usage in [254, 255]: self.chksum = kb del kb def sign(self, sigdata, hash_alg): return self.__privkey__().sign(sigdata, hash_alg) class ElGPriv(PrivKey, ElGPub): __privfields__ = ('x', ) def __privkey__(self): raise NotImplementedError() def _compute_chksum(self): chs = sum(bytearray(self.x.to_mpibytes())) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) def _generate(self, key_size): raise NotImplementedError(PubKeyAlgorithm.ElGamal) def parse(self, packet): super(ElGPriv, self).parse(packet) self.s2k.parse(packet) if not self.s2k: self.x = MPI(packet) else: self.encbytes = packet if self.s2k.usage in [0, 255]: self.chksum = packet[:2] del packet[:2] def decrypt_keyblob(self, passphrase): kb = super(ElGPriv, self).decrypt_keyblob(passphrase) del passphrase self.x = MPI(kb) if self.s2k.usage in [254, 255]: self.chksum = kb del kb class ECDSAPriv(PrivKey, ECDSAPub): __privfields__ = ('s', ) def __privkey__(self): ecp = ec.EllipticCurvePublicNumbers(self.p.x, self.p.y, self.oid.curve()) return ec.EllipticCurvePrivateNumbers(self.s, ecp).private_key(default_backend()) def _compute_chksum(self): chs = sum(bytearray(self.s.to_mpibytes())) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) def _generate(self, oid): if any(c != 0 for c in self): # pragma: no cover raise PGPError("Key is already populated!") self.oid = EllipticCurveOID(oid) if not self.oid.can_gen: raise ValueError("Curve not currently supported: {}".format(oid.name)) pk = ec.generate_private_key(self.oid.curve(), default_backend()) pubn = pk.public_key().public_numbers() self.p = ECPoint.from_values(self.oid.key_size, ECPointFormat.Standard, MPI(pubn.x), MPI(pubn.y)) self.s = MPI(pk.private_numbers().private_value) self._compute_chksum() def parse(self, packet): super(ECDSAPriv, self).parse(packet) self.s2k.parse(packet) if not self.s2k: self.s = MPI(packet) if self.s2k.usage == 0: self.chksum = packet[:2] del packet[:2] else: ##TODO: this needs to be bounded to the length of the encrypted key material self.encbytes = packet def decrypt_keyblob(self, passphrase): kb = super(ECDSAPriv, self).decrypt_keyblob(passphrase) del passphrase self.s = MPI(kb) def sign(self, sigdata, hash_alg): return self.__privkey__().sign(sigdata, ec.ECDSA(hash_alg)) class EdDSAPriv(PrivKey, EdDSAPub): __privfields__ = ('s', ) def __privkey__(self): s = self.int_to_bytes(self.s, (self.oid.key_size + 7) // 8) return ed25519.Ed25519PrivateKey.from_private_bytes(s) def _compute_chksum(self): chs = sum(bytearray(self.s.to_mpibytes())) % 65536 self.chksum = bytearray(self.int_to_bytes(chs, 2)) def _generate(self, oid): if any(c != 0 for c in self): # pragma: no cover raise PGPError("Key is already populated!") self.oid = EllipticCurveOID(oid) if self.oid != EllipticCurveOID.Ed25519: raise ValueError("EdDSA only supported with {}".format(EllipticCurveOID.Ed25519)) pk = ed25519.Ed25519PrivateKey.generate() x = pk.public_key().public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) self.p = ECPoint.from_values(self.oid.key_size, ECPointFormat.Native, x) self.s = MPI(self.bytes_to_int(pk.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption() ))) self._compute_chksum() def parse(self, packet): super(EdDSAPriv, self).parse(packet) self.s2k.parse(packet) if not self.s2k: self.s = MPI(packet) if self.s2k.usage == 0: self.chksum = packet[:2] del packet[:2] else: ##TODO: this needs to be bounded to the length of the encrypted key material self.encbytes = packet def decrypt_keyblob(self, passphrase): kb = super(EdDSAPriv, self).decrypt_keyblob(passphrase) del passphrase self.s = MPI(kb) def sign(self, sigdata, hash_alg): # GnuPG requires a pre-hashing with EdDSA # https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-06#section-14.8 digest = hashes.Hash(hash_alg, backend=default_backend()) digest.update(sigdata) sigdata = digest.finalize() return self.__privkey__().sign(sigdata) class ECDHPriv(ECDSAPriv, ECDHPub): def __bytearray__(self): _b = ECDHPub.__bytearray__(self) _b += self.s2k.__bytearray__() if not self.s2k: _b += self.s.to_mpibytes() if self.s2k.usage == 0: _b += self.chksum else: _b += self.encbytes return _b def __len__(self): l = ECDHPub.__len__(self) + len(self.s2k) + len(self.chksum) if self.s2k: l += len(self.encbytes) else: l += sum(len(getattr(self, i)) for i in self.__privfields__) return l def __privkey__(self): if self.oid == EllipticCurveOID.Curve25519: # NOTE: openssl and GPG don't use the same endianness for Curve25519 secret value s = self.int_to_bytes(self.s, (self.oid.key_size + 7) // 8, 'little') return x25519.X25519PrivateKey.from_private_bytes(s) else: return ECDSAPriv.__privkey__(self) def _generate(self, oid): _oid = EllipticCurveOID(oid) if _oid == EllipticCurveOID.Curve25519: if any(c != 0 for c in self): # pragma: no cover raise PGPError("Key is already populated!") self.oid = _oid pk = x25519.X25519PrivateKey.generate() x = pk.public_key().public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) self.p = ECPoint.from_values(self.oid.key_size, ECPointFormat.Native, x) # NOTE: openssl and GPG don't use the same endianness for Curve25519 secret value self.s = MPI(self.bytes_to_int(pk.private_bytes( encoding=serialization.Encoding.Raw, format=serialization.PrivateFormat.Raw, encryption_algorithm=serialization.NoEncryption() ), 'little')) self._compute_chksum() else: ECDSAPriv._generate(self, oid) self.kdf.halg = self.oid.kdf_halg self.kdf.encalg = self.oid.kek_alg def publen(self): return ECDHPub.__len__(self) def parse(self, packet): ECDHPub.parse(self, packet) self.s2k.parse(packet) if not self.s2k: self.s = MPI(packet) if self.s2k.usage == 0: self.chksum = packet[:2] del packet[:2] else: ##TODO: this needs to be bounded to the length of the encrypted key material self.encbytes = packet def sign(self, sigdata, hash_alg): raise PGPError("Cannot sign with an ECDH key") class CipherText(MPIs): def __init__(self): super(CipherText, self).__init__() for i in self.__mpis__: setattr(self, i, MPI(0)) @classmethod @abc.abstractmethod def encrypt(cls, encfn, *args): """create and populate a concrete CipherText class instance""" @abc.abstractmethod def decrypt(self, decfn, *args): """decrypt the ciphertext contained in this CipherText instance""" def __bytearray__(self): _bytes = bytearray() for i in self: _bytes += i.to_mpibytes() return _bytes class RSACipherText(CipherText): __mpis__ = ('me_mod_n', ) @classmethod def encrypt(cls, encfn, *args): ct = cls() ct.me_mod_n = MPI(cls.bytes_to_int(encfn(*args))) return ct def decrypt(self, decfn, *args): return decfn(*args) def parse(self, packet): self.me_mod_n = MPI(packet) class ElGCipherText(CipherText): __mpis__ = ('gk_mod_p', 'myk_mod_p') @classmethod def encrypt(cls, encfn, *args): raise NotImplementedError() def decrypt(self, decfn, *args): raise NotImplementedError() def parse(self, packet): self.gk_mod_p = MPI(packet) self.myk_mod_p = MPI(packet) class ECDHCipherText(CipherText): __mpis__ = ('p',) @classmethod def encrypt(cls, pk, *args): """ For convenience, the synopsis of the encoding method is given below; however, this section, [NIST-SP800-56A], and [RFC3394] are the normative sources of the definition. Obtain the authenticated recipient public key R Generate an ephemeral key pair {v, V=vG} Compute the shared point S = vR; m = symm_alg_ID || session key || checksum || pkcs5_padding; curve_OID_len = (byte)len(curve_OID); Param = curve_OID_len || curve_OID || public_key_alg_ID || 03 || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous Sender " || recipient_fingerprint; Z_len = the key size for the KEK_alg_ID used with AESKeyWrap Compute Z = KDF( S, Z_len, Param ); Compute C = AESKeyWrap( Z, m ) as per [RFC3394] VB = convert point V to the octet string Output (MPI(VB) || len(C) || C). The decryption is the inverse of the method given. Note that the recipient obtains the shared secret by calculating """ # *args should be: # - m # _m, = args # m may need to be PKCS5-padded padder = PKCS7(64).padder() m = padder.update(_m) + padder.finalize() km = pk.keymaterial ct = cls() # generate ephemeral key pair and keep public key in ct # use private key to compute the shared point "s" if km.oid == EllipticCurveOID.Curve25519: v = x25519.X25519PrivateKey.generate() x = v.public_key().public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) ct.p = ECPoint.from_values(km.oid.key_size, ECPointFormat.Native, x) s = v.exchange(km.__pubkey__()) else: v = ec.generate_private_key(km.oid.curve(), default_backend()) x = MPI(v.public_key().public_numbers().x) y = MPI(v.public_key().public_numbers().y) ct.p = ECPoint.from_values(km.oid.key_size, ECPointFormat.Standard, x, y) s = v.exchange(ec.ECDH(), km.__pubkey__()) # derive the wrapping key z = km.kdf.derive_key(s, km.oid, PubKeyAlgorithm.ECDH, pk.fingerprint) # compute C ct.c = aes_key_wrap(z, m, default_backend()) return ct def decrypt(self, pk, *args): km = pk.keymaterial if km.oid == EllipticCurveOID.Curve25519: v = x25519.X25519PublicKey.from_public_bytes(self.p.x) s = km.__privkey__().exchange(v) else: # assemble the public component of ephemeral key v v = ec.EllipticCurvePublicNumbers(self.p.x, self.p.y, km.oid.curve()).public_key(default_backend()) # compute s using the inverse of how it was derived during encryption s = km.__privkey__().exchange(ec.ECDH(), v) # derive the wrapping key z = km.kdf.derive_key(s, km.oid, PubKeyAlgorithm.ECDH, pk.fingerprint) # unwrap and unpad m _m = aes_key_unwrap(z, self.c, default_backend()) padder = PKCS7(64).unpadder() return padder.update(_m) + padder.finalize() def __init__(self): super(ECDHCipherText, self).__init__() self.c = bytearray(0) def __bytearray__(self): _bytes = bytearray() _bytes += self.p.to_mpibytes() _bytes.append(len(self.c)) _bytes += self.c return _bytes def parse(self, packet): # read ephemeral public key self.p = ECPoint(packet) # read signature value clen = packet[0] del packet[0] self.c += packet[:clen] del packet[:clen] PGPy-0.5.4/pgpy/packet/packets.py000066400000000000000000001543421403641706600166110ustar00rootroot00000000000000""" packet.py """ import abc import binascii import calendar import copy import hashlib import os import re from datetime import datetime import six from cryptography.hazmat.primitives import constant_time from cryptography.hazmat.primitives.asymmetric import padding from .fields import DSAPriv, DSAPub, DSASignature from .fields import ECDSAPub, ECDSAPriv, ECDSASignature from .fields import ECDHPub, ECDHPriv, ECDHCipherText from .fields import EdDSAPub, EdDSAPriv, EdDSASignature from .fields import ElGCipherText, ElGPriv, ElGPub from .fields import OpaquePubKey from .fields import OpaquePrivKey from .fields import OpaqueSignature from .fields import RSACipherText, RSAPriv, RSAPub, RSASignature from .fields import String2Key from .fields import SubPackets from .fields import UserAttributeSubPackets from .types import Packet from .types import Primary from .types import Private from .types import Public from .types import Sub from .types import VersionedPacket from ..constants import CompressionAlgorithm from ..constants import HashAlgorithm from ..constants import PubKeyAlgorithm from ..constants import SignatureType from ..constants import SymmetricKeyAlgorithm from ..constants import TrustFlags from ..constants import TrustLevel from ..decorators import sdproperty from ..errors import PGPDecryptionError from ..symenc import _decrypt from ..symenc import _encrypt from ..types import Fingerprint __all__ = ['PKESessionKey', 'PKESessionKeyV3', 'Signature', 'SignatureV4', 'SKESessionKey', 'SKESessionKeyV4', 'OnePassSignature', 'OnePassSignatureV3', 'PrivKey', 'PubKey', 'PubKeyV4', 'PrivKeyV4', 'PrivSubKey', 'PrivSubKeyV4', 'CompressedData', 'SKEData', 'Marker', 'LiteralData', 'Trust', 'UserID', 'PubSubKey', 'PubSubKeyV4', 'UserAttribute', 'IntegrityProtectedSKEData', 'IntegrityProtectedSKEDataV1', 'MDC'] class PKESessionKey(VersionedPacket): __typeid__ = 0x01 __ver__ = 0 @abc.abstractmethod def decrypt_sk(self, pk): raise NotImplementedError() @abc.abstractmethod def encrypt_sk(self, pk, symalg, symkey): raise NotImplementedError() class PKESessionKeyV3(PKESessionKey): """ 5.1. Public-Key Encrypted Session Key Packets (Tag 1) A Public-Key Encrypted Session Key packet holds the session key used to encrypt a message. Zero or more Public-Key Encrypted Session Key packets and/or Symmetric-Key Encrypted Session Key packets may precede a Symmetrically Encrypted Data Packet, which holds an encrypted message. The message is encrypted with the session key, and the session key is itself encrypted and stored in the Encrypted Session Key packet(s). The Symmetrically Encrypted Data Packet is preceded by one Public-Key Encrypted Session Key packet for each OpenPGP key to which the message is encrypted. The recipient of the message finds a session key that is encrypted to their public key, decrypts the session key, and then uses the session key to decrypt the message. The body of this packet consists of: - A one-octet number giving the version number of the packet type. The currently defined value for packet version is 3. - An eight-octet number that gives the Key ID of the public key to which the session key is encrypted. If the session key is encrypted to a subkey, then the Key ID of this subkey is used here instead of the Key ID of the primary key. - A one-octet number giving the public-key algorithm used. - A string of octets that is the encrypted session key. This string takes up the remainder of the packet, and its contents are dependent on the public-key algorithm used. Algorithm Specific Fields for RSA encryption - multiprecision integer (MPI) of RSA encrypted value m**e mod n. Algorithm Specific Fields for Elgamal encryption: - MPI of Elgamal (Diffie-Hellman) value g**k mod p. - MPI of Elgamal (Diffie-Hellman) value m * y**k mod p. The value "m" in the above formulas is derived from the session key as follows. First, the session key is prefixed with a one-octet algorithm identifier that specifies the symmetric encryption algorithm used to encrypt the following Symmetrically Encrypted Data Packet. Then a two-octet checksum is appended, which is equal to the sum of the preceding session key octets, not including the algorithm identifier, modulo 65536. This value is then encoded as described in PKCS#1 block encoding EME-PKCS1-v1_5 in Section 7.2.1 of [RFC3447] to form the "m" value used in the formulas above. See Section 13.1 of this document for notes on OpenPGP's use of PKCS#1. Note that when an implementation forms several PKESKs with one session key, forming a message that can be decrypted by several keys, the implementation MUST make a new PKCS#1 encoding for each key. An implementation MAY accept or use a Key ID of zero as a "wild card" or "speculative" Key ID. In this case, the receiving implementation would try all available private keys, checking for a valid decrypted session key. This format helps reduce traffic analysis of messages. """ __ver__ = 3 @sdproperty def encrypter(self): return self._encrypter @encrypter.register(bytearray) def encrypter_bin(self, val): self._encrypter = binascii.hexlify(val).upper().decode('latin-1') @sdproperty def pkalg(self): return self._pkalg @pkalg.register(int) @pkalg.register(PubKeyAlgorithm) def pkalg_int(self, val): self._pkalg = PubKeyAlgorithm(val) _c = {PubKeyAlgorithm.RSAEncryptOrSign: RSACipherText, PubKeyAlgorithm.RSAEncrypt: RSACipherText, PubKeyAlgorithm.ElGamal: ElGCipherText, PubKeyAlgorithm.FormerlyElGamalEncryptOrSign: ElGCipherText, PubKeyAlgorithm.ECDH: ECDHCipherText} ct = _c.get(self._pkalg, None) self.ct = ct() if ct is not None else ct def __init__(self): super(PKESessionKeyV3, self).__init__() self.encrypter = bytearray(8) self.pkalg = 0 self.ct = None def __bytearray__(self): _bytes = bytearray() _bytes += super(PKESessionKeyV3, self).__bytearray__() _bytes += binascii.unhexlify(self.encrypter.encode()) _bytes += bytearray([self.pkalg]) _bytes += self.ct.__bytearray__() if self.ct is not None else b'\x00' * (self.header.length - 10) return _bytes def __copy__(self): sk = self.__class__() sk.header = copy.copy(self.header) sk._encrypter = self._encrypter sk.pkalg = self.pkalg if self.ct is not None: sk.ct = copy.copy(self.ct) return sk def decrypt_sk(self, pk): if self.pkalg == PubKeyAlgorithm.RSAEncryptOrSign: # pad up ct with null bytes if necessary ct = self.ct.me_mod_n.to_mpibytes()[2:] ct = b'\x00' * ((pk.keymaterial.__privkey__().key_size // 8) - len(ct)) + ct decrypter = pk.keymaterial.__privkey__().decrypt decargs = (ct, padding.PKCS1v15(),) elif self.pkalg == PubKeyAlgorithm.ECDH: decrypter = pk decargs = () else: raise NotImplementedError(self.pkalg) m = bytearray(self.ct.decrypt(decrypter, *decargs)) """ The value "m" in the above formulas is derived from the session key as follows. First, the session key is prefixed with a one-octet algorithm identifier that specifies the symmetric encryption algorithm used to encrypt the following Symmetrically Encrypted Data Packet. Then a two-octet checksum is appended, which is equal to the sum of the preceding session key octets, not including the algorithm identifier, modulo 65536. This value is then encoded as described in PKCS#1 block encoding EME-PKCS1-v1_5 in Section 7.2.1 of [RFC3447] to form the "m" value used in the formulas above. See Section 13.1 of this document for notes on OpenPGP's use of PKCS#1. """ symalg = SymmetricKeyAlgorithm(m[0]) del m[0] symkey = m[:symalg.key_size // 8] del m[:symalg.key_size // 8] checksum = self.bytes_to_int(m[:2]) del m[:2] if not sum(symkey) % 65536 == checksum: # pragma: no cover raise PGPDecryptionError("{:s} decryption failed".format(self.pkalg.name)) return (symalg, symkey) def encrypt_sk(self, pk, symalg, symkey): m = bytearray(self.int_to_bytes(symalg) + symkey) m += self.int_to_bytes(sum(bytearray(symkey)) % 65536, 2) if self.pkalg == PubKeyAlgorithm.RSAEncryptOrSign: encrypter = pk.keymaterial.__pubkey__().encrypt encargs = (bytes(m), padding.PKCS1v15(),) elif self.pkalg == PubKeyAlgorithm.ECDH: encrypter = pk encargs = (bytes(m),) else: raise NotImplementedError(self.pkalg) self.ct = self.ct.encrypt(encrypter, *encargs) self.update_hlen() def parse(self, packet): super(PKESessionKeyV3, self).parse(packet) self.encrypter = packet[:8] del packet[:8] self.pkalg = packet[0] del packet[0] if self.ct is not None: self.ct.parse(packet) else: # pragma: no cover del packet[:(self.header.length - 18)] class Signature(VersionedPacket): __typeid__ = 0x02 __ver__ = 0 class SignatureV4(Signature): """ 5.2.3. Version 4 Signature Packet Format The body of a version 4 Signature packet contains: - One-octet version number (4). - One-octet signature type. - One-octet public-key algorithm. - One-octet hash algorithm. - Two-octet scalar octet count for following hashed subpacket data. Note that this is the length in octets of all of the hashed subpackets; a pointer incremented by this number will skip over the hashed subpackets. - Hashed subpacket data set (zero or more subpackets). - Two-octet scalar octet count for the following unhashed subpacket data. Note that this is the length in octets of all of the unhashed subpackets; a pointer incremented by this number will skip over the unhashed subpackets. - Unhashed subpacket data set (zero or more subpackets). - Two-octet field holding the left 16 bits of the signed hash value. - One or more multiprecision integers comprising the signature. This portion is algorithm specific, as described above. The concatenation of the data being signed and the signature data from the version number through the hashed subpacket data (inclusive) is hashed. The resulting hash value is what is signed. The left 16 bits of the hash are included in the Signature packet to provide a quick test to reject some invalid signatures. There are two fields consisting of Signature subpackets. The first field is hashed with the rest of the signature data, while the second is unhashed. The second set of subpackets is not cryptographically protected by the signature and should include only advisory information. The algorithms for converting the hash function result to a signature are described in a section below. """ __ver__ = 4 @sdproperty def sigtype(self): return self._sigtype @sigtype.register(int) @sigtype.register(SignatureType) def sigtype_int(self, val): self._sigtype = SignatureType(val) @sdproperty def pubalg(self): return self._pubalg @pubalg.register(int) @pubalg.register(PubKeyAlgorithm) def pubalg_int(self, val): self._pubalg = PubKeyAlgorithm(val) sigs = {PubKeyAlgorithm.RSAEncryptOrSign: RSASignature, PubKeyAlgorithm.RSAEncrypt: RSASignature, PubKeyAlgorithm.RSASign: RSASignature, PubKeyAlgorithm.DSA: DSASignature, PubKeyAlgorithm.ECDSA: ECDSASignature, PubKeyAlgorithm.EdDSA: EdDSASignature,} self.signature = sigs.get(self.pubalg, OpaqueSignature)() @sdproperty def halg(self): return self._halg @halg.register(int) @halg.register(HashAlgorithm) def halg_int(self, val): try: self._halg = HashAlgorithm(val) except ValueError: # pragma: no cover self._halg = val @property def signature(self): return self._signature @signature.setter def signature(self, val): self._signature = val @property def signer(self): return self.subpackets['Issuer'][-1].issuer def __init__(self): super(Signature, self).__init__() self._sigtype = None self._pubalg = None self._halg = None self.subpackets = SubPackets() self.hash2 = bytearray(2) self.signature = None def __bytearray__(self): _bytes = bytearray() _bytes += super(Signature, self).__bytearray__() _bytes += self.int_to_bytes(self.sigtype) _bytes += self.int_to_bytes(self.pubalg) _bytes += self.int_to_bytes(self.halg) _bytes += self.subpackets.__bytearray__() _bytes += self.hash2 _bytes += self.signature.__bytearray__() return _bytes def canonical_bytes(self): '''Returns a bytearray that is the way the signature packet should be represented if it is itself being signed. from RFC 4880 section 5.2.4: When a signature is made over a Signature packet (type 0x50), the hash data starts with the octet 0x88, followed by the four-octet length of the signature, and then the body of the Signature packet. (Note that this is an old-style packet header for a Signature packet with the length-of-length set to zero.) The unhashed subpacket data of the Signature packet being hashed is not included in the hash, and the unhashed subpacket data length value is set to zero. ''' _body = bytearray() _body += self.int_to_bytes(self.header.version) _body += self.int_to_bytes(self.sigtype) _body += self.int_to_bytes(self.pubalg) _body += self.int_to_bytes(self.halg) _body += self.subpackets.__hashbytearray__() _body += self.int_to_bytes(0, minlen=2) # empty unhashed subpackets _body += self.hash2 _body += self.signature.__bytearray__() _hdr = bytearray() _hdr += b'\x88' _hdr += self.int_to_bytes(len(_body), minlen=4) return _hdr + _body def __copy__(self): spkt = SignatureV4() spkt.header = copy.copy(self.header) spkt._sigtype = self._sigtype spkt._pubalg = self._pubalg spkt._halg = self._halg spkt.subpackets = copy.copy(self.subpackets) spkt.hash2 = copy.copy(self.hash2) spkt.signature = copy.copy(self.signature) return spkt def update_hlen(self): self.subpackets.update_hlen() super(SignatureV4, self).update_hlen() def parse(self, packet): super(Signature, self).parse(packet) self.sigtype = packet[0] del packet[0] self.pubalg = packet[0] del packet[0] self.halg = packet[0] del packet[0] self.subpackets.parse(packet) self.hash2 = packet[:2] del packet[:2] self.signature.parse(packet) class SKESessionKey(VersionedPacket): __typeid__ = 0x03 __ver__ = 0 @abc.abstractmethod def decrypt_sk(self, passphrase): raise NotImplementedError() @abc.abstractmethod def encrypt_sk(self, passphrase, sk): raise NotImplementedError() class SKESessionKeyV4(SKESessionKey): """ 5.3. Symmetric-Key Encrypted Session Key Packets (Tag 3) The Symmetric-Key Encrypted Session Key packet holds the symmetric-key encryption of a session key used to encrypt a message. Zero or more Public-Key Encrypted Session Key packets and/or Symmetric-Key Encrypted Session Key packets may precede a Symmetrically Encrypted Data packet that holds an encrypted message. The message is encrypted with a session key, and the session key is itself encrypted and stored in the Encrypted Session Key packet or the Symmetric-Key Encrypted Session Key packet. If the Symmetrically Encrypted Data packet is preceded by one or more Symmetric-Key Encrypted Session Key packets, each specifies a passphrase that may be used to decrypt the message. This allows a message to be encrypted to a number of public keys, and also to one or more passphrases. This packet type is new and is not generated by PGP 2.x or PGP 5.0. The body of this packet consists of: - A one-octet version number. The only currently defined version is 4. - A one-octet number describing the symmetric algorithm used. - A string-to-key (S2K) specifier, length as defined above. - Optionally, the encrypted session key itself, which is decrypted with the string-to-key object. If the encrypted session key is not present (which can be detected on the basis of packet length and S2K specifier size), then the S2K algorithm applied to the passphrase produces the session key for decrypting the file, using the symmetric cipher algorithm from the Symmetric-Key Encrypted Session Key packet. If the encrypted session key is present, the result of applying the S2K algorithm to the passphrase is used to decrypt just that encrypted session key field, using CFB mode with an IV of all zeros. The decryption result consists of a one-octet algorithm identifier that specifies the symmetric-key encryption algorithm used to encrypt the following Symmetrically Encrypted Data packet, followed by the session key octets themselves. Note: because an all-zero IV is used for this decryption, the S2K specifier MUST use a salt value, either a Salted S2K or an Iterated-Salted S2K. The salt value will ensure that the decryption key is not repeated even if the passphrase is reused. """ __ver__ = 4 @property def symalg(self): return self.s2k.encalg def __init__(self): super(SKESessionKeyV4, self).__init__() self.s2k = String2Key() self.ct = bytearray() def __bytearray__(self): _bytes = bytearray() _bytes += super(SKESessionKeyV4, self).__bytearray__() _bytes += self.s2k.__bytearray__()[1:] _bytes += self.ct return _bytes def __copy__(self): sk = self.__class__() sk.header = copy.copy(self.header) sk.s2k = copy.copy(self.s2k) sk.ct = self.ct[:] return sk def parse(self, packet): super(SKESessionKeyV4, self).parse(packet) # prepend a valid usage identifier so this parses correctly packet.insert(0, 255) self.s2k.parse(packet, iv=False) ctend = self.header.length - len(self.s2k) self.ct = packet[:ctend] del packet[:ctend] def decrypt_sk(self, passphrase): # derive the first session key from our passphrase sk = self.s2k.derive_key(passphrase) del passphrase # if there is no ciphertext, then the first session key is the session key being used if len(self.ct) == 0: return self.symalg, sk # otherwise, we now need to decrypt the encrypted session key m = bytearray(_decrypt(bytes(self.ct), sk, self.symalg)) del sk symalg = SymmetricKeyAlgorithm(m[0]) del m[0] return symalg, bytes(m) def encrypt_sk(self, passphrase, sk): # generate the salt and derive the key to encrypt sk with from it self.s2k.salt = bytearray(os.urandom(8)) esk = self.s2k.derive_key(passphrase) del passphrase self.ct = _encrypt(self.int_to_bytes(self.symalg) + sk, esk, self.symalg) # update header length and return sk self.update_hlen() class OnePassSignature(VersionedPacket): __typeid__ = 0x04 __ver__ = 0 class OnePassSignatureV3(OnePassSignature): """ 5.4. One-Pass Signature Packets (Tag 4) The One-Pass Signature packet precedes the signed data and contains enough information to allow the receiver to begin calculating any hashes needed to verify the signature. It allows the Signature packet to be placed at the end of the message, so that the signer can compute the entire signed message in one pass. A One-Pass Signature does not interoperate with PGP 2.6.x or earlier. The body of this packet consists of: - A one-octet version number. The current version is 3. - A one-octet signature type. Signature types are described in Section 5.2.1. - A one-octet number describing the hash algorithm used. - A one-octet number describing the public-key algorithm used. - An eight-octet number holding the Key ID of the signing key. - A one-octet number holding a flag showing whether the signature is nested. A zero value indicates that the next packet is another One-Pass Signature packet that describes another signature to be applied to the same message data. Note that if a message contains more than one one-pass signature, then the Signature packets bracket the message; that is, the first Signature packet after the message corresponds to the last one-pass packet and the final Signature packet corresponds to the first one-pass packet. """ __ver__ = 3 @sdproperty def sigtype(self): return self._sigtype @sigtype.register(int) @sigtype.register(SignatureType) def sigtype_int(self, val): self._sigtype = SignatureType(val) @sdproperty def pubalg(self): return self._pubalg @pubalg.register(int) @pubalg.register(PubKeyAlgorithm) def pubalg_int(self, val): self._pubalg = PubKeyAlgorithm(val) if self._pubalg in [PubKeyAlgorithm.RSAEncryptOrSign, PubKeyAlgorithm.RSAEncrypt, PubKeyAlgorithm.RSASign]: self.signature = RSASignature() elif self._pubalg == PubKeyAlgorithm.DSA: self.signature = DSASignature() @sdproperty def halg(self): return self._halg @halg.register(int) @halg.register(HashAlgorithm) def halg_int(self, val): try: self._halg = HashAlgorithm(val) except ValueError: # pragma: no cover self._halg = val @sdproperty def signer(self): return self._signer @signer.register(str) @signer.register(six.text_type) def signer_str(self, val): self._signer = val @signer.register(bytearray) def signer_bin(self, val): self._signer = binascii.hexlify(val).upper().decode('latin-1') def __init__(self): super(OnePassSignatureV3, self).__init__() self._sigtype = None self._halg = None self._pubalg = None self._signer = b'\x00' * 8 self.nested = False def __bytearray__(self): _bytes = bytearray() _bytes += super(OnePassSignatureV3, self).__bytearray__() _bytes += bytearray([self.sigtype]) _bytes += bytearray([self.halg]) _bytes += bytearray([self.pubalg]) _bytes += binascii.unhexlify(six.b(self.signer)) _bytes += bytearray([int(self.nested)]) return _bytes def parse(self, packet): super(OnePassSignatureV3, self).parse(packet) self.sigtype = packet[0] del packet[0] self.halg = packet[0] del packet[0] self.pubalg = packet[0] del packet[0] self.signer = packet[:8] del packet[:8] self.nested = (packet[0] == 1) del packet[0] class PrivKey(VersionedPacket, Primary, Private): __typeid__ = 0x05 __ver__ = 0 class PubKey(VersionedPacket, Primary, Public): __typeid__ = 0x06 __ver__ = 0 @abc.abstractproperty def fingerprint(self): """compute and return the fingerprint of the key""" class PubKeyV4(PubKey): __ver__ = 4 @sdproperty def created(self): return self._created @created.register(datetime) def created_datetime(self, val): self._created = val @created.register(int) def created_int(self, val): self.created = datetime.utcfromtimestamp(val) @created.register(bytes) @created.register(bytearray) def created_bin(self, val): self.created = self.bytes_to_int(val) @sdproperty def pkalg(self): return self._pkalg @pkalg.register(int) @pkalg.register(PubKeyAlgorithm) def pkalg_int(self, val): self._pkalg = PubKeyAlgorithm(val) _c = { # True means public (True, PubKeyAlgorithm.RSAEncryptOrSign): RSAPub, (True, PubKeyAlgorithm.RSAEncrypt): RSAPub, (True, PubKeyAlgorithm.RSASign): RSAPub, (True, PubKeyAlgorithm.DSA): DSAPub, (True, PubKeyAlgorithm.ElGamal): ElGPub, (True, PubKeyAlgorithm.FormerlyElGamalEncryptOrSign): ElGPub, (True, PubKeyAlgorithm.ECDSA): ECDSAPub, (True, PubKeyAlgorithm.ECDH): ECDHPub, (True, PubKeyAlgorithm.EdDSA): EdDSAPub, # False means private (False, PubKeyAlgorithm.RSAEncryptOrSign): RSAPriv, (False, PubKeyAlgorithm.RSAEncrypt): RSAPriv, (False, PubKeyAlgorithm.RSASign): RSAPriv, (False, PubKeyAlgorithm.DSA): DSAPriv, (False, PubKeyAlgorithm.ElGamal): ElGPriv, (False, PubKeyAlgorithm.FormerlyElGamalEncryptOrSign): ElGPriv, (False, PubKeyAlgorithm.ECDSA): ECDSAPriv, (False, PubKeyAlgorithm.ECDH): ECDHPriv, (False, PubKeyAlgorithm.EdDSA): EdDSAPriv, } k = (self.public, self.pkalg) km = _c.get(k, None) self.keymaterial = (km or (OpaquePubKey if self.public else OpaquePrivKey))() # km = _c.get(k, None) # self.keymaterial = km() if km is not None else km @property def public(self): return isinstance(self, PubKey) and not isinstance(self, PrivKey) @property def fingerprint(self): # A V4 fingerprint is the 160-bit SHA-1 hash of the octet 0x99, followed by the two-octet packet length, # followed by the entire Public-Key packet starting with the version field. The Key ID is the # low-order 64 bits of the fingerprint. fp = hashlib.new('sha1') plen = self.keymaterial.publen() bcde_len = self.int_to_bytes(6 + plen, 2) # a.1) 0x99 (1 octet) # a.2) high-order length octet # a.3) low-order length octet fp.update(b'\x99' + bcde_len[:1] + bcde_len[-1:]) # b) version number = 4 (1 octet); fp.update(b'\x04') # c) timestamp of key creation (4 octets); fp.update(self.int_to_bytes(calendar.timegm(self.created.timetuple()), 4)) # d) algorithm (1 octet): 17 = DSA (example); fp.update(self.int_to_bytes(self.pkalg)) # e) Algorithm-specific fields. fp.update(self.keymaterial.__bytearray__()[:plen]) # and return the digest return Fingerprint(fp.hexdigest().upper()) def __init__(self): super(PubKeyV4, self).__init__() self.created = datetime.utcnow() self.pkalg = 0 self.keymaterial = None def __bytearray__(self): _bytes = bytearray() _bytes += super(PubKeyV4, self).__bytearray__() _bytes += self.int_to_bytes(calendar.timegm(self.created.timetuple()), 4) _bytes += self.int_to_bytes(self.pkalg) _bytes += self.keymaterial.__bytearray__() return _bytes def __copy__(self): pk = self.__class__() pk.header = copy.copy(self.header) pk.created = self.created pk.pkalg = self.pkalg pk.keymaterial = copy.copy(self.keymaterial) return pk def verify(self, subj, sigbytes, hash_alg): return self.keymaterial.verify(subj, sigbytes, hash_alg) def parse(self, packet): super(PubKeyV4, self).parse(packet) self.created = packet[:4] del packet[:4] self.pkalg = packet[0] del packet[0] # bound keymaterial to the remaining length of the packet pend = self.header.length - 6 self.keymaterial.parse(packet[:pend]) del packet[:pend] class PrivKeyV4(PrivKey, PubKeyV4): __ver__ = 4 @classmethod def new(cls, key_algorithm, key_size, created=None): # build a key packet pk = PrivKeyV4() pk.pkalg = key_algorithm if pk.keymaterial is None: raise NotImplementedError(key_algorithm) pk.keymaterial._generate(key_size) if created is not None: pk.created = created pk.update_hlen() return pk def pubkey(self): # return a copy of ourselves, but just the public half pk = PubKeyV4() if not isinstance(self, PrivSubKeyV4) else PubSubKeyV4() pk.created = self.created pk.pkalg = self.pkalg # copy over MPIs for pm in self.keymaterial.__pubfields__: setattr(pk.keymaterial, pm, copy.copy(getattr(self.keymaterial, pm))) if self.pkalg in {PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.EdDSA}: pk.keymaterial.oid = self.keymaterial.oid if self.pkalg == PubKeyAlgorithm.ECDH: pk.keymaterial.oid = self.keymaterial.oid pk.keymaterial.kdf = copy.copy(self.keymaterial.kdf) pk.update_hlen() return pk @property def protected(self): return bool(self.keymaterial.s2k) @property def unlocked(self): if self.protected: return 0 not in list(self.keymaterial) return True # pragma: no cover def protect(self, passphrase, enc_alg, hash_alg): self.keymaterial.encrypt_keyblob(passphrase, enc_alg, hash_alg) del passphrase self.update_hlen() def unprotect(self, passphrase): self.keymaterial.decrypt_keyblob(passphrase) del passphrase def sign(self, sigdata, hash_alg): return self.keymaterial.sign(sigdata, hash_alg) class PrivSubKey(VersionedPacket, Sub, Private): __typeid__ = 0x07 __ver__ = 0 class PrivSubKeyV4(PrivSubKey, PrivKeyV4): __ver__ = 4 class CompressedData(Packet): """ 5.6. Compressed Data Packet (Tag 8) The Compressed Data packet contains compressed data. Typically, this packet is found as the contents of an encrypted packet, or following a Signature or One-Pass Signature packet, and contains a literal data packet. The body of this packet consists of: - One octet that gives the algorithm used to compress the packet. - Compressed data, which makes up the remainder of the packet. A Compressed Data Packet's body contains an block that compresses some set of packets. See section "Packet Composition" for details on how messages are formed. ZIP-compressed packets are compressed with raw RFC 1951 [RFC1951] DEFLATE blocks. Note that PGP V2.6 uses 13 bits of compression. If an implementation uses more bits of compression, PGP V2.6 cannot decompress it. ZLIB-compressed packets are compressed with RFC 1950 [RFC1950] ZLIB- style blocks. BZip2-compressed packets are compressed using the BZip2 [BZ2] algorithm. """ __typeid__ = 0x08 @sdproperty def calg(self): return self._calg @calg.register(int) @calg.register(CompressionAlgorithm) def calg_int(self, val): self._calg = CompressionAlgorithm(val) def __init__(self): super(CompressedData, self).__init__() self._calg = None self.packets = [] def __bytearray__(self): _bytes = bytearray() _bytes += super(CompressedData, self).__bytearray__() _bytes += bytearray([self.calg]) _pb = bytearray() for pkt in self.packets: _pb += pkt.__bytearray__() _bytes += self.calg.compress(bytes(_pb)) return _bytes def parse(self, packet): super(CompressedData, self).parse(packet) self.calg = packet[0] del packet[0] cdata = bytearray(self.calg.decompress(packet[:self.header.length - 1])) del packet[:self.header.length - 1] while len(cdata) > 0: self.packets.append(Packet(cdata)) class SKEData(Packet): """ 5.7. Symmetrically Encrypted Data Packet (Tag 9) The Symmetrically Encrypted Data packet contains data encrypted with a symmetric-key algorithm. When it has been decrypted, it contains other packets (usually a literal data packet or compressed data packet, but in theory other Symmetrically Encrypted Data packets or sequences of packets that form whole OpenPGP messages). The body of this packet consists of: - Encrypted data, the output of the selected symmetric-key cipher operating in OpenPGP's variant of Cipher Feedback (CFB) mode. The symmetric cipher used may be specified in a Public-Key or Symmetric-Key Encrypted Session Key packet that precedes the Symmetrically Encrypted Data packet. In that case, the cipher algorithm octet is prefixed to the session key before it is encrypted. If no packets of these types precede the encrypted data, the IDEA algorithm is used with the session key calculated as the MD5 hash of the passphrase, though this use is deprecated. The data is encrypted in CFB mode, with a CFB shift size equal to the cipher's block size. The Initial Vector (IV) is specified as all zeros. Instead of using an IV, OpenPGP prefixes a string of length equal to the block size of the cipher plus two to the data before it is encrypted. The first block-size octets (for example, 8 octets for a 64-bit block length) are random, and the following two octets are copies of the last two octets of the IV. For example, in an 8-octet block, octet 9 is a repeat of octet 7, and octet 10 is a repeat of octet 8. In a cipher of length 16, octet 17 is a repeat of octet 15 and octet 18 is a repeat of octet 16. As a pedantic clarification, in both these examples, we consider the first octet to be numbered 1. After encrypting the first block-size-plus-two octets, the CFB state is resynchronized. The last block-size octets of ciphertext are passed through the cipher and the block boundary is reset. The repetition of 16 bits in the random data prefixed to the message allows the receiver to immediately check whether the session key is incorrect. See the "Security Considerations" section for hints on the proper use of this "quick check". """ __typeid__ = 0x09 def __init__(self): super(SKEData, self).__init__() self.ct = bytearray() def __bytearray__(self): _bytes = bytearray() _bytes += super(SKEData, self).__bytearray__() _bytes += self.ct return _bytes def __copy__(self): skd = self.__class__() skd.ct = self.ct[:] return skd def parse(self, packet): super(SKEData, self).parse(packet) self.ct = packet[:self.header.length] del packet[:self.header.length] def decrypt(self, key, alg): # pragma: no cover block_size_bytes = alg.block_size // 8 pt_prefix = _decrypt(bytes(self.ct[:block_size_bytes + 2]), bytes(key), alg) # old Symmetrically Encrypted Data Packet required # to change iv after decrypting prefix iv_resync = bytes(self.ct[2:block_size_bytes + 2]) iv = bytes(pt_prefix[:block_size_bytes]) del pt_prefix[:block_size_bytes] ivl2 = bytes(pt_prefix[:2]) if not constant_time.bytes_eq(iv[-2:], ivl2): raise PGPDecryptionError("Decryption failed") pt = _decrypt(bytes(self.ct[block_size_bytes + 2:]), bytes(key), alg, iv=iv_resync) return pt class Marker(Packet): __typeid__ = 0x0a def __init__(self): super(Marker, self).__init__() self.data = b'PGP' def __bytearray__(self): _bytes = bytearray() _bytes += super(Marker, self).__bytearray__() _bytes += self.data return _bytes def parse(self, packet): super(Marker, self).parse(packet) self.data = packet[:self.header.length] del packet[:self.header.length] class LiteralData(Packet): """ 5.9. Literal Data Packet (Tag 11) A Literal Data packet contains the body of a message; data that is not to be further interpreted. The body of this packet consists of: - A one-octet field that describes how the data is formatted. If it is a 'b' (0x62), then the Literal packet contains binary data. If it is a 't' (0x74), then it contains text data, and thus may need line ends converted to local form, or other text-mode changes. The tag 'u' (0x75) means the same as 't', but also indicates that implementation believes that the literal data contains UTF-8 text. Early versions of PGP also defined a value of 'l' as a 'local' mode for machine-local conversions. RFC 1991 [RFC1991] incorrectly stated this local mode flag as '1' (ASCII numeral one). Both of these local modes are deprecated. - File name as a string (one-octet length, followed by a file name). This may be a zero-length string. Commonly, if the source of the encrypted data is a file, this will be the name of the encrypted file. An implementation MAY consider the file name in the Literal packet to be a more authoritative name than the actual file name. If the special name "_CONSOLE" is used, the message is considered to be "for your eyes only". This advises that the message data is unusually sensitive, and the receiving program should process it more carefully, perhaps avoiding storing the received data to disk, for example. - A four-octet number that indicates a date associated with the literal data. Commonly, the date might be the modification date of a file, or the time the packet was created, or a zero that indicates no specific time. - The remainder of the packet is literal data. Text data is stored with text endings (i.e., network- normal line endings). These should be converted to native line endings by the receiving software. """ __typeid__ = 0x0B @sdproperty def mtime(self): return self._mtime @mtime.register(datetime) def mtime_datetime(self, val): self._mtime = val @mtime.register(int) def mtime_int(self, val): self.mtime = datetime.utcfromtimestamp(val) @mtime.register(bytes) @mtime.register(bytearray) def mtime_bin(self, val): self.mtime = self.bytes_to_int(val) @property def contents(self): if self.format == 't': return self._contents.decode('latin-1') if self.format == 'u': return self._contents.decode('utf-8') return self._contents def __init__(self): super(LiteralData, self).__init__() self.format = 'b' self.filename = '' self.mtime = datetime.utcnow() self._contents = bytearray() def __bytearray__(self): _bytes = bytearray() _bytes += super(LiteralData, self).__bytearray__() _bytes += self.format.encode('latin-1') _bytes += bytearray([len(self.filename)]) _bytes += self.filename.encode('latin-1') _bytes += self.int_to_bytes(calendar.timegm(self.mtime.timetuple()), 4) _bytes += self._contents return _bytes def __copy__(self): pkt = LiteralData() pkt.header = copy.copy(self.header) pkt.format = self.format pkt.filename = self.filename pkt.mtime = self.mtime pkt._contents = self._contents[:] return pkt def parse(self, packet): super(LiteralData, self).parse(packet) self.format = chr(packet[0]) del packet[0] fnl = packet[0] del packet[0] self.filename = packet[:fnl].decode() del packet[:fnl] self.mtime = packet[:4] del packet[:4] self._contents = packet[:self.header.length - (6 + fnl)] del packet[:self.header.length - (6 + fnl)] class Trust(Packet): """ 5.10. Trust Packet (Tag 12) The Trust packet is used only within keyrings and is not normally exported. Trust packets contain data that record the user's specifications of which key holders are trustworthy introducers, along with other information that implementing software uses for trust information. The format of Trust packets is defined by a given implementation. Trust packets SHOULD NOT be emitted to output streams that are transferred to other users, and they SHOULD be ignored on any input other than local keyring files. """ __typeid__ = 0x0C @sdproperty def trustlevel(self): return self._trustlevel @trustlevel.register(int) @trustlevel.register(TrustLevel) def trustlevel_int(self, val): self._trustlevel = TrustLevel(val & 0x0F) @sdproperty def trustflags(self): return self._trustflags @trustflags.register(list) def trustflags_list(self, val): self._trustflags = val @trustflags.register(int) def trustflags_int(self, val): self._trustflags = TrustFlags & val def __init__(self): super(Trust, self).__init__() self.trustlevel = TrustLevel.Unknown self.trustflags = [] def __bytearray__(self): _bytes = bytearray() _bytes += super(Trust, self).__bytearray__() _bytes += self.int_to_bytes(self.trustlevel + sum(self.trustflags), 2) return _bytes def parse(self, packet): super(Trust, self).parse(packet) # self.trustlevel = packet[0] & 0x1f t = self.bytes_to_int(packet[:2]) del packet[:2] self.trustlevel = t self.trustflags = t class UserID(Packet): """ 5.11. User ID Packet (Tag 13) A User ID packet consists of UTF-8 text that is intended to represent the name and email address of the key holder. By convention, it includes an RFC 2822 [RFC2822] mail name-addr, but there are no restrictions on its content. The packet length in the header specifies the length of the User ID. """ __typeid__ = 0x0D def __init__(self, uid=""): super(UserID, self).__init__() self.uid = uid self._encoding_fallback = False def __bytearray__(self): _bytes = bytearray() _bytes += super(UserID, self).__bytearray__() textenc = 'utf-8' if not self._encoding_fallback else 'charmap' _bytes += self.uid.encode(textenc) return _bytes def __copy__(self): uid = UserID() uid.header = copy.copy(self.header) uid.uid = self.uid return uid def parse(self, packet): super(UserID, self).parse(packet) uid_bytes = packet[:self.header.length] # uid_text = packet[:self.header.length].decode('utf-8') del packet[:self.header.length] try: self.uid = uid_bytes.decode('utf-8') except UnicodeDecodeError: self.uid = uid_bytes.decode('charmap') self._encoding_fallback = True class PubSubKey(VersionedPacket, Sub, Public): __typeid__ = 0x0E __ver__ = 0 class PubSubKeyV4(PubSubKey, PubKeyV4): __ver__ = 4 class UserAttribute(Packet): """ 5.12. User Attribute Packet (Tag 17) The User Attribute packet is a variation of the User ID packet. It is capable of storing more types of data than the User ID packet, which is limited to text. Like the User ID packet, a User Attribute packet may be certified by the key owner ("self-signed") or any other key owner who cares to certify it. Except as noted, a User Attribute packet may be used anywhere that a User ID packet may be used. While User Attribute packets are not a required part of the OpenPGP standard, implementations SHOULD provide at least enough compatibility to properly handle a certification signature on the User Attribute packet. A simple way to do this is by treating the User Attribute packet as a User ID packet with opaque contents, but an implementation may use any method desired. The User Attribute packet is made up of one or more attribute subpackets. Each subpacket consists of a subpacket header and a body. The header consists of: - the subpacket length (1, 2, or 5 octets) - the subpacket type (1 octet) and is followed by the subpacket specific data. The only currently defined subpacket type is 1, signifying an image. An implementation SHOULD ignore any subpacket of a type that it does not recognize. Subpacket types 100 through 110 are reserved for private or experimental use. """ __typeid__ = 0x11 @property def image(self): if 'Image' not in self.subpackets: self.subpackets.addnew('Image') return next(iter(self.subpackets['Image'])) def __init__(self): super(UserAttribute, self).__init__() self.subpackets = UserAttributeSubPackets() def __bytearray__(self): _bytes = bytearray() _bytes += super(UserAttribute, self).__bytearray__() _bytes += self.subpackets.__bytearray__() return _bytes def parse(self, packet): super(UserAttribute, self).parse(packet) plen = len(packet) while self.header.length > (plen - len(packet)): self.subpackets.parse(packet) def update_hlen(self): self.subpackets.update_hlen() super(UserAttribute, self).update_hlen() class IntegrityProtectedSKEData(VersionedPacket): __typeid__ = 0x12 __ver__ = 0 class IntegrityProtectedSKEDataV1(IntegrityProtectedSKEData): """ 5.13. Sym. Encrypted Integrity Protected Data Packet (Tag 18) The Symmetrically Encrypted Integrity Protected Data packet is a variant of the Symmetrically Encrypted Data packet. It is a new feature created for OpenPGP that addresses the problem of detecting a modification to encrypted data. It is used in combination with a Modification Detection Code packet. There is a corresponding feature in the features Signature subpacket that denotes that an implementation can properly use this packet type. An implementation MUST support decrypting these packets and SHOULD prefer generating them to the older Symmetrically Encrypted Data packet when possible. Since this data packet protects against modification attacks, this standard encourages its proliferation. While blanket adoption of this data packet would create interoperability problems, rapid adoption is nevertheless important. An implementation SHOULD specifically denote support for this packet, but it MAY infer it from other mechanisms. For example, an implementation might infer from the use of a cipher such as Advanced Encryption Standard (AES) or Twofish that a user supports this feature. It might place in the unhashed portion of another user's key signature a Features subpacket. It might also present a user with an opportunity to regenerate their own self- signature with a Features subpacket. This packet contains data encrypted with a symmetric-key algorithm and protected against modification by the SHA-1 hash algorithm. When it has been decrypted, it will typically contain other packets (often a Literal Data packet or Compressed Data packet). The last decrypted packet in this packet's payload MUST be a Modification Detection Code packet. The body of this packet consists of: - A one-octet version number. The only currently defined value is 1. - Encrypted data, the output of the selected symmetric-key cipher operating in Cipher Feedback mode with shift amount equal to the block size of the cipher (CFB-n where n is the block size). The symmetric cipher used MUST be specified in a Public-Key or Symmetric-Key Encrypted Session Key packet that precedes the Symmetrically Encrypted Data packet. In either case, the cipher algorithm octet is prefixed to the session key before it is encrypted. The data is encrypted in CFB mode, with a CFB shift size equal to the cipher's block size. The Initial Vector (IV) is specified as all zeros. Instead of using an IV, OpenPGP prefixes an octet string to the data before it is encrypted. The length of the octet string equals the block size of the cipher in octets, plus two. The first octets in the group, of length equal to the block size of the cipher, are random; the last two octets are each copies of their 2nd preceding octet. For example, with a cipher whose block size is 128 bits or 16 octets, the prefix data will contain 16 random octets, then two more octets, which are copies of the 15th and 16th octets, respectively. Unlike the Symmetrically Encrypted Data Packet, no special CFB resynchronization is done after encrypting this prefix data. See "OpenPGP CFB Mode" below for more details. The repetition of 16 bits in the random data prefixed to the message allows the receiver to immediately check whether the session key is incorrect. The plaintext of the data to be encrypted is passed through the SHA-1 hash function, and the result of the hash is appended to the plaintext in a Modification Detection Code packet. The input to the hash function includes the prefix data described above; it includes all of the plaintext, and then also includes two octets of values 0xD3, 0x14. These represent the encoding of a Modification Detection Code packet tag and length field of 20 octets. The resulting hash value is stored in a Modification Detection Code (MDC) packet, which MUST use the two octet encoding just given to represent its tag and length field. The body of the MDC packet is the 20-octet output of the SHA-1 hash. The Modification Detection Code packet is appended to the plaintext and encrypted along with the plaintext using the same CFB context. During decryption, the plaintext data should be hashed with SHA-1, including the prefix data as well as the packet tag and length field of the Modification Detection Code packet. The body of the MDC packet, upon decryption, is compared with the result of the SHA-1 hash. Any failure of the MDC indicates that the message has been modified and MUST be treated as a security problem. Failures include a difference in the hash values, but also the absence of an MDC packet, or an MDC packet in any position other than the end of the plaintext. Any failure SHOULD be reported to the user. Note: future designs of new versions of this packet should consider rollback attacks since it will be possible for an attacker to change the version back to 1. """ __ver__ = 1 def __init__(self): super(IntegrityProtectedSKEDataV1, self).__init__() self.ct = bytearray() def __bytearray__(self): _bytes = bytearray() _bytes += super(IntegrityProtectedSKEDataV1, self).__bytearray__() _bytes += self.ct return _bytes def __copy__(self): skd = self.__class__() skd.ct = self.ct[:] return skd def parse(self, packet): super(IntegrityProtectedSKEDataV1, self).parse(packet) self.ct = packet[:self.header.length - 1] del packet[:self.header.length - 1] def encrypt(self, key, alg, data): iv = alg.gen_iv() data = iv + iv[-2:] + data mdc = MDC() mdc.mdc = binascii.hexlify(hashlib.new('SHA1', data + b'\xd3\x14').digest()) mdc.update_hlen() data += mdc.__bytes__() self.ct = _encrypt(data, key, alg) self.update_hlen() def decrypt(self, key, alg): # iv, ivl2, pt = super(IntegrityProtectedSKEDataV1, self).decrypt(key, alg) pt = _decrypt(bytes(self.ct), bytes(key), alg) # do the MDC checks _expected_mdcbytes = b'\xd3\x14' + hashlib.new('SHA1', pt[:-20]).digest() if not constant_time.bytes_eq(bytes(pt[-22:]), _expected_mdcbytes): raise PGPDecryptionError("Decryption failed") # pragma: no cover iv = bytes(pt[:alg.block_size // 8]) del pt[:alg.block_size // 8] ivl2 = bytes(pt[:2]) del pt[:2] if not constant_time.bytes_eq(iv[-2:], ivl2): raise PGPDecryptionError("Decryption failed") # pragma: no cover return pt class MDC(Packet): """ 5.14. Modification Detection Code Packet (Tag 19) The Modification Detection Code packet contains a SHA-1 hash of plaintext data, which is used to detect message modification. It is only used with a Symmetrically Encrypted Integrity Protected Data packet. The Modification Detection Code packet MUST be the last packet in the plaintext data that is encrypted in the Symmetrically Encrypted Integrity Protected Data packet, and MUST appear in no other place. A Modification Detection Code packet MUST have a length of 20 octets. The body of this packet consists of: - A 20-octet SHA-1 hash of the preceding plaintext data of the Symmetrically Encrypted Integrity Protected Data packet, including prefix data, the tag octet, and length octet of the Modification Detection Code packet. Note that the Modification Detection Code packet MUST always use a new format encoding of the packet tag, and a one-octet encoding of the packet length. The reason for this is that the hashing rules for modification detection include a one-octet tag and one-octet length in the data hash. While this is a bit restrictive, it reduces complexity. """ __typeid__ = 0x13 def __init__(self): super(MDC, self).__init__() self.mdc = '' def __bytearray__(self): return super(MDC, self).__bytearray__() + binascii.unhexlify(self.mdc) def parse(self, packet): super(MDC, self).parse(packet) self.mdc = binascii.hexlify(packet[:20]) del packet[:20] PGPy-0.5.4/pgpy/packet/subpackets/000077500000000000000000000000001403641706600167405ustar00rootroot00000000000000PGPy-0.5.4/pgpy/packet/subpackets/__init__.py000066400000000000000000000003151403641706600210500ustar00rootroot00000000000000from .types import Signature as Signature from .types import UserAttribute as UserAttribute from .signature import * # NOQA from .userattribute import * # NOQA __all__ = ['Signature', 'UserAttribute'] PGPy-0.5.4/pgpy/packet/subpackets/signature.py000066400000000000000000001026271403641706600213230ustar00rootroot00000000000000""" signature.py Signature SubPackets """ import binascii import calendar from datetime import datetime from datetime import timedelta import six from .types import EmbeddedSignatureHeader from .types import Signature from ...constants import CompressionAlgorithm from ...constants import Features as _Features from ...constants import HashAlgorithm from ...constants import KeyFlags as _KeyFlags from ...constants import KeyServerPreferences as _KeyServerPreferences from ...constants import NotationDataFlags from ...constants import PubKeyAlgorithm from ...constants import RevocationKeyClass from ...constants import RevocationReason from ...constants import SymmetricKeyAlgorithm from ...decorators import sdproperty from ...types import Fingerprint __all__ = ['URI', 'FlagList', 'ByteFlag', 'Boolean', 'CreationTime', 'SignatureExpirationTime', 'ExportableCertification', 'TrustSignature', 'RegularExpression', 'Revocable', 'KeyExpirationTime', 'PreferredSymmetricAlgorithms', 'RevocationKey', 'Issuer', 'NotationData', 'PreferredHashAlgorithms', 'PreferredCompressionAlgorithms', 'KeyServerPreferences', 'PreferredKeyServer', 'PrimaryUserID', 'Policy', 'KeyFlags', 'SignersUserID', 'ReasonForRevocation', 'Features', 'EmbeddedSignature', 'IssuerFingerprint', 'IntendedRecipient', 'AttestedCertifications'] class URI(Signature): @sdproperty def uri(self): return self._uri @uri.register(str) @uri.register(six.text_type) def uri_str(self, val): self._uri = val @uri.register(bytearray) def uri_bytearray(self, val): self.uri = val.decode('latin-1') def __init__(self): super(URI, self).__init__() self.uri = "" def __bytearray__(self): _bytes = super(URI, self).__bytearray__() _bytes += self.uri.encode() return _bytes def parse(self, packet): super(URI, self).parse(packet) self.uri = packet[:(self.header.length - 1)] del packet[:(self.header.length - 1)] class FlagList(Signature): __flags__ = None @sdproperty def flags(self): return self._flags @flags.register(list) @flags.register(tuple) def flags_list(self, val): self._flags = list(val) @flags.register(int) @flags.register(CompressionAlgorithm) @flags.register(HashAlgorithm) @flags.register(PubKeyAlgorithm) @flags.register(SymmetricKeyAlgorithm) def flags_int(self, val): if self.__flags__ is None: # pragma: no cover raise AttributeError("Error: __flags__ not set!") self._flags.append(self.__flags__(val)) @flags.register(bytearray) def flags_bytearray(self, val): self.flags = self.bytes_to_int(val) def __init__(self): super(FlagList, self).__init__() self.flags = [] def __bytearray__(self): _bytes = super(FlagList, self).__bytearray__() _bytes += b''.join(self.int_to_bytes(b) for b in self.flags) return _bytes def parse(self, packet): super(FlagList, self).parse(packet) for i in range(0, self.header.length - 1): self.flags = packet[:1] del packet[:1] class ByteFlag(Signature): __flags__ = None @sdproperty def flags(self): return self._flags @flags.register(set) @flags.register(list) def flags_seq(self, val): self._flags = set(val) @flags.register(int) @flags.register(_KeyFlags) @flags.register(_Features) def flags_int(self, val): if self.__flags__ is None: # pragma: no cover raise AttributeError("Error: __flags__ not set!") self._flags |= (self.__flags__ & val) @flags.register(bytearray) def flags_bytearray(self, val): self.flags = self.bytes_to_int(val) def __init__(self): super(ByteFlag, self).__init__() self.flags = [] def __bytearray__(self): _bytes = super(ByteFlag, self).__bytearray__() _bytes += self.int_to_bytes(sum(self.flags)) # null-pad _bytes if they are not up to the end now if len(_bytes) < len(self): _bytes += b'\x00' * (len(self) - len(_bytes)) return _bytes def parse(self, packet): super(ByteFlag, self).parse(packet) for i in range(0, self.header.length - 1): self.flags = packet[:1] del packet[:1] class Boolean(Signature): @sdproperty def bflag(self): return self._bool @bflag.register(bool) def bflag_bool(self, val): self._bool = val @bflag.register(bytearray) def bflag_bytearray(self, val): self.bool = bool(self.bytes_to_int(val)) def __init__(self): super(Boolean, self).__init__() self.bflag = False def __bytearray__(self): _bytes = super(Boolean, self).__bytearray__() _bytes += self.int_to_bytes(int(self.bflag)) return _bytes def __bool__(self): return self.bflag def __nonzero__(self): return self.__bool__() def parse(self, packet): super(Boolean, self).parse(packet) self.bflag = packet[:1] del packet[:1] class CreationTime(Signature): """ 5.2.3.4. Signature Creation Time (4-octet time field) The time the signature was made. MUST be present in the hashed area. """ __typeid__ = 0x02 @sdproperty def created(self): return self._created @created.register(datetime) def created_datetime(self, val): self._created = val @created.register(int) def created_int(self, val): self.created = datetime.utcfromtimestamp(val) @created.register(bytearray) def created_bytearray(self, val): self.created = self.bytes_to_int(val) def __init__(self): super(CreationTime, self).__init__() self.created = datetime.utcnow() def __bytearray__(self): _bytes = super(CreationTime, self).__bytearray__() _bytes += self.int_to_bytes(calendar.timegm(self.created.utctimetuple()), 4) return _bytes def parse(self, packet): super(CreationTime, self).parse(packet) self.created = packet[:4] del packet[:4] class SignatureExpirationTime(Signature): """ 5.2.3.10. Signature Expiration Time (4-octet time field) The validity period of the signature. This is the number of seconds after the signature creation time that the signature expires. If this is not present or has a value of zero, it never expires. """ __typeid__ = 0x03 @sdproperty def expires(self): return self._expires @expires.register(timedelta) def expires_timedelta(self, val): self._expires = val @expires.register(int) def expires_int(self, val): self.expires = timedelta(seconds=val) @expires.register(bytearray) def expires_bytearray(self, val): self.expires = self.bytes_to_int(val) def __init__(self): super(SignatureExpirationTime, self).__init__() self.expires = 0 def __bytearray__(self): _bytes = super(SignatureExpirationTime, self).__bytearray__() _bytes += self.int_to_bytes(int(self.expires.total_seconds()), 4) return _bytes def parse(self, packet): super(SignatureExpirationTime, self).parse(packet) self.expires = packet[:4] del packet[:4] class ExportableCertification(Boolean): """ 5.2.3.11. Exportable Certification (1 octet of exportability, 0 for not, 1 for exportable) This subpacket denotes whether a certification signature is "exportable", to be used by other users than the signature's issuer. The packet body contains a Boolean flag indicating whether the signature is exportable. If this packet is not present, the certification is exportable; it is equivalent to a flag containing a 1. Non-exportable, or "local", certifications are signatures made by a user to mark a key as valid within that user's implementation only. Thus, when an implementation prepares a user's copy of a key for transport to another user (this is the process of "exporting" the key), any local certification signatures are deleted from the key. The receiver of a transported key "imports" it, and likewise trims any local certifications. In normal operation, there won't be any, assuming the import is performed on an exported key. However, there are instances where this can reasonably happen. For example, if an implementation allows keys to be imported from a key database in addition to an exported key, then this situation can arise. Some implementations do not represent the interest of a single user (for example, a key server). Such implementations always trim local certifications from any key they handle. """ __typeid__ = 0x04 class TrustSignature(Signature): """ 5.2.3.13. Trust Signature (1 octet "level" (depth), 1 octet of trust amount) Signer asserts that the key is not only valid but also trustworthy at the specified level. Level 0 has the same meaning as an ordinary validity signature. Level 1 means that the signed key is asserted to be a valid trusted introducer, with the 2nd octet of the body specifying the degree of trust. Level 2 means that the signed key is asserted to be trusted to issue level 1 trust signatures, i.e., that it is a "meta introducer". Generally, a level n trust signature asserts that a key is trusted to issue level n-1 trust signatures. The trust amount is in a range from 0-255, interpreted such that values less than 120 indicate partial trust and values of 120 or greater indicate complete trust. Implementations SHOULD emit values of 60 for partial trust and 120 for complete trust. """ __typeid__ = 0x05 @sdproperty def level(self): return self._level @level.register(int) def level_int(self, val): self._level = val @level.register(bytearray) def level_bytearray(self, val): self.level = self.bytes_to_int(val) @sdproperty def amount(self): return self._amount @amount.register(int) def amount_int(self, val): # clamp 'val' to the range 0-255 self._amount = max(0, min(val, 255)) @amount.register(bytearray) def amount_bytearray(self, val): self.amount = self.bytes_to_int(val) def __init__(self): super(TrustSignature, self).__init__() self.level = 0 self.amount = 0 def __bytearray__(self): _bytes = super(TrustSignature, self).__bytearray__() _bytes += self.int_to_bytes(self.level) _bytes += self.int_to_bytes(self.amount) return _bytes def parse(self, packet): super(TrustSignature, self).parse(packet) self.level = packet[:1] del packet[:1] self.amount = packet[:1] del packet[:1] class RegularExpression(Signature): """ 5.2.3.14. Regular Expression (null-terminated regular expression) Used in conjunction with trust Signature packets (of level > 0) to limit the scope of trust that is extended. Only signatures by the target key on User IDs that match the regular expression in the body of this packet have trust extended by the trust Signature subpacket. The regular expression uses the same syntax as the Henry Spencer's "almost public domain" regular expression [REGEX] package. A description of the syntax is found in Section 8 below. """ __typeid__ = 0x06 @sdproperty def regex(self): return self._regex @regex.register(str) @regex.register(six.text_type) def regex_str(self, val): self._regex = val @regex.register(bytearray) def regex_bytearray(self, val): self.regex = val.decode('latin-1') def __init__(self): super(RegularExpression, self).__init__() self.regex = r'' def __bytearray__(self): _bytes = super(RegularExpression, self).__bytearray__() _bytes += self.regex.encode() return _bytes def parse(self, packet): super(RegularExpression, self).parse(packet) self.regex = packet[:(self.header.length - 1)] del packet[:(self.header.length - 1)] class Revocable(Boolean): """ 5.2.3.12. Revocable (1 octet of revocability, 0 for not, 1 for revocable) Signature's revocability status. The packet body contains a Boolean flag indicating whether the signature is revocable. Signatures that are not revocable have any later revocation signatures ignored. They represent a commitment by the signer that he cannot revoke his signature for the life of his key. If this packet is not present, the signature is revocable. """ __typeid__ = 0x07 class KeyExpirationTime(SignatureExpirationTime): """ 5.2.3.6. Key Expiration Time (4-octet time field) The validity period of the key. This is the number of seconds after the key creation time that the key expires. If this is not present or has a value of zero, the key never expires. This is found only on a self-signature. """ __typeid__ = 0x09 class PreferredSymmetricAlgorithms(FlagList): """ 5.2.3.7. Preferred Symmetric Algorithms (array of one-octet values) Symmetric algorithm numbers that indicate which algorithms the key holder prefers to use. The subpacket body is an ordered list of octets with the most preferred listed first. It is assumed that only algorithms listed are supported by the recipient's software. Algorithm numbers are in Section 9. This is only found on a self- signature. """ __typeid__ = 0x0B __flags__ = SymmetricKeyAlgorithm class RevocationKey(Signature): """ 5.2.3.15. Revocation Key (1 octet of class, 1 octet of public-key algorithm ID, 20 octets of fingerprint) Authorizes the specified key to issue revocation signatures for this key. Class octet must have bit 0x80 set. If the bit 0x40 is set, then this means that the revocation information is sensitive. Other bits are for future expansion to other kinds of authorizations. This is found on a self-signature. If the "sensitive" flag is set, the keyholder feels this subpacket contains private trust information that describes a real-world sensitive relationship. If this flag is set, implementations SHOULD NOT export this signature to other users except in cases where the data needs to be available: when the signature is being sent to the designated revoker, or when it is accompanied by a revocation signature from that revoker. Note that it may be appropriate to isolate this subpacket within a separate signature so that it is not combined with other subpackets that need to be exported. """ __typeid__ = 0x0C @sdproperty def keyclass(self): return self._keyclass @keyclass.register(list) def keyclass_list(self, val): self._keyclass = val @keyclass.register(int) @keyclass.register(RevocationKeyClass) def keyclass_int(self, val): self._keyclass += RevocationKeyClass & val @keyclass.register(bytearray) def keyclass_bytearray(self, val): self.keyclass = self.bytes_to_int(val) @sdproperty def algorithm(self): return self._algorithm @algorithm.register(int) @algorithm.register(PubKeyAlgorithm) def algorithm_int(self, val): self._algorithm = PubKeyAlgorithm(val) @algorithm.register(bytearray) def algorithm_bytearray(self, val): self.algorithm = self.bytes_to_int(val) @sdproperty def fingerprint(self): return self._fingerprint @fingerprint.register(str) @fingerprint.register(six.text_type) @fingerprint.register(Fingerprint) def fingerprint_str(self, val): self._fingerprint = Fingerprint(val) @fingerprint.register(bytearray) def fingerprint_bytearray(self, val): self.fingerprint = ''.join('{:02x}'.format(c) for c in val).upper() def __init__(self): super(RevocationKey, self).__init__() self.keyclass = [] self.algorithm = PubKeyAlgorithm.Invalid self._fingerprint = "" def __bytearray__(self): _bytes = super(RevocationKey, self).__bytearray__() _bytes += self.int_to_bytes(sum(self.keyclass)) _bytes += self.int_to_bytes(self.algorithm.value) _bytes += self.fingerprint.__bytes__() return _bytes def parse(self, packet): super(RevocationKey, self).parse(packet) self.keyclass = packet[:1] del packet[:1] self.algorithm = packet[:1] del packet[:1] self.fingerprint = packet[:20] del packet[:20] class Issuer(Signature): __typeid__ = 0x10 @sdproperty def issuer(self): return self._issuer @issuer.register(bytearray) def issuer_bytearray(self, val): self._issuer = binascii.hexlify(val).upper().decode('latin-1') def __init__(self): super(Issuer, self).__init__() self.issuer = bytearray() def __bytearray__(self): _bytes = super(Issuer, self).__bytearray__() _bytes += binascii.unhexlify(self._issuer.encode()) return _bytes def parse(self, packet): super(Issuer, self).parse(packet) self.issuer = packet[:8] del packet[:8] class NotationData(Signature): __typeid__ = 0x14 @sdproperty def flags(self): return self._flags @flags.register(list) def flags_list(self, val): self._flags = val @flags.register(int) @flags.register(NotationDataFlags) def flags_int(self, val): self.flags += NotationDataFlags & val @flags.register(bytearray) def flags_bytearray(self, val): self.flags = self.bytes_to_int(val) @sdproperty def name(self): return self._name @name.register(str) @name.register(six.text_type) def name_str(self, val): self._name = val @name.register(bytearray) def name_bytearray(self, val): self.name = val.decode('latin-1') @sdproperty def value(self): return self._value @value.register(str) @value.register(six.text_type) def value_str(self, val): self._value = val @value.register(bytearray) def value_bytearray(self, val): if NotationDataFlags.HumanReadable in self.flags: self.value = val.decode('latin-1') else: # pragma: no cover self._value = val def __init__(self): super(NotationData, self).__init__() self.flags = [0, 0, 0, 0] self.name = "" self.value = "" def __bytearray__(self): _bytes = super(NotationData, self).__bytearray__() _bytes += self.int_to_bytes(sum(self.flags)) + b'\x00\x00\x00' _bytes += self.int_to_bytes(len(self.name), 2) _bytes += self.int_to_bytes(len(self.value), 2) _bytes += self.name.encode() _bytes += self.value if isinstance(self.value, bytearray) else self.value.encode() return bytes(_bytes) def parse(self, packet): super(NotationData, self).parse(packet) self.flags = packet[:1] del packet[:4] nlen = self.bytes_to_int(packet[:2]) del packet[:2] vlen = self.bytes_to_int(packet[:2]) del packet[:2] self.name = packet[:nlen] del packet[:nlen] self.value = packet[:vlen] del packet[:vlen] class PreferredHashAlgorithms(FlagList): __typeid__ = 0x15 __flags__ = HashAlgorithm class PreferredCompressionAlgorithms(FlagList): __typeid__ = 0x16 __flags__ = CompressionAlgorithm class KeyServerPreferences(ByteFlag): __typeid__ = 0x17 __flags__ = _KeyServerPreferences class PreferredKeyServer(URI): __typeid__ = 0x18 class PrimaryUserID(Signature): __typeid__ = 0x19 @sdproperty def primary(self): return self._primary @primary.register(bool) def primary_bool(self, val): self._primary = val @primary.register(bytearray) def primary_byrearray(self, val): self.primary = bool(self.bytes_to_int(val)) def __init__(self): super(PrimaryUserID, self).__init__() self.primary = True def __bytearray__(self): _bytes = super(PrimaryUserID, self).__bytearray__() _bytes += self.int_to_bytes(int(self.primary)) return _bytes def __bool__(self): return self.primary def __nonzero__(self): return self.__bool__() def parse(self, packet): super(PrimaryUserID, self).parse(packet) self.primary = packet[:1] del packet[:1] class Policy(URI): __typeid__ = 0x1a class KeyFlags(ByteFlag): __typeid__ = 0x1B __flags__ = _KeyFlags class SignersUserID(Signature): __typeid__ = 0x1C @sdproperty def userid(self): return self._userid @userid.register(str) @userid.register(six.text_type) def userid_str(self, val): self._userid = val @userid.register(bytearray) def userid_bytearray(self, val): self.userid = val.decode('latin-1') def __init__(self): super(SignersUserID, self).__init__() self.userid = "" def __bytearray__(self): _bytes = super(SignersUserID, self).__bytearray__() _bytes += self.userid.encode() return _bytes def parse(self, packet): super(SignersUserID, self).parse(packet) self.userid = packet[:(self.header.length - 1)] del packet[:(self.header.length - 1)] class ReasonForRevocation(Signature): __typeid__ = 0x1D @sdproperty def code(self): return self._code @code.register(int) @code.register(RevocationReason) def code_int(self, val): self._code = RevocationReason(val) @code.register(bytearray) def code_bytearray(self, val): self.code = self.bytes_to_int(val) @sdproperty def string(self): return self._string @string.register(str) @string.register(six.text_type) def string_str(self, val): self._string = val @string.register(bytearray) def string_bytearray(self, val): self.string = val.decode('latin-1') def __init__(self): super(ReasonForRevocation, self).__init__() self.code = 0x00 self.string = "" def __bytearray__(self): _bytes = super(ReasonForRevocation, self).__bytearray__() _bytes += self.int_to_bytes(self.code) _bytes += self.string.encode() return _bytes def parse(self, packet): super(ReasonForRevocation, self).parse(packet) self.code = packet[:1] del packet[:1] self.string = packet[:(self.header.length - 2)] del packet[:(self.header.length - 2)] class Features(ByteFlag): __typeid__ = 0x1E __flags__ = _Features ##TODO: obtain subpacket type 0x1F - Signature Target class EmbeddedSignature(Signature): __typeid__ = 0x20 @sdproperty def _sig(self): return self._sigpkt @_sig.setter def _sig(self, val): esh = EmbeddedSignatureHeader() esh.version = val.header.version val.header = esh val.update_hlen() self._sigpkt = val @property def sigtype(self): return self._sig.sigtype @property def pubalg(self): return self._sig.pubalg @property def halg(self): return self._sig.halg @property def subpackets(self): return self._sig.subpackets @property def hash2(self): # pragma: no cover return self._sig.hash2 @property def signature(self): return self._sig.signature @property def signer(self): return self._sig.signer def __init__(self): super(EmbeddedSignature, self).__init__() from ..packets import SignatureV4 self._sigpkt = SignatureV4() self._sigpkt.header = EmbeddedSignatureHeader() def __bytearray__(self): return super(EmbeddedSignature, self).__bytearray__() + self._sigpkt.__bytearray__() def parse(self, packet): super(EmbeddedSignature, self).parse(packet) self._sig.parse(packet) class IssuerFingerprint(Signature): ''' (from RFC4880bis-07) 5.2.3.28. Issuer Fingerprint (1 octet key version number, N octets of fingerprint) The OpenPGP Key fingerprint of the key issuing the signature. This subpacket SHOULD be included in all signatures. If the version of the issuing key is 4 and an Issuer subpacket is also included in the signature, the key ID of the Issuer subpacket MUST match the low 64 bits of the fingerprint. Note that the length N of the fingerprint for a version 4 key is 20 octets; for a version 5 key N is 32. ''' __typeid__ = 0x21 @sdproperty def version(self): return self._version @version.register(int) def version_int(self, val): self._version = val @version.register(bytearray) def version_bytearray(self, val): self.version = self.bytes_to_int(val) @sdproperty def issuer_fingerprint(self): return self._issuer_fpr @issuer_fingerprint.register(str) @issuer_fingerprint.register(six.text_type) @issuer_fingerprint.register(Fingerprint) def issuer_fingerprint_str(self, val): self._issuer_fpr = Fingerprint(val) @issuer_fingerprint.register(bytearray) def issuer_fingerprint_bytearray(self, val): self.issuer_fingerprint = ''.join('{:02x}'.format(c) for c in val).upper() def __init__(self): super(IssuerFingerprint, self).__init__() self.version = 4 self._issuer_fpr = "" def __bytearray__(self): _bytes = super(IssuerFingerprint, self).__bytearray__() _bytes += self.int_to_bytes(self.version) _bytes += self.issuer_fingerprint.__bytes__() return _bytes def parse(self, packet): super(IssuerFingerprint, self).parse(packet) self.version = packet[:1] del packet[:1] if self.version == 4: fpr_len = 20 elif self.version == 5: # pragma: no cover fpr_len = 32 else: # pragma: no cover fpr_len = self.header.length - 1 self.issuer_fingerprint = packet[:fpr_len] del packet[:fpr_len] class IntendedRecipient(Signature): ''' (from RFC4880bis-08) 5.2.3.29. Intended Recipient (1 octet key version number, N octets of fingerprint) The OpenPGP Key fingerprint of the intended recipient primary key. If one or more subpackets of this type are included in a signature, it SHOULD be considered valid only in an encrypted context, where the key it was encrypted to is one of the indicated primary keys, or one of their subkeys. This can be used to prevent forwarding a signature outside of its intended, encrypted context. Note that the length N of the fingerprint for a version 4 key is 20 octets; for a version 5 key N is 32. ''' __typeid__ = 0x23 @sdproperty def version(self): return self._version @version.register(int) def version_int(self, val): self._version = val @version.register(bytearray) def version_bytearray(self, val): self.version = self.bytes_to_int(val) @sdproperty def intended_recipient(self): return self._intended_recipient @intended_recipient.register(str) @intended_recipient.register(six.text_type) @intended_recipient.register(Fingerprint) def intended_recipient_str(self, val): self._intended_recipient = Fingerprint(val) @intended_recipient.register(bytearray) def intended_recipient_bytearray(self, val): self.intended_recipient = ''.join('{:02x}'.format(c) for c in val).upper() def __init__(self): super(IntendedRecipient, self).__init__() self.version = 4 self._intended_recipient = "" def __bytearray__(self): _bytes = super(IntendedRecipient, self).__bytearray__() _bytes += self.int_to_bytes(self.version) _bytes += self.intended_recipient.__bytes__() return _bytes def parse(self, packet): super(IntendedRecipient, self).parse(packet) self.version = packet[:1] del packet[:1] if self.version == 4: fpr_len = 20 elif self.version == 5: # pragma: no cover fpr_len = 32 else: # pragma: no cover fpr_len = self.header.length - 1 self.intended_recipient = packet[:fpr_len] del packet[:fpr_len] class AttestedCertifications(Signature): ''' (from RFC4880bis-08) 5.2.3.30. Attested Certifications (N octets of certification digests) This subpacket MUST only appear as a hashed subpacket of an Attestation Key Signature. It has no meaning in any other signature type. It is used by the primary key to attest to a set of third- party certifications over the associated User ID or User Attribute. This enables the holder of an OpenPGP primary key to mark specific third-party certifications as re-distributable with the rest of the Transferable Public Key (see the "No-modify" flag in "Key Server Preferences", above). Implementations MUST include exactly one Attested Certification subpacket in any generated Attestation Key Signature. The contents of the subpacket consists of a series of digests using the same hash algorithm used by the signature itself. Each digest is made over one third-party signature (any Certification, i.e., signature type 0x10-0x13) that covers the same Primary Key and User ID (or User Attribute). For example, an Attestation Key Signature made by key X over user ID U using hash algorithm SHA256 might contain an Attested Certifications subpacket of 192 octets (6*32 octets) covering six third-party certification Signatures over . They SHOULD be ordered by binary hash value from low to high (e.g., a hash with hexadecimal value 037a... precedes a hash with value 0392..., etc). The length of this subpacket MUST be an integer multiple of the length of the hash algorithm used for the enclosing Attestation Key Signature. The listed digests MUST be calculated over the third-party certification's Signature packet as described in the "Computing Signatures" section, but without a trailer: the hash data starts with the octet 0x88, followed by the four-octet length of the Signature, and then the body of the Signature packet. (Note that this is an old-style packet header for a Signature packet with the length-of- length field set to zero.) The unhashed subpacket data of the Signature packet being hashed is not included in the hash, and the unhashed subpacket data length value is set to zero. If an implementation encounters more than one such subpacket in an Attestation Key Signature, it MUST treat it as a single Attested Certifications subpacket containing the union of all hashes. The Attested Certifications subpacket in the most recent Attestation Key Signature over a given user ID supersedes all Attested Certifications subpackets from any previous Attestation Key Signature. However, note that if more than one Attestation Key Signatures has the same (most recent) Signature Creation Time subpacket, implementations MUST consider the union of the attestations of all Attestation Key Signatures (this allows the keyholder to attest to more third-party certifications than could fit in a single Attestation Key Signature). If a keyholder Alice has already attested to third-party certifications from Bob and Carol and she wants to add an attestation to a certification from David, she should issue a new Attestation Key Signature (with a more recent Signature Creation timestamp) that contains an Attested Certifications subpacket covering all three third-party certifications. If she later decides that she does not want Carol's certification to be redistributed with her certificate, she can issue a new Attestation Key Signature (again, with a more recent Signature Creation timestamp) that contains an Attested Certifications subpacket covering only the certifications from Bob and David. Note that Certification Revocation Signatures are not relevant for Attestation Key Signatures. To rescind all attestations, the primary key holder needs only to publish a more recent Attestation Key Signature with an empty Attested Certifications subpacket. ''' __typeid__ = 0x25 @sdproperty def attested_certifications(self): return self._attested_certifications @attested_certifications.register(bytearray) @attested_certifications.register(bytes) def attested_certifications_bytearray(self, val): self._attested_certifications = val def __init__(self): super(AttestedCertifications, self).__init__() self._attested_certifications = bytearray() def __bytearray__(self): _bytes = super(AttestedCertifications, self).__bytearray__() _bytes += self._attested_certifications return _bytes def parse(self, packet): super(AttestedCertifications, self).parse(packet) self.attested_certifications = packet[:(self.header.length - 1)] del packet[:(self.header.length - 1)] PGPy-0.5.4/pgpy/packet/subpackets/types.py000066400000000000000000000063701403641706600204640ustar00rootroot00000000000000""" subpacket.py """ import abc from ..types import VersionedHeader from ...decorators import sdproperty from ...types import Dispatchable from ...types import Header as _Header __all__ = ['Header', 'EmbeddedSignatureHeader', 'SubPacket', 'Signature', 'UserAttribute', 'Opaque'] class Header(_Header): @sdproperty def critical(self): return self._critical @critical.register(bool) def critical_bool(self, val): self._critical = val @sdproperty def typeid(self): return self._typeid @typeid.register(int) def typeid_int(self, val): self._typeid = val & 0x7f @typeid.register(bytes) @typeid.register(bytearray) def typeid_bin(self, val): v = self.bytes_to_int(val) self.typeid = v self.critical = bool(v & 0x80) def __init__(self): super(Header, self).__init__() self._typeid = -1 self.critical = False def parse(self, packet): self.length = packet self.typeid = packet[:1] del packet[:1] def __len__(self): return self.llen + 1 def __bytearray__(self): _bytes = bytearray(self.encode_length(self.length)) _bytes += self.int_to_bytes((int(self.critical) << 7) + self.typeid) return _bytes class EmbeddedSignatureHeader(VersionedHeader): def __bytearray__(self): return bytearray([self.version]) def parse(self, packet): self.tag = 2 super(EmbeddedSignatureHeader, self).parse(packet) class SubPacket(Dispatchable): __headercls__ = Header def __init__(self): super(SubPacket, self).__init__() self.header = Header() # if self.__typeid__ not in [-1, None]: if (self.header.typeid == -1 and (not hasattr(self.__typeid__, '__abstractmethod__')) and (self.__typeid__ not in [-1, None])): self.header.typeid = self.__typeid__ def __bytearray__(self): return self.header.__bytearray__() def __len__(self): return (self.header.llen + self.header.length) def __repr__(self): return "<{} [0x{:02x}] at 0x{:x}>".format(self.__class__.__name__, self.header.typeid, id(self)) def update_hlen(self): self.header.length = (len(self.__bytearray__()) - len(self.header)) + 1 @abc.abstractmethod def parse(self, packet): # pragma: no cover if self.header._typeid == -1: self.header.parse(packet) class Signature(SubPacket): __typeid__ = -1 class UserAttribute(SubPacket): __typeid__ = -1 class Opaque(Signature, UserAttribute): __typeid__ = None @sdproperty def payload(self): return self._payload @payload.register(bytes) @payload.register(bytearray) def payload_bin(self, val): self._payload = bytearray(val) def __init__(self): super(Opaque, self).__init__() self.payload = b'' def __bytearray__(self): _bytes = super(Opaque, self).__bytearray__() _bytes += self.payload return _bytes def parse(self, packet): super(Opaque, self).parse(packet) self.payload = packet[:(self.header.length - 1)] del packet[:(self.header.length - 1)] PGPy-0.5.4/pgpy/packet/subpackets/userattribute.py000066400000000000000000000066641403641706600222300ustar00rootroot00000000000000""" userattribute.py """ import struct from .types import UserAttribute from ...constants import ImageEncoding from ...decorators import sdproperty from ...memoryview import memoryview __all__ = ('Image',) class Image(UserAttribute): """ 5.12.1. The Image Attribute Subpacket The Image Attribute subpacket is used to encode an image, presumably (but not required to be) that of the key owner. The Image Attribute subpacket begins with an image header. The first two octets of the image header contain the length of the image header. Note that unlike other multi-octet numerical values in this document, due to a historical accident this value is encoded as a little-endian number. The image header length is followed by a single octet for the image header version. The only currently defined version of the image header is 1, which is a 16-octet image header. The first three octets of a version 1 image header are thus 0x10, 0x00, 0x01. The fourth octet of a version 1 image header designates the encoding format of the image. The only currently defined encoding format is the value 1 to indicate JPEG. Image format types 100 through 110 are reserved for private or experimental use. The rest of the version 1 image header is made up of 12 reserved octets, all of which MUST be set to 0. The rest of the image subpacket contains the image itself. As the only currently defined image type is JPEG, the image is encoded in the JPEG File Interchange Format (JFIF), a standard file format for JPEG images [JFIF]. An implementation MAY try to determine the type of an image by examination of the image data if it is unable to handle a particular version of the image header or if a specified encoding format value is not recognized. """ __typeid__ = 0x01 @sdproperty def version(self): return self._version @version.register(int) def version_int(self, val): self._version = val @sdproperty def iencoding(self): return self._iencoding @iencoding.register(int) @iencoding.register(ImageEncoding) def iencoding_int(self, val): try: self._iencoding = ImageEncoding(val) except ValueError: # pragma: no cover self._iencoding = val @sdproperty def image(self): return self._image @image.register(bytes) @image.register(bytearray) def image_bin(self, val): self._image = bytearray(val) def __init__(self): super(Image, self).__init__() self.version = 1 self.iencoding = 1 self.image = bytearray() def __bytearray__(self): _bytes = super(Image, self).__bytearray__() if self.version == 1: # v1 image header length is always 16 bytes # and stored little-endian due to an 'historical accident' _bytes += struct.pack('> 2) try: self._tag = PacketTag(_tag) except ValueError: # pragma: no cover self._tag = _tag @property def typeid(self): return self.tag def __init__(self): super(Header, self).__init__() self.tag = 0x00 def __bytearray__(self): tag = 0x80 | (self._lenfmt << 6) tag |= (self.tag) if self._lenfmt else ((self.tag << 2) | {1: 0, 2: 1, 4: 2, 0: 3}[self.llen]) _bytes = bytearray(self.int_to_bytes(tag)) _bytes += self.encode_length(self.length, self._lenfmt, self.llen) return _bytes def __len__(self): return 1 + self.llen def parse(self, packet): """ There are two formats for headers old style --------- Old style headers can be 1, 2, 3, or 6 octets long and are composed of a Tag and a Length. If the header length is 1 octet (length_type == 3), then there is no Length field. new style --------- New style headers can be 2, 3, or 6 octets long and are also composed of a Tag and a Length. Packet Tag ---------- The packet tag is the first byte, comprising the following fields: +-------------+----------+---------------+---+---+---+---+----------+----------+ | byte | 1 | +-------------+----------+---------------+---+---+---+---+----------+----------+ | bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +-------------+----------+---------------+---+---+---+---+----------+----------+ | old-style | always 1 | packet format | packet tag | length type | | description | | 0 = old-style | | 0 = 1 octet | | | | 1 = new-style | | 1 = 2 octets | | | | | | 2 = 5 octets | | | | | | 3 = no length field | +-------------+ + +---------------+---------------------+ | new-style | | | packet tag | | description | | | | +-------------+----------+---------------+-------------------------------------+ :param packet: raw packet bytes """ self._lenfmt = ((packet[0] & 0x40) >> 6) self.tag = packet[0] if self._lenfmt == 0: self.llen = (packet[0] & 0x03) del packet[0] if (self._lenfmt == 0 and self.llen > 0) or self._lenfmt == 1: self.length = packet else: # indeterminate packet length self.length = len(packet) class VersionedHeader(Header): @sdproperty def version(self): return self._version @version.register(int) def version_int(self, val): self._version = val def __init__(self): super(VersionedHeader, self).__init__() self.version = 0 def __bytearray__(self): _bytes = bytearray(super(VersionedHeader, self).__bytearray__()) _bytes += bytearray([self.version]) return _bytes def parse(self, packet): # pragma: no cover if self.tag == 0: super(VersionedHeader, self).parse(packet) if self.version == 0: self.version = packet[0] del packet[0] class Packet(Dispatchable): __typeid__ = -1 __headercls__ = Header def __init__(self, _=None): super(Packet, self).__init__() self.header = self.__headercls__() if isinstance(self.__typeid__, six.integer_types): self.header.tag = self.__typeid__ @abc.abstractmethod def __bytearray__(self): return self.header.__bytearray__() def __len__(self): return len(self.header) + self.header.length def __repr__(self): return "<{cls:s} [tag {tag:02d}] at 0x{id:x}>".format(cls=self.__class__.__name__, tag=self.header.tag, id=id(self)) def update_hlen(self): self.header.length = len(self.__bytearray__()) - len(self.header) @abc.abstractmethod def parse(self, packet): if self.header.tag == 0: self.header.parse(packet) class VersionedPacket(Packet): __headercls__ = VersionedHeader def __init__(self): super(VersionedPacket, self).__init__() if isinstance(self.__ver__, six.integer_types): self.header.version = self.__ver__ def __repr__(self): return "<{cls:s} [tag {tag:02d}][v{ver:d}] at 0x{id:x}>".format(cls=self.__class__.__name__, tag=self.header.tag, ver=self.header.version, id=id(self)) class Opaque(Packet): __typeid__ = None @sdproperty def payload(self): return self._payload @payload.register(bytearray) @payload.register(bytes) def payload_bin(self, val): self._payload = val def __init__(self): super(Opaque, self).__init__() self.payload = b'' def __bytearray__(self): _bytes = super(Opaque, self).__bytearray__() _bytes += self.payload return _bytes def parse(self, packet): # pragma: no cover super(Opaque, self).parse(packet) pend = self.header.length if hasattr(self.header, 'version'): pend -= 1 self.payload = packet[:pend] del packet[:pend] # key marker classes for convenience class Key(object): pass class Public(Key): pass class Private(Key): pass class Primary(Key): pass class Sub(Key): pass # This is required for class MPI to work in both Python 2 and 3 if not six.PY2: long = int class MPI(long): def __new__(cls, num): mpi = num if isinstance(num, (bytes, bytearray)): if isinstance(num, bytes): # pragma: no cover num = bytearray(num) fl = ((MPIs.bytes_to_int(num[:2]) + 7) // 8) del num[:2] mpi = MPIs.bytes_to_int(num[:fl]) del num[:fl] return super(MPI, cls).__new__(cls, mpi) def byte_length(self): return ((self.bit_length() + 7) // 8) def to_mpibytes(self): return MPIs.int_to_bytes(self.bit_length(), 2) + MPIs.int_to_bytes(self, self.byte_length()) def __len__(self): return self.byte_length() + 2 class MPIs(Field): # this differs from MPI in that it's subclasses hold/parse several MPI fields # and, in the case of v4 private keys, also a String2Key specifier/information. __mpis__ = () def __len__(self): return sum(len(i) for i in self) def __iter__(self): """yield all components of an MPI so it can be iterated over""" for i in self.__mpis__: yield getattr(self, i) def __copy__(self): pk = self.__class__() for m in self.__mpis__: setattr(pk, m, copy.copy(getattr(self, m))) return pk PGPy-0.5.4/pgpy/pgp.py000066400000000000000000003331531403641706600144750ustar00rootroot00000000000000""" pgp.py this is where the armorable PGP block objects live """ import binascii import collections try: import collections.abc as collections_abc except ImportError: collections_abc = collections import contextlib import copy import functools import itertools import operator import os import re import warnings import weakref import six from datetime import datetime from cryptography.hazmat.primitives import hashes from .constants import CompressionAlgorithm from .constants import Features from .constants import HashAlgorithm from .constants import ImageEncoding from .constants import KeyFlags from .constants import NotationDataFlags from .constants import PacketTag from .constants import PubKeyAlgorithm from .constants import RevocationKeyClass from .constants import RevocationReason from .constants import SignatureType from .constants import SymmetricKeyAlgorithm from .decorators import KeyAction from .errors import PGPDecryptionError from .errors import PGPError from .packet import Key from .packet import MDC from .packet import Packet from .packet import Primary from .packet import Private from .packet import PubKeyV4 from .packet import PubSubKeyV4 from .packet import PrivKeyV4 from .packet import PrivSubKeyV4 from .packet import Public from .packet import Sub from .packet import UserID from .packet import UserAttribute from .packet.packets import CompressedData from .packet.packets import IntegrityProtectedSKEData from .packet.packets import IntegrityProtectedSKEDataV1 from .packet.packets import LiteralData from .packet.packets import OnePassSignature from .packet.packets import OnePassSignatureV3 from .packet.packets import PKESessionKey from .packet.packets import PKESessionKeyV3 from .packet.packets import Signature from .packet.packets import SignatureV4 from .packet.packets import SKEData from .packet.packets import Marker from .packet.packets import SKESessionKey from .packet.packets import SKESessionKeyV4 from .packet.types import Opaque from .types import Armorable from .types import Fingerprint from .types import ParentRef from .types import PGPObject from .types import SignatureVerification from .types import SorteDeque __all__ = ['PGPSignature', 'PGPUID', 'PGPMessage', 'PGPKey', 'PGPKeyring'] class PGPSignature(Armorable, ParentRef, PGPObject): _reason_for_revocation = collections.namedtuple('ReasonForRevocation', ['code', 'comment']) @property def __sig__(self): return self._signature.signature.__sig__() @property def cipherprefs(self): """ A ``list`` of preferred symmetric algorithms specified in this signature, if any. Otherwise, an empty ``list``. """ if 'PreferredSymmetricAlgorithms' in self._signature.subpackets: return next(iter(self._signature.subpackets['h_PreferredSymmetricAlgorithms'])).flags return [] @property def compprefs(self): """ A ``list`` of preferred compression algorithms specified in this signature, if any. Otherwise, an empty ``list``. """ if 'PreferredCompressionAlgorithms' in self._signature.subpackets: return next(iter(self._signature.subpackets['h_PreferredCompressionAlgorithms'])).flags return [] @property def created(self): """ A :py:obj:`~datetime.datetime` of when this signature was created. """ return self._signature.subpackets['h_CreationTime'][-1].created @property def embedded(self): return self.parent is not None @property def expires_at(self): """ A :py:obj:`~datetime.datetime` of when this signature expires, if a signature expiration date is specified. Otherwise, ``None`` """ if 'SignatureExpirationTime' in self._signature.subpackets: expd = next(iter(self._signature.subpackets['SignatureExpirationTime'])).expires return self.created + expd return None @property def exportable(self): """ ``False`` if this signature is marked as being not exportable. Otherwise, ``True``. """ if 'ExportableCertification' in self._signature.subpackets: return bool(next(iter(self._signature.subpackets['ExportableCertification']))) return True @property def features(self): """ A ``set`` of implementation features specified in this signature, if any. Otherwise, an empty ``set``. """ if 'Features' in self._signature.subpackets: return next(iter(self._signature.subpackets['Features'])).flags return set() @property def hash2(self): return self._signature.hash2 @property def hashprefs(self): """ A ``list`` of preferred hash algorithms specified in this signature, if any. Otherwise, an empty ``list``. """ if 'PreferredHashAlgorithms' in self._signature.subpackets: return next(iter(self._signature.subpackets['h_PreferredHashAlgorithms'])).flags return [] @property def hash_algorithm(self): """ The :py:obj:`~constants.HashAlgorithm` used when computing this signature. """ return self._signature.halg @property def is_expired(self): """ ``True`` if the signature has an expiration date, and is expired. Otherwise, ``False`` """ expires_at = self.expires_at if expires_at is not None and expires_at != self.created: return expires_at < datetime.utcnow() return False @property def key_algorithm(self): """ The :py:obj:`~constants.PubKeyAlgorithm` of the key that generated this signature. """ return self._signature.pubalg @property def key_expiration(self): if 'KeyExpirationTime' in self._signature.subpackets: return next(iter(self._signature.subpackets['KeyExpirationTime'])).expires return None @property def key_flags(self): """ A ``set`` of :py:obj:`~constants.KeyFlags` specified in this signature, if any. Otherwise, an empty ``set``. """ if 'KeyFlags' in self._signature.subpackets: return next(iter(self._signature.subpackets['h_KeyFlags'])).flags return set() @property def keyserver(self): """ The preferred key server specified in this signature, if any. Otherwise, an empty ``str``. """ if 'PreferredKeyServer' in self._signature.subpackets: return next(iter(self._signature.subpackets['h_PreferredKeyServer'])).uri return '' @property def keyserverprefs(self): """ A ``list`` of :py:obj:`~constants.KeyServerPreferences` in this signature, if any. Otherwise, an empty ``list``. """ if 'KeyServerPreferences' in self._signature.subpackets: return next(iter(self._signature.subpackets['h_KeyServerPreferences'])).flags return [] @property def magic(self): return "SIGNATURE" @property def notation(self): """ A ``dict`` of notation data in this signature, if any. Otherwise, an empty ``dict``. """ return dict((nd.name, nd.value) for nd in self._signature.subpackets['NotationData']) @property def policy_uri(self): """ The policy URI specified in this signature, if any. Otherwise, an empty ``str``. """ if 'Policy' in self._signature.subpackets: return next(iter(self._signature.subpackets['Policy'])).uri return '' @property def revocable(self): """ ``False`` if this signature is marked as being not revocable. Otherwise, ``True``. """ if 'Revocable' in self._signature.subpackets: return bool(next(iter(self._signature.subpackets['Revocable']))) return True @property def revocation_key(self): if 'RevocationKey' in self._signature.subpackets: raise NotImplementedError() return None @property def revocation_reason(self): if 'ReasonForRevocation' in self._signature.subpackets: subpacket = next(iter(self._signature.subpackets['ReasonForRevocation'])) return self._reason_for_revocation(subpacket.code, subpacket.string) return None @property def attested_certifications(self): """ Returns a set of all the hashes of attested certifications covered by this Attestation Key Signature. Unhashed subpackets are ignored. """ if self._signature.sigtype != SignatureType.Attestation: return set() ret = set() hlen = self.hash_algorithm.digest_size for n in self._signature.subpackets['h_AttestedCertifications']: attestations = bytes(n.attested_certifications) for i in range(0, len(attestations), hlen): ret.add(attestations[i:i+hlen]) return ret @property def signer(self): """ The 16-character Key ID of the key that generated this signature. """ return self._signature.signer @property def signer_fingerprint(self): """ The fingerprint of the key that generated this signature, if it contained. Otherwise, an empty ``str``. """ if 'IssuerFingerprint' in self._signature.subpackets: return next(iter(self._signature.subpackets['IssuerFingerprint'])).issuer_fingerprint return '' @property def intended_recipients(self): """ Returns an iterator over all the primary key fingerprints marked as intended encrypted recipients for this signature. """ return map(lambda x: x.intended_recipient, self._signature.subpackets['IntendedRecipient']) @property def target_signature(self): return NotImplemented @property def type(self): """ The :py:obj:`~constants.SignatureType` of this signature. """ return self._signature.sigtype @classmethod def new(cls, sigtype, pkalg, halg, signer, created=None): sig = PGPSignature() if created is None: created=datetime.utcnow() sigpkt = SignatureV4() sigpkt.header.tag = 2 sigpkt.header.version = 4 sigpkt.subpackets.addnew('CreationTime', hashed=True, created=created) sigpkt.subpackets.addnew('Issuer', _issuer=signer) sigpkt.sigtype = sigtype sigpkt.pubalg = pkalg if halg is not None: sigpkt.halg = halg sig._signature = sigpkt return sig def __init__(self): """ PGPSignature objects represent OpenPGP compliant signatures. PGPSignature implements the ``__str__`` method, the output of which will be the signature object in OpenPGP-compliant ASCII-armored format. PGPSignature implements the ``__bytes__`` method, the output of which will be the signature object in OpenPGP-compliant binary format. """ super(PGPSignature, self).__init__() self._signature = None def __bytearray__(self): return self._signature.__bytearray__() def __repr__(self): return "".format(self.type.name, id(self)) def __lt__(self, other): return self.created < other.created def __or__(self, other): if isinstance(other, Signature): if self._signature is None: self._signature = other return self ##TODO: this is not a great way to do this if other.__class__.__name__ == 'EmbeddedSignature': self._signature = other return self raise TypeError def __copy__(self): # because the default shallow copy isn't actually all that useful, # and deepcopy does too much work sig = super(PGPSignature, self).__copy__() # sig = PGPSignature() # sig.ascii_headers = self.ascii_headers.copy() sig |= copy.copy(self._signature) return sig def attests_to(self, othersig): 'returns True if this signature attests to othersig (acknolwedges it for redistribution)' if not isinstance(othersig, PGPSignature): raise TypeError h = self.hash_algorithm.hasher h.update(othersig._signature.canonical_bytes()) return h.digest() in self.attested_certifications def hashdata(self, subject): _data = bytearray() if isinstance(subject, six.string_types): try: subject = subject.encode('utf-8') except UnicodeEncodeError: subject = subject.encode('charmap') """ All signatures are formed by producing a hash over the signature data, and then using the resulting hash in the signature algorithm. """ if self.type == SignatureType.BinaryDocument: """ For binary document signatures (type 0x00), the document data is hashed directly. """ if isinstance(subject, (SKEData, IntegrityProtectedSKEData)): _data += subject.__bytearray__() else: _data += bytearray(subject) if self.type == SignatureType.CanonicalDocument: """ For text document signatures (type 0x01), the document is canonicalized by converting line endings to , and the resulting data is hashed. """ _data += re.subn(br'\r?\n', b'\r\n', subject)[0] if self.type in {SignatureType.Generic_Cert, SignatureType.Persona_Cert, SignatureType.Casual_Cert, SignatureType.Positive_Cert, SignatureType.CertRevocation, SignatureType.Subkey_Binding, SignatureType.PrimaryKey_Binding}: """ When a signature is made over a key, the hash data starts with the octet 0x99, followed by a two-octet length of the key, and then body of the key packet. (Note that this is an old-style packet header for a key packet with two-octet length.) ... Key revocation signatures (types 0x20 and 0x28) hash only the key being revoked. """ _s = b'' if isinstance(subject, PGPUID): _s = subject._parent.hashdata elif isinstance(subject, PGPKey) and not subject.is_primary: _s = subject._parent.hashdata elif isinstance(subject, PGPKey) and subject.is_primary: _s = subject.hashdata if len(_s) > 0: _data += b'\x99' + self.int_to_bytes(len(_s), 2) + _s if self.type in {SignatureType.Subkey_Binding, SignatureType.PrimaryKey_Binding}: """ A subkey binding signature (type 0x18) or primary key binding signature (type 0x19) then hashes the subkey using the same format as the main key (also using 0x99 as the first octet). """ if subject.is_primary: _s = subject.subkeys[self.signer].hashdata else: _s = subject.hashdata _data += b'\x99' + self.int_to_bytes(len(_s), 2) + _s if self.type in {SignatureType.KeyRevocation, SignatureType.SubkeyRevocation, SignatureType.DirectlyOnKey}: """ The signature is calculated directly on the key being revoked. A revoked key is not to be used. Only revocation signatures by the key being revoked, or by an authorized revocation key, should be considered valid revocation signatures. Subkey revocation signature The signature is calculated directly on the subkey being revoked. A revoked subkey is not to be used. Only revocation signatures by the top-level signature key that is bound to this subkey, or by an authorized revocation key, should be considered valid revocation signatures. - clarification from draft-ietf-openpgp-rfc4880bis-02: Primary key revocation signatures (type 0x20) hash only the key being revoked. Subkey revocation signature (type 0x28) hash first the primary key and then the subkey being revoked Signature directly on a key This signature is calculated directly on a key. It binds the information in the Signature subpackets to the key, and is appropriate to be used for subpackets that provide information about the key, such as the Revocation Key subpacket. It is also appropriate for statements that non-self certifiers want to make about the key itself, rather than the binding between a key and a name. """ if self.type == SignatureType.SubkeyRevocation: # hash the primary key first if this is a Subkey Revocation signature _s = subject.parent.hashdata _data += b'\x99' + self.int_to_bytes(len(_s), 2) + _s _s = subject.hashdata _data += b'\x99' + self.int_to_bytes(len(_s), 2) + _s if self.type in {SignatureType.Generic_Cert, SignatureType.Persona_Cert, SignatureType.Casual_Cert, SignatureType.Positive_Cert, SignatureType.CertRevocation}: """ A certification signature (type 0x10 through 0x13) hashes the User ID being bound to the key into the hash context after the above data. ... A V4 certification hashes the constant 0xB4 for User ID certifications or the constant 0xD1 for User Attribute certifications, followed by a four-octet number giving the length of the User ID or User Attribute data, and then the User ID or User Attribute data. ... The [certificate revocation] signature is computed over the same data as the certificate that it revokes, and should have a later creation date than that certificate. """ _s = subject.hashdata if subject.is_uid: _data += b'\xb4' else: _data += b'\xd1' _data += self.int_to_bytes(len(_s), 4) + _s # if this is a new signature, do update_hlen if 0 in list(self._signature.signature): self._signature.update_hlen() """ Once the data body is hashed, then a trailer is hashed. (...) A V4 signature hashes the packet body starting from its first field, the version number, through the end of the hashed subpacket data. Thus, the fields hashed are the signature version, the signature type, the public-key algorithm, the hash algorithm, the hashed subpacket length, and the hashed subpacket body. V4 signatures also hash in a final trailer of six octets: the version of the Signature packet, i.e., 0x04; 0xFF; and a four-octet, big-endian number that is the length of the hashed data from the Signature packet (note that this number does not include these final six octets). """ hcontext = bytearray() hcontext.append(self._signature.header.version if not self.embedded else self._signature._sig.header.version) hcontext.append(self.type) hcontext.append(self.key_algorithm) hcontext.append(self.hash_algorithm) hcontext += self._signature.subpackets.__hashbytearray__() hlen = len(hcontext) _data += hcontext _data += b'\x04\xff' _data += self.int_to_bytes(hlen, 4) return bytes(_data) def make_onepass(self): onepass = OnePassSignatureV3() onepass.sigtype = self.type onepass.halg = self.hash_algorithm onepass.pubalg = self.key_algorithm onepass.signer = self.signer onepass.update_hlen() return onepass def parse(self, packet): unarmored = self.ascii_unarmor(packet) data = unarmored['body'] if unarmored['magic'] is not None and unarmored['magic'] != 'SIGNATURE': raise ValueError('Expected: SIGNATURE. Got: {}'.format(str(unarmored['magic']))) if unarmored['headers'] is not None: self.ascii_headers = unarmored['headers'] # load *one* packet from data pkt = Packet(data) if pkt.header.tag == PacketTag.Signature and not isinstance(pkt, Opaque): self._signature = pkt else: raise ValueError('Expected: Signature. Got: {:s}'.format(pkt.__class__.__name__)) class PGPUID(ParentRef): @property def __sig__(self): return list(self._signatures) def _splitstring(self): '''returns name, comment email from User ID string''' if not isinstance(self._uid, UserID): return ("", "", "") if self._uid.uid == "": return ("", "", "") rfc2822 = re.match(r"""^ # name should always match something (?P.+?) # comment *optionally* matches text in parens following name # this should never come after email and must be followed immediately by # either the email field, or the end of the packet. (\ \((?P.+?)\)(?=(\ <|$)))? # email *optionally* matches text in angle brackets following name or comment # this should never come before a comment, if comment exists, # but can immediately follow name if comment does not exist (\ <(?P.+)>)? $ """, self._uid.uid, flags=re.VERBOSE).groupdict() return (rfc2822['name'], rfc2822['comment'] or "", rfc2822['email'] or "") @property def name(self): """If this is a User ID, the stored name. If this is not a User ID, this will be an empty string.""" return self._splitstring()[0] @property def comment(self): """ If this is a User ID, this will be the stored comment. If this is not a User ID, or there is no stored comment, this will be an empty string., """ return self._splitstring()[1] @property def email(self): """ If this is a User ID, this will be the stored email address. If this is not a User ID, or there is no stored email address, this will be an empty string. """ return self._splitstring()[2] @property def userid(self): """ If this is a User ID, this will be the full UTF-8 string. If this is not a User ID, this will be ``None``. """ return self._uid.uid if isinstance(self._uid, UserID) else None @property def image(self): """ If this is a User Attribute, this will be the stored image. If this is not a User Attribute, this will be ``None``. """ return self._uid.image.image if isinstance(self._uid, UserAttribute) else None @property def is_primary(self): """ If the most recent, valid self-signature specifies this as being primary, this will be True. Otherwise, False. """ if self.selfsig is not None: return bool(next(iter(self.selfsig._signature.subpackets['h_PrimaryUserID']), False)) return False @property def is_uid(self): """ ``True`` if this is a User ID, otherwise False. """ return isinstance(self._uid, UserID) @property def is_ua(self): """ ``True`` if this is a User Attribute, otherwise False. """ return isinstance(self._uid, UserAttribute) @property def selfsig(self): """ This will be the most recent, self-signature of this User ID or Attribute. If there isn't one, this will be ``None``. """ if self.parent is not None: return next((sig for sig in reversed(self._signatures) if sig.signer == self.parent.fingerprint.keyid), None) @property def signers(self): """ This will be a set of all of the key ids which have signed this User ID or Attribute. """ return set(s.signer for s in self.__sig__) @property def hashdata(self): if self.is_uid: return self._uid.__bytearray__()[len(self._uid.header):] if self.is_ua: return self._uid.subpackets.__bytearray__() @property def third_party_certifications(self): ''' A generator returning all third-party certifications ''' if self.parent is None: return fpr = self.parent.fingerprint keyid = self.parent.fingerprint.keyid for sig in self._signatures: if (sig.signer_fingerprint != '' and fpr != sig.signer_fingerprint) or (sig.signer != keyid): yield sig def attested_to(self, certifications): '''filter certifications, only returning those that have been attested to by the first party''' # first find the set of the most recent valid Attestation Key Signatures: if self.parent is None: return mostrecent = None attestations = [] now = datetime.utcnow() fpr = self.parent.fingerprint keyid = self.parent.fingerprint.keyid for sig in self._signatures: if sig._signature.sigtype == SignatureType.Attestation and \ ((sig.signer_fingerprint == fpr) or (sig.signer == keyid)) and \ self.parent.verify(self, sig) and \ sig.created <= now: if mostrecent is None or sig.created > mostrecent: attestations = [sig] mostrecent = sig.created elif sig.created == mostrecent: attestations.append(sig) # now filter the certifications: for certification in certifications: for a in attestations: if a.attests_to(certification): yield certification @property def attested_third_party_certifications(self): ''' A generator that provides a list of all third-party certifications attested to by the primary key. ''' return self.attested_to(self.third_party_certifications) @classmethod def new(cls, pn, comment="", email=""): """ Create a new User ID or photo. :param pn: User ID name, or photo. If this is a ``bytearray``, it will be loaded as a photo. Otherwise, it will be used as the name field for a User ID. :type pn: ``bytearray``, ``str``, ``unicode`` :param comment: The comment field for a User ID. Ignored if this is a photo. :type comment: ``str``, ``unicode`` :param email: The email address field for a User ID. Ignored if this is a photo. :type email: ``str``, ``unicode`` :returns: :py:obj:`PGPUID` """ uid = PGPUID() if isinstance(pn, bytearray): uid._uid = UserAttribute() uid._uid.image.image = pn uid._uid.image.iencoding = ImageEncoding.encodingof(pn) uid._uid.update_hlen() else: uid._uid = UserID() uidstr = pn if comment: uidstr += ' (' + comment + ')' if email: uidstr += ' <' + email + '>' uid._uid.uid = uidstr uid._uid.update_hlen() return uid def __init__(self): """ PGPUID objects represent User IDs and User Attributes for keys. PGPUID implements the ``__format__`` method for User IDs, returning a string in the format 'name (comment) ', leaving out any comment or email fields that are not present. """ super(PGPUID, self).__init__() self._uid = None self._signatures = SorteDeque() def __repr__(self): if self.selfsig is not None: return "".format(self._uid.__class__.__name__, self.selfsig.created, id(self)) return "".format(self._uid.__class__.__name__, id(self)) def __lt__(self, other): # pragma: no cover if self.is_uid == other.is_uid: if self.is_primary == other.is_primary: mysig = self.selfsig othersig = other.selfsig if mysig is None: return not (othersig is None) if othersig is None: return False return mysig > othersig if self.is_primary: return True return False if self.is_uid and other.is_ua: return True if self.is_ua and other.is_uid: return False def __or__(self, other): if isinstance(other, PGPSignature): self._signatures.insort(other) if self.parent is not None and self in self.parent._uids: self.parent._uids.resort(self) return self if isinstance(other, UserID) and self._uid is None: self._uid = other return self if isinstance(other, UserAttribute) and self._uid is None: self._uid = other return self raise TypeError("unsupported operand type(s) for |: '{:s}' and '{:s}'" "".format(self.__class__.__name__, other.__class__.__name__)) def __copy__(self): # because the default shallow copy isn't actually all that useful, # and deepcopy does too much work uid = PGPUID() uid |= copy.copy(self._uid) for sig in self._signatures: uid |= copy.copy(sig) return uid def __format__(self, format_spec): if self.is_uid: comment = six.u("") if self.comment == "" else six.u(" ({:s})").format(self.comment) email = six.u("") if self.email == "" else six.u(" <{:s}>").format(self.email) return six.u("{:s}{:s}{:s}").format(self.name, comment, email) raise NotImplementedError class PGPMessage(Armorable, PGPObject): @staticmethod def dash_unescape(text): return re.subn(r'^- ', '', text, flags=re.MULTILINE)[0] @staticmethod def dash_escape(text): return re.subn(r'^-', '- -', text, flags=re.MULTILINE)[0] @property def encrypters(self): """A ``set`` containing all key ids (if any) to which this message was encrypted.""" return set(m.encrypter for m in self._sessionkeys if isinstance(m, PKESessionKey)) @property def filename(self): """If applicable, returns the original filename of the message. Otherwise, returns an empty string.""" if self.type == 'literal': return self._message.filename return '' @property def is_compressed(self): """``True`` if this message will be compressed when exported""" return self._compression != CompressionAlgorithm.Uncompressed @property def is_encrypted(self): """``True`` if this message is encrypted; otherwise, ``False``""" return isinstance(self._message, (SKEData, IntegrityProtectedSKEData)) @property def is_sensitive(self): """``True`` if this message is marked sensitive; otherwise ``False``""" return self.type == 'literal' and self._message.filename == '_CONSOLE' @property def is_signed(self): """ ``True`` if this message is signed; otherwise, ``False``. Should always be ``False`` if the message is encrypted. """ return len(self._signatures) > 0 @property def issuers(self): """A ``set`` containing all key ids (if any) which have signed or encrypted this message.""" return self.encrypters | self.signers @property def magic(self): if self.type == 'cleartext': return "SIGNATURE" return "MESSAGE" @property def message(self): """The message contents""" if self.type == 'cleartext': return self.bytes_to_text(self._message) if self.type == 'literal': return self._message.contents if self.type == 'encrypted': return self._message @property def signatures(self): """A ``set`` containing all key ids (if any) which have signed this message.""" return list(self._signatures) @property def signers(self): """A ``set`` containing all key ids (if any) which have signed this message.""" return set(m.signer for m in self._signatures) @property def type(self): ##TODO: it might be better to use an Enum for the output of this if isinstance(self._message, (six.string_types, six.binary_type, bytearray)): return 'cleartext' if isinstance(self._message, LiteralData): return 'literal' if isinstance(self._message, (SKEData, IntegrityProtectedSKEData)): return 'encrypted' raise NotImplementedError def __init__(self): """ PGPMessage objects represent OpenPGP message compositions. PGPMessage implements the ``__str__`` method, the output of which will be the message composition in OpenPGP-compliant ASCII-armored format. PGPMessage implements the ``__bytes__`` method, the output of which will be the message composition in OpenPGP-compliant binary format. Any signatures within the PGPMessage that are marked as being non-exportable will not be included in the output of either of those methods. """ super(PGPMessage, self).__init__() self._compression = CompressionAlgorithm.Uncompressed self._message = None self._mdc = None self._signatures = SorteDeque() self._sessionkeys = [] def __bytearray__(self): if self.is_compressed: comp = CompressedData() comp.calg = self._compression comp.packets = [pkt for pkt in self] comp.update_hlen() return comp.__bytearray__() _bytes = bytearray() for pkt in self: _bytes += pkt.__bytearray__() return _bytes def __str__(self): if self.type == 'cleartext': tmpl = u"-----BEGIN PGP SIGNED MESSAGE-----\n" \ u"{hhdr:s}\n" \ u"{cleartext:s}\n" \ u"{signature:s}" # only add a Hash: header if we actually have at least one signature hashes = set(s.hash_algorithm.name for s in self.signatures) hhdr = 'Hash: {hashes:s}\n'.format(hashes=','.join(sorted(hashes))) if hashes else '' return tmpl.format(hhdr=hhdr, cleartext=self.dash_escape(self.bytes_to_text(self._message)), signature=super(PGPMessage, self).__str__()) return super(PGPMessage, self).__str__() def __iter__(self): if self.type == 'cleartext': for sig in self._signatures: yield sig elif self.is_encrypted: for sig in self._signatures: yield sig for pkt in self._sessionkeys: yield pkt yield self.message else: ##TODO: is it worth coming up with a way of disabling one-pass signing? for sig in reversed(self._signatures): ops = sig.make_onepass() if sig is not self._signatures[-1]: ops.nested = True yield ops yield self._message if self._mdc is not None: # pragma: no cover yield self._mdc for sig in self._signatures: yield sig def __or__(self, other): if isinstance(other, Marker): return self if isinstance(other, CompressedData): self._compression = other.calg for pkt in other.packets: self |= pkt return self if isinstance(other, (six.string_types, six.binary_type, bytearray)): if self._message is None: self._message = self.text_to_bytes(other) return self if isinstance(other, (LiteralData, SKEData, IntegrityProtectedSKEData)): if self._message is None: self._message = other return self if isinstance(other, MDC): if self._mdc is None: self._mdc = other return self if isinstance(other, OnePassSignature): # these are "generated" on the fly during composition return self if isinstance(other, Signature): other = PGPSignature() | other if isinstance(other, PGPSignature): self._signatures.insort(other) return self if isinstance(other, (PKESessionKey, SKESessionKey)): self._sessionkeys.append(other) return self if isinstance(other, PGPMessage): self._message = other._message self._mdc = other._mdc self._compression = other._compression self._sessionkeys += other._sessionkeys self._signatures += other._signatures return self raise NotImplementedError(str(type(other))) def __copy__(self): msg = super(PGPMessage, self).__copy__() msg._compression = self._compression msg._message = copy.copy(self._message) msg._mdc = copy.copy(self._mdc) for sig in self._signatures: msg |= copy.copy(sig) for sk in self._sessionkeys: msg |= copy.copy(sk) return msg @classmethod def new(cls, message, **kwargs): """ Create a new PGPMessage object. :param message: The message to be stored. :type message: ``str``, ``unicode``, ``bytes``, ``bytearray`` :returns: :py:obj:`PGPMessage` The following optional keyword arguments can be used with :py:meth:`PGPMessage.new`: :keyword file: if True, ``message`` should be a path to a file. The contents of that file will be read and used as the contents of the message. :type file: ``bool`` :keyword cleartext: if True, the message will be cleartext with inline signatures. :type cleartext: ``bool`` :keyword sensitive: if True, the filename will be set to '_CONSOLE' to signal other OpenPGP clients to treat this message as being 'for your eyes only'. Ignored if cleartext is True. :type sensitive: ``bool`` :keyword format: Set the message format identifier. Ignored if cleartext is True. :type format: ``str`` :keyword compression: Set the compression algorithm for the new message. Defaults to :py:obj:`CompressionAlgorithm.ZIP`. Ignored if cleartext is True. :keyword encoding: Set the Charset header for the message. :type encoding: ``str`` representing a valid codec in codecs """ # TODO: have 'codecs' above (in :type encoding:) link to python documentation page on codecs cleartext = kwargs.pop('cleartext', False) format = kwargs.pop('format', None) sensitive = kwargs.pop('sensitive', False) compression = kwargs.pop('compression', CompressionAlgorithm.ZIP) file = kwargs.pop('file', False) charset = kwargs.pop('encoding', None) filename = '' mtime = datetime.utcnow() msg = PGPMessage() if charset: msg.charset = charset # if format in 'tu' and isinstance(message, (six.binary_type, bytearray)): # # if message format is text or unicode and we got binary data, we'll need to transcode it to UTF-8 # message = if file and os.path.isfile(message): filename = message message = bytearray(os.path.getsize(filename)) mtime = datetime.utcfromtimestamp(os.path.getmtime(filename)) with open(filename, 'rb') as mf: mf.readinto(message) # if format is None, we can try to detect it if format is None: if isinstance(message, six.text_type): # message is definitely UTF-8 already format = 'u' elif cls.is_ascii(message): # message is probably text format = 't' else: # message is probably binary format = 'b' # if message is a binary type and we're building a textual message, we need to transcode the bytes to UTF-8 if isinstance(message, (six.binary_type, bytearray)) and (cleartext or format in 'tu'): message = message.decode(charset or 'utf-8') if cleartext: msg |= message else: # load literal data lit = LiteralData() lit._contents = bytearray(msg.text_to_bytes(message)) lit.filename = '_CONSOLE' if sensitive else os.path.basename(filename) lit.mtime = mtime lit.format = format # if cls.is_ascii(message): # lit.format = 't' lit.update_hlen() msg |= lit msg._compression = compression return msg def encrypt(self, passphrase, sessionkey=None, **prefs): """ encrypt(passphrase, [sessionkey=None,] **prefs) Encrypt the contents of this message using a passphrase. :param passphrase: The passphrase to use for encrypting this message. :type passphrase: ``str``, ``unicode``, ``bytes`` :param sessionkey: Provide a session key to use when encrypting something. Default is ``None``. If ``None``, a session key of the appropriate length will be generated randomly. .. warning:: Care should be taken when making use of this option! Session keys *absolutely need* to be unpredictable! Use the ``gen_key()`` method on the desired :py:obj:`~constants.SymmetricKeyAlgorithm` to generate the session key! :type sessionkey: ``bytes``, ``str`` :raises: :py:exc:`~errors.PGPEncryptionError` :returns: A new :py:obj:`PGPMessage` containing the encrypted contents of this message. """ cipher_algo = prefs.pop('cipher', SymmetricKeyAlgorithm.AES256) hash_algo = prefs.pop('hash', HashAlgorithm.SHA256) # set up a new SKESessionKeyV4 skesk = SKESessionKeyV4() skesk.s2k.usage = 255 skesk.s2k.specifier = 3 skesk.s2k.halg = hash_algo skesk.s2k.encalg = cipher_algo skesk.s2k.count = skesk.s2k.halg.tuned_count if sessionkey is None: sessionkey = cipher_algo.gen_key() skesk.encrypt_sk(passphrase, sessionkey) del passphrase msg = PGPMessage() | skesk if not self.is_encrypted: skedata = IntegrityProtectedSKEDataV1() skedata.encrypt(sessionkey, cipher_algo, self.__bytes__()) msg |= skedata else: msg |= self return msg def decrypt(self, passphrase): """ Attempt to decrypt this message using a passphrase. :param passphrase: The passphrase to use to attempt to decrypt this message. :type passphrase: ``str``, ``unicode``, ``bytes`` :raises: :py:exc:`~errors.PGPDecryptionError` if decryption failed for any reason. :returns: A new :py:obj:`PGPMessage` containing the decrypted contents of this message """ if not self.is_encrypted: raise PGPError("This message is not encrypted!") for skesk in iter(sk for sk in self._sessionkeys if isinstance(sk, SKESessionKey)): try: symalg, key = skesk.decrypt_sk(passphrase) decmsg = PGPMessage() decmsg.parse(self.message.decrypt(key, symalg)) except (TypeError, ValueError, NotImplementedError, PGPDecryptionError): continue else: del passphrase break else: raise PGPDecryptionError("Decryption failed") return decmsg def parse(self, packet): unarmored = self.ascii_unarmor(packet) data = unarmored['body'] if unarmored['magic'] is not None and unarmored['magic'] not in ['MESSAGE', 'SIGNATURE']: raise ValueError('Expected: MESSAGE. Got: {}'.format(str(unarmored['magic']))) if unarmored['headers'] is not None: self.ascii_headers = unarmored['headers'] # cleartext signature if unarmored['magic'] == 'SIGNATURE': # the composition for this will be the 'cleartext' as a str, # followed by one or more signatures (each one loaded into a PGPSignature) self |= self.dash_unescape(unarmored['cleartext']) while len(data) > 0: pkt = Packet(data) if not isinstance(pkt, Signature): # pragma: no cover warnings.warn("Discarded unexpected packet: {:s}".format(pkt.__class__.__name__), stacklevel=2) continue self |= PGPSignature() | pkt else: while len(data) > 0: self |= Packet(data) class PGPKey(Armorable, ParentRef, PGPObject): """ 11.1. Transferable Public Keys OpenPGP users may transfer public keys. The essential elements of a transferable public key are as follows: - One Public-Key packet - Zero or more revocation signatures - One or more User ID packets - After each User ID packet, zero or more Signature packets (certifications) - Zero or more User Attribute packets - After each User Attribute packet, zero or more Signature packets (certifications) - Zero or more Subkey packets - After each Subkey packet, one Signature packet, plus optionally a revocation The Public-Key packet occurs first. Each of the following User ID packets provides the identity of the owner of this public key. If there are multiple User ID packets, this corresponds to multiple means of identifying the same unique individual user; for example, a user may have more than one email address, and construct a User ID for each one. Immediately following each User ID packet, there are zero or more Signature packets. Each Signature packet is calculated on the immediately preceding User ID packet and the initial Public-Key packet. The signature serves to certify the corresponding public key and User ID. In effect, the signer is testifying to his or her belief that this public key belongs to the user identified by this User ID. Within the same section as the User ID packets, there are zero or more User Attribute packets. Like the User ID packets, a User Attribute packet is followed by zero or more Signature packets calculated on the immediately preceding User Attribute packet and the initial Public-Key packet. User Attribute packets and User ID packets may be freely intermixed in this section, so long as the signatures that follow them are maintained on the proper User Attribute or User ID packet. After the User ID packet or Attribute packet, there may be zero or more Subkey packets. In general, subkeys are provided in cases where the top-level public key is a signature-only key. However, any V4 key may have subkeys, and the subkeys may be encryption-only keys, signature-only keys, or general-purpose keys. V3 keys MUST NOT have subkeys. Each Subkey packet MUST be followed by one Signature packet, which should be a subkey binding signature issued by the top-level key. For subkeys that can issue signatures, the subkey binding signature MUST contain an Embedded Signature subpacket with a primary key binding signature (0x19) issued by the subkey on the top-level key. Subkey and Key packets may each be followed by a revocation Signature packet to indicate that the key is revoked. Revocation signatures are only accepted if they are issued by the key itself, or by a key that is authorized to issue revocations via a Revocation Key subpacket in a self-signature by the top-level key. Transferable public-key packet sequences may be concatenated to allow transferring multiple public keys in one operation. 11.2. Transferable Secret Keys OpenPGP users may transfer secret keys. The format of a transferable secret key is the same as a transferable public key except that secret-key and secret-subkey packets are used instead of the public key and public-subkey packets. Implementations SHOULD include self- signatures on any user IDs and subkeys, as this allows for a complete public key to be automatically extracted from the transferable secret key. Implementations MAY choose to omit the self-signatures, especially if a transferable public key accompanies the transferable secret key. """ @property def __key__(self): return self._key.keymaterial @property def __sig__(self): return list(self._signatures) @property def created(self): """A :py:obj:`~datetime.datetime` object of the creation date and time of the key, in UTC.""" return self._key.created @property def expires_at(self): """A :py:obj:`~datetime.datetime` object of when this key is to be considered expired, if any. Otherwise, ``None``""" try: expires = min(sig.key_expiration for sig in itertools.chain(iter(uid.selfsig for uid in self.userids), self.self_signatures) if sig.key_expiration is not None) except ValueError: return None else: return (self.created + expires) @property def fingerprint(self): """The fingerprint of this key, as a :py:obj:`~pgpy.types.Fingerprint` object.""" if self._key: return self._key.fingerprint @property def hashdata(self): # when signing a key, only the public portion of the keys is hashed # if this is a private key, the private components of the key material need to be left out pub = self._key if self.is_public else self._key.pubkey() return pub.__bytearray__()[len(pub.header):] @property def is_expired(self): """``True`` if this key is expired, otherwise ``False``""" expires = self.expires_at if expires is not None: return expires <= datetime.utcnow() return False @property def is_primary(self): """``True`` if this is a primary key; ``False`` if this is a subkey""" return isinstance(self._key, Primary) and not isinstance(self._key, Sub) @property def is_protected(self): """``True`` if this is a private key that is protected with a passphrase, otherwise ``False``""" if self.is_public: return False return self._key.protected @property def is_public(self): """``True`` if this is a public key, otherwise ``False``""" return isinstance(self._key, Public) and not isinstance(self._key, Private) @property def is_unlocked(self): """``False`` if this is a private key that is protected with a passphrase and has not yet been unlocked, otherwise ``True``""" if self.is_public: return True if not self.is_protected: return True return self._key.unlocked @property def key_algorithm(self): """The :py:obj:`constants.PubKeyAlgorithm` pertaining to this key""" return self._key.pkalg @property def key_size(self): """ The size pertaining to this key. ``int`` for non-EC key algorithms; :py:obj:`constants.EllipticCurveOID` for EC keys. .. versionadded:: 0.4.1 """ if self.key_algorithm in {PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.ECDH, PubKeyAlgorithm.EdDSA}: return self._key.keymaterial.oid # check if keymaterial is not an Opaque class containing a bytearray param = next(iter(self._key.keymaterial)) if isinstance(param, bytearray): return 0 return param.bit_length() @property def magic(self): return '{:s} KEY BLOCK'.format('PUBLIC' if (isinstance(self._key, Public) and not isinstance(self._key, Private)) else 'PRIVATE' if isinstance(self._key, Private) else '') @property def pubkey(self): """If the :py:obj:`PGPKey` object is a private key, this method returns a corresponding public key object with all the trimmings. If it is already a public key, just return it. """ if self.is_public: return self if self._sibling is None or isinstance(self._sibling, weakref.ref): # create a new key shell pub = PGPKey() pub.ascii_headers = self.ascii_headers.copy() # get the public half of the primary key pub._key = self._key.pubkey() # get the public half of each subkey for skid, subkey in self.subkeys.items(): pub |= subkey.pubkey # copy user ids and user attributes for uid in self._uids: pub |= copy.copy(uid) # copy signatures that weren't copied with uids for sig in self._signatures: if sig.parent is None: pub |= copy.copy(sig) # keep connect the two halves using a weak reference self._sibling = weakref.ref(pub) pub._sibling = weakref.ref(self) # copy parent if self.parent: pub._parent = weakref.ref(self.parent) return self._sibling() @pubkey.setter def pubkey(self, pubkey): if self.is_public: raise TypeError("cannot add public sibling to pubkey") if not pubkey.is_public: raise TypeError("sibling must be public") if self._sibling is not None and self._sibling() is not None: raise ValueError("public key reference already set") if pubkey.fingerprint != self.fingerprint: raise ValueError("key fingerprint mismatch") # TODO: sync packets with sibling self._sibling = weakref.ref(pubkey) pubkey._sibling = weakref.ref(self) @property def self_signatures(self): keyid, keytype = (self.fingerprint.keyid, SignatureType.DirectlyOnKey) if self.is_primary \ else (self.parent.fingerprint.keyid, SignatureType.Subkey_Binding) ##TODO: filter out revoked signatures as well for sig in iter(sig for sig in self._signatures if all([sig.type == keytype, sig.signer == keyid, not sig.is_expired])): yield sig @property def signers(self): """A ``set`` of key ids of keys that were used to sign this key""" return {sig.signer for sig in self.__sig__} @property def revocation_signatures(self): keyid, keytype = (self.fingerprint.keyid, SignatureType.KeyRevocation) if self.is_primary \ else (self.parent.fingerprint.keyid, SignatureType.SubkeyRevocation) for sig in iter(sig for sig in self._signatures if all([sig.type == keytype, sig.signer == keyid, not sig.is_expired])): yield sig @property def subkeys(self): """An :py:obj:`~collections.OrderedDict` of subkeys bound to this primary key, if applicable, selected by 16-character keyid.""" return self._children @property def userids(self): """A ``list`` of :py:obj:`PGPUID` objects containing User ID information about this key""" return [ u for u in self._uids if u.is_uid ] @property def userattributes(self): """A ``list`` of :py:obj:`PGPUID` objects containing one or more images associated with this key""" return [u for u in self._uids if u.is_ua] @property def revocation_keys(self): """A ``generator`` with the list of keys that can revoke this key. See also :py:func:`PGPSignature.revocation_key`""" for sig in self._signatures: if sig.revocation_key: yield sig.revocation_key @classmethod def new(cls, key_algorithm, key_size, created=None): """ Generate a new PGP key :param key_algorithm: Key algorithm to use. :type key_algorithm: :py:obj:`~constants.PubKeyAlgorithm` :param key_size: Key size in bits, unless `key_algorithm` is :py:obj:`~constants.PubKeyAlgorithm.ECDSA` or :py:obj:`~constants.PubKeyAlgorithm.ECDH`, in which case it should be the Curve OID to use. :type key_size: ``int`` or :py:obj:`~constants.EllipticCurveOID` :param created: When was the key created? (``None`` or unset means now) :type created: :py:obj:`~datetime.datetime` or ``None`` :return: A newly generated :py:obj:`PGPKey` """ # new private key shell first key = PGPKey() if key_algorithm in {PubKeyAlgorithm.RSAEncrypt, PubKeyAlgorithm.RSASign}: # pragma: no cover warnings.warn('{:s} is deprecated - generating key using RSAEncryptOrSign'.format(key_algorithm.name)) key_algorithm = PubKeyAlgorithm.RSAEncryptOrSign # generate some key data to match key_algorithm and key_size key._key = PrivKeyV4.new(key_algorithm, key_size, created=created) return key def __init__(self): """ PGPKey objects represent OpenPGP compliant keys along with all of their associated data. PGPKey implements the `__str__` method, the output of which will be the key composition in OpenPGP-compliant ASCII-armored format. PGPKey implements the `__bytes__` method, the output of which will be the key composition in OpenPGP-compliant binary format. Any signatures within the PGPKey that are marked as being non-exportable will not be included in the output of either of those methods. """ super(PGPKey, self).__init__() self._key = None self._children = collections.OrderedDict() self._signatures = SorteDeque() self._uids = SorteDeque() self._sibling = None def __bytearray__(self): _bytes = bytearray() # us _bytes += self._key.__bytearray__() # our signatures; ignore embedded signatures for sig in iter(s for s in self._signatures if not s.embedded and s.exportable): _bytes += sig.__bytearray__() # one or more User IDs, followed by their signatures for uid in self._uids: _bytes += uid._uid.__bytearray__() for s in [s for s in uid._signatures if s.exportable]: _bytes += s.__bytearray__() # subkeys for sk in self._children.values(): _bytes += sk.__bytearray__() return _bytes def __repr__(self): if self._key is not None: return "" \ "".format(self._key.__class__.__name__, self.fingerprint.keyid, id(self)) return "" \ "".format(id(self)) def __contains__(self, item): if isinstance(item, PGPKey): # pragma: no cover return item.fingerprint.keyid in self.subkeys if isinstance(item, Fingerprint): # pragma: no cover return item.keyid in self.subkeys if isinstance(item, PGPUID): return item in self._uids if isinstance(item, PGPSignature): return item in self._signatures raise TypeError def __or__(self, other, from_sib=False): if isinstance(other, Key) and self._key is None: self._key = other elif isinstance(other, PGPKey) and not other.is_primary and other.is_public == self.is_public: other._parent = self self._children[other.fingerprint.keyid] = other elif isinstance(other, PGPSignature): self._signatures.insort(other) # if this is a subkey binding signature that has embedded primary key binding signatures, add them to parent if other.type == SignatureType.Subkey_Binding: for es in iter(pkb for pkb in other._signature.subpackets['EmbeddedSignature']): esig = PGPSignature() | es esig._parent = other self._signatures.insort(esig) elif isinstance(other, PGPUID): other._parent = weakref.ref(self) self._uids.insort(other) else: raise TypeError("unsupported operand type(s) for |: '{:s}' and '{:s}'" "".format(self.__class__.__name__, other.__class__.__name__)) if isinstance(self._sibling, weakref.ref) and not from_sib: sib = self._sibling() if sib is None: self._sibling = None else: # pragma: no cover sib.__or__(copy.copy(other), True) return self def __copy__(self): key = super(PGPKey, self).__copy__() key._key = copy.copy(self._key) for uid in self._uids: key |= copy.copy(uid) for id, subkey in self._children.items(): key |= copy.copy(subkey) for sig in self._signatures: if sig.embedded: # embedded signatures don't need to be explicitly copied continue key |= copy.copy(sig) return key def protect(self, passphrase, enc_alg, hash_alg): """ Add a passphrase to a private key. If the key is already passphrase protected, it should be unlocked before a new passphrase can be specified. Has no effect on public keys. :param passphrase: A passphrase to protect the key with :type passphrase: ``str``, ``unicode`` :param enc_alg: Symmetric encryption algorithm to use to protect the key :type enc_alg: :py:obj:`~constants.SymmetricKeyAlgorithm` :param hash_alg: Hash algorithm to use in the String-to-Key specifier :type hash_alg: :py:obj:`~constants.HashAlgorithm` """ ##TODO: specify strong defaults for enc_alg and hash_alg if self.is_public: # we can't protect public keys because only private key material is ever protected warnings.warn("Public keys cannot be passphrase-protected", stacklevel=2) return if self.is_protected and not self.is_unlocked: # we can't protect a key that is already protected unless it is unlocked first warnings.warn("This key is already protected with a passphrase - " "please unlock it before attempting to specify a new passphrase", stacklevel=2) return for sk in itertools.chain([self], self.subkeys.values()): sk._key.protect(passphrase, enc_alg, hash_alg) del passphrase @contextlib.contextmanager def unlock(self, passphrase): """ Context manager method for unlocking passphrase-protected private keys. Has no effect if the key is not both private and passphrase-protected. When the context managed block is exited, the unprotected private key material is removed. Example:: privkey = PGPKey() privkey.parse(keytext) assert privkey.is_protected assert privkey.is_unlocked is False # privkey.sign("some text") <- this would raise an exception with privkey.unlock("TheCorrectPassphrase"): # privkey is now unlocked assert privkey.is_unlocked # so you can do things with it sig = privkey.sign("some text") # privkey is no longer unlocked assert privkey.is_unlocked is False Emits a :py:obj:`~warnings.UserWarning` if the key is public or not passphrase protected. :param passphrase: The passphrase to be used to unlock this key. :type passphrase: ``str`` :raises: :py:exc:`~pgpy.errors.PGPDecryptionError` if the passphrase is incorrect """ if self.is_public: # we can't unprotect public keys because only private key material is ever protected warnings.warn("Public keys cannot be passphrase-protected", stacklevel=3) yield self return if not self.is_protected: # we can't unprotect private keys that are not protected, because there is no ciphertext to decrypt warnings.warn("This key is not protected with a passphrase", stacklevel=3) yield self return try: for sk in itertools.chain([self], self.subkeys.values()): sk._key.unprotect(passphrase) del passphrase yield self finally: # clean up here by deleting the previously decrypted secret key material for sk in itertools.chain([self], self.subkeys.values()): sk._key.keymaterial.clear() def add_uid(self, uid, selfsign=True, **prefs): """ Add a User ID to this key. :param uid: The user id to add :type uid: :py:obj:`~pgpy.PGPUID` :param selfsign: Whether or not to self-sign the user id before adding it :type selfsign: ``bool`` Valid optional keyword arguments are identical to those of self-signatures for :py:meth:`PGPKey.certify`. Any such keyword arguments are ignored if selfsign is ``False`` """ uid._parent = self if selfsign: uid |= self.certify(uid, SignatureType.Positive_Cert, **prefs) self |= uid def get_uid(self, search): """ Find and return a User ID that matches the search string given. :param search: A text string to match name, comment, or email address against :type search: ``str``, ``unicode`` :return: The first matching :py:obj:`~pgpy.PGPUID`, or ``None`` if no matches were found. """ if self.is_primary: return next((u for u in self._uids if search in filter(lambda a: a is not None, (u.name, u.comment, u.email))), None) return self.parent.get_uid(search) def del_uid(self, search): """ Find and remove a user id that matches the search string given. This method does not modify the corresponding :py:obj:`~pgpy.PGPUID` object; it only removes it from the list of user ids on the key. :param search: A text string to match name, comment, or email address against :type search: ``str``, ``unicode`` """ u = self.get_uid(search) if u is None: raise KeyError("uid '{:s}' not found".format(search)) u._parent = None self._uids.remove(u) def add_subkey(self, key, **prefs): """ Add a key as a subkey to this key. :param key: A private :py:obj:`~pgpy.PGPKey` that does not have any subkeys of its own :keyword usage: A ``set`` of key usage flags, as :py:obj:`~constants.KeyFlags` for the subkey to be added. :type usage: ``set`` Other valid optional keyword arguments are identical to those of self-signatures for :py:meth:`PGPKey.certify` """ if self.is_public: raise PGPError("Cannot add a subkey to a public key. Add the subkey to the private component first!") if key.is_public: raise PGPError("Cannot add a public key as a subkey to this key") if key.is_primary: if len(key._children) > 0: raise PGPError("Cannot add a key that already has subkeys as a subkey!") # convert key into a subkey npk = PrivSubKeyV4() npk.pkalg = key._key.pkalg npk.created = key._key.created npk.keymaterial = key._key.keymaterial key._key = npk key._key.update_hlen() self._children[key.fingerprint.keyid] = key key._parent = self ##TODO: skip this step if the key already has a subkey binding signature bsig = self.bind(key, **prefs) key |= bsig def _get_key_flags(self, user=None): if self.is_primary: if user is not None: user = self.get_uid(user) elif len(self._uids) == 0: return {KeyFlags.Certify} else: user = next(iter(self.userids)) # RFC 4880 says that primary keys *must* be capable of certification return {KeyFlags.Certify} | user.selfsig.key_flags return next(self.self_signatures).key_flags def _sign(self, subject, sig, **prefs): """ The actual signing magic happens here. :param subject: The subject to sign :param sig: The :py:obj:`PGPSignature` object the new signature is to be encapsulated within :returns: ``sig``, after the signature is added to it. """ user = prefs.pop('user', None) uid = None if user is not None: uid = self.get_uid(user) else: uid = next(iter(self.userids), None) if uid is None and self.parent is not None: uid = next(iter(self.parent.userids), None) if sig.hash_algorithm is None: sig._signature.halg = next((h for h in uid.selfsig.hashprefs if h.is_supported), HashAlgorithm.SHA256) if uid is not None and sig.hash_algorithm not in uid.selfsig.hashprefs: warnings.warn("Selected hash algorithm not in key preferences", stacklevel=4) # signature options that can be applied at any level expires = prefs.pop('expires', None) notation = prefs.pop('notation', None) revocable = prefs.pop('revocable', True) policy_uri = prefs.pop('policy_uri', None) intended_recipients = prefs.pop('intended_recipients', []) for intended_recipient in intended_recipients: if isinstance(intended_recipient, PGPKey) and isinstance(intended_recipient._key, PubKeyV4): sig._signature.subpackets.addnew('IntendedRecipient', hashed=True, version=4, intended_recipient=intended_recipient.fingerprint) elif isinstance(intended_recipient, Fingerprint): # FIXME: what if it's not a v4 fingerprint? sig._signature.subpackets.addnew('IntendedRecipient', hashed=True, version=4, intended_recipient=intended_recipient) else: warnings.warn("Intended Recipient is not a PGPKey, ignoring") if expires is not None: # expires should be a timedelta, so if it's a datetime, turn it into a timedelta if isinstance(expires, datetime): expires = expires - self.created sig._signature.subpackets.addnew('SignatureExpirationTime', hashed=True, expires=expires) if revocable is False: sig._signature.subpackets.addnew('Revocable', hashed=True, bflag=revocable) if notation is not None: for name, value in notation.items(): # mark all notations as human readable unless value is a bytearray flags = NotationDataFlags.HumanReadable if isinstance(value, bytearray): flags = 0x00 sig._signature.subpackets.addnew('NotationData', hashed=True, flags=flags, name=name, value=value) if policy_uri is not None: sig._signature.subpackets.addnew('Policy', hashed=True, uri=policy_uri) if user is not None and uid is not None: signers_uid = "{:s}".format(uid) sig._signature.subpackets.addnew('SignersUserID', hashed=True, userid=signers_uid) # handle an edge case for timestamp signatures vs standalone signatures if sig.type == SignatureType.Timestamp and len(sig._signature.subpackets._hashed_sp) > 1: sig._signature.sigtype = SignatureType.Standalone if prefs.pop('include_issuer_fingerprint', True): if isinstance(self._key, PrivKeyV4): sig._signature.subpackets.addnew('IssuerFingerprint', hashed=True, _version=4, _issuer_fpr=self.fingerprint) sigdata = sig.hashdata(subject) h2 = sig.hash_algorithm.hasher h2.update(sigdata) sig._signature.hash2 = bytearray(h2.digest()[:2]) _sig = self._key.sign(sigdata, getattr(hashes, sig.hash_algorithm.name)()) if _sig is NotImplemented: raise NotImplementedError(self.key_algorithm) sig._signature.signature.from_signer(_sig) sig._signature.update_hlen() return sig @KeyAction(KeyFlags.Sign, is_unlocked=True, is_public=False) def sign(self, subject, **prefs): """ Sign text, a message, or a timestamp using this key. :param subject: The text to be signed :type subject: ``str``, :py:obj:`~pgpy.PGPMessage`, ``None`` :raises: :py:exc:`~pgpy.errors.PGPError` if the key is passphrase-protected and has not been unlocked :raises: :py:exc:`~pgpy.errors.PGPError` if the key is public :returns: :py:obj:`PGPSignature` The following optional keyword arguments can be used with :py:meth:`PGPKey.sign`, as well as :py:meth:`PGPKey.certify`, :py:meth:`PGPKey.revoke`, and :py:meth:`PGPKey.bind`: :keyword expires: Set an expiration date for this signature :type expires: :py:obj:`~datetime.datetime`, :py:obj:`~datetime.timedelta` :keyword notation: Add arbitrary notation data to this signature. :type notation: ``dict`` :keyword policy_uri: Add a URI to the signature that should describe the policy under which the signature was issued. :type policy_uri: ``str`` :keyword revocable: If ``False``, this signature will be marked non-revocable :type revocable: ``bool`` :keyword user: Specify which User ID to use when creating this signature. Also adds a "Signer's User ID" to the signature. :type user: ``str`` :keyword created: Specify the time that the signature should be made. If unset or None, it will use the present time. :type created: :py:obj:`~datetime.datetime` :keyword intended_recipients: Specify a list of :py:obj:`PGPKey` objects that will be encrypted to. :type intended_recipients: ``list`` :keyword include_issuer_fingerprint: Whether to include a hashed subpacket indicating the issuer fingerprint. (only for v4 keys, defaults to True) :type include_issuer_fingerprint: ``bool`` """ sig_type = SignatureType.BinaryDocument hash_algo = prefs.pop('hash', None) if subject is None: sig_type = SignatureType.Timestamp if isinstance(subject, PGPMessage): if subject.type == 'cleartext': sig_type = SignatureType.CanonicalDocument subject = subject.message sig = PGPSignature.new(sig_type, self.key_algorithm, hash_algo, self.fingerprint.keyid, created=prefs.pop('created', None)) return self._sign(subject, sig, **prefs) @KeyAction(KeyFlags.Certify, is_unlocked=True, is_public=False) def certify(self, subject, level=SignatureType.Generic_Cert, **prefs): """ certify(subject, level=SignatureType.Generic_Cert, **prefs) Sign a key or a user id within a key. :param subject: The user id or key to be certified. :type subject: :py:obj:`PGPKey`, :py:obj:`PGPUID` :param level: :py:obj:`~constants.SignatureType.Generic_Cert`, :py:obj:`~constants.SignatureType.Persona_Cert`, :py:obj:`~constants.SignatureType.Casual_Cert`, or :py:obj:`~constants.SignatureType.Positive_Cert`. Only used if subject is a :py:obj:`PGPUID`; otherwise, it is ignored. :raises: :py:exc:`~pgpy.errors.PGPError` if the key is passphrase-protected and has not been unlocked :raises: :py:exc:`~pgpy.errors.PGPError` if the key is public :returns: :py:obj:`PGPSignature` In addition to the optional keyword arguments accepted by :py:meth:`PGPKey.sign`, the following optional keyword arguments can be used with :py:meth:`PGPKey.certify`. These optional keywords only make sense, and thus only have an effect, when self-signing a key or User ID: :keyword usage: A ``set`` of key usage flags, as :py:obj:`~constants.KeyFlags`. This keyword is ignored for non-self-certifications. :type usage: ``set`` :keyword ciphers: A list of preferred symmetric ciphers, as :py:obj:`~constants.SymmetricKeyAlgorithm`. This keyword is ignored for non-self-certifications. :type ciphers: ``list`` :keyword hashes: A list of preferred hash algorithms, as :py:obj:`~constants.HashAlgorithm`. This keyword is ignored for non-self-certifications. :type hashes: ``list`` :keyword compression: A list of preferred compression algorithms, as :py:obj:`~constants.CompressionAlgorithm`. This keyword is ignored for non-self-certifications. :type compression: ``list`` :keyword key_expiration: Specify a key expiration date for when this key should expire, or a :py:obj:`~datetime.timedelta` of how long after the key was created it should expire. This keyword is ignored for non-self-certifications. :type key_expiration: :py:obj:`datetime.datetime`, :py:obj:`datetime.timedelta` :keyword attested_certifications: A list of third-party certifications, as :py:obj:`PGPSignature`, that the certificate holder wants to attest to for redistribution with the certificate. Alternatively, any element in the list can be a ``bytes`` or ``bytearray`` object of the appropriate length (the length of this certification's digest). This keyword is only used for signatures of type Attestation. :type attested_certifications: ``list`` :keyword keyserver: Specify the URI of the preferred key server of the user. This keyword is ignored for non-self-certifications. :type keyserver: ``str``, ``unicode``, ``bytes`` :keyword keyserver_flags: A set of Key Server Preferences, as :py:obj:`~constants.KeyServerPreferences`. :type keyserver_flags: ``set`` :keyword primary: Whether or not to consider the certified User ID as the primary one. This keyword is ignored for non-self-certifications, and any certifications directly on keys. :type primary: ``bool`` These optional keywords only make sense, and thus only have an effect, when signing another key or User ID: :keyword trust: Specify the level and amount of trust to assert when certifying a public key. Should be a tuple of two ``int`` s, specifying the trust level and trust amount. See `RFC 4880 Section 5.2.3.13. Trust Signature `_ for more on what these values mean. :type trust: ``tuple`` of two ``int`` s :keyword regex: Specify a regular expression to constrain the specified trust signature in the resulting signature. Symbolically signifies that the specified trust signature only applies to User IDs which match this regular expression. This is meaningless without also specifying trust level and amount. :type regex: ``str`` :keyword exportable: Whether this certification is exportable or not. :type exportable: ``bool`` """ hash_algo = prefs.pop('hash', None) sig_type = level if isinstance(subject, PGPKey): sig_type = SignatureType.DirectlyOnKey sig = PGPSignature.new(sig_type, self.key_algorithm, hash_algo, self.fingerprint.keyid, created=prefs.pop('created', None)) # signature options that only make sense in certifications usage = prefs.pop('usage', None) exportable = prefs.pop('exportable', None) if usage is not None: sig._signature.subpackets.addnew('KeyFlags', hashed=True, flags=usage) if exportable is not None: sig._signature.subpackets.addnew('ExportableCertification', hashed=True, bflag=exportable) keyfp = self.fingerprint if isinstance(subject, PGPKey): keyfp = subject.fingerprint if isinstance(subject, PGPUID) and subject._parent is not None: keyfp = subject._parent.fingerprint if keyfp == self.fingerprint: # signature options that only make sense in self-certifications cipher_prefs = prefs.pop('ciphers', None) hash_prefs = prefs.pop('hashes', None) compression_prefs = prefs.pop('compression', None) key_expires = prefs.pop('key_expiration', None) keyserver_flags = prefs.pop('keyserver_flags', None) keyserver = prefs.pop('keyserver', None) primary_uid = prefs.pop('primary', None) attested_certifications = prefs.pop('attested_certifications', []) if key_expires is not None: # key expires should be a timedelta, so if it's a datetime, turn it into a timedelta if isinstance(key_expires, datetime): key_expires = key_expires - self.created sig._signature.subpackets.addnew('KeyExpirationTime', hashed=True, expires=key_expires) if cipher_prefs is not None: sig._signature.subpackets.addnew('PreferredSymmetricAlgorithms', hashed=True, flags=cipher_prefs) if hash_prefs: sig._signature.subpackets.addnew('PreferredHashAlgorithms', hashed=True, flags=hash_prefs) if sig.hash_algorithm is None: sig._signature.halg = hash_prefs[0] if sig.hash_algorithm is None: sig._signature.halg = HashAlgorithm.SHA256 if compression_prefs is not None: sig._signature.subpackets.addnew('PreferredCompressionAlgorithms', hashed=True, flags=compression_prefs) if keyserver_flags is not None: sig._signature.subpackets.addnew('KeyServerPreferences', hashed=True, flags=keyserver_flags) if keyserver is not None: sig._signature.subpackets.addnew('PreferredKeyServer', hashed=True, uri=keyserver) if primary_uid is not None: sig._signature.subpackets.addnew('PrimaryUserID', hashed=True, primary=primary_uid) cert_sigtypes = {SignatureType.Generic_Cert, SignatureType.Persona_Cert, SignatureType.Casual_Cert, SignatureType.Positive_Cert, SignatureType.CertRevocation} # Features is always set on certifications: if sig._signature.sigtype in cert_sigtypes: sig._signature.subpackets.addnew('Features', hashed=True, flags=Features.pgpy_features) # If this is an attestation, then we must include a Attested Certifications subpacket: if sig._signature.sigtype == SignatureType.Attestation: attestations = set() for attestation in attested_certifications: if isinstance(attestation, PGPSignature) and attestation.type in cert_sigtypes: h = sig.hash_algorithm.hasher h.update(attestation._signature.canonical_bytes()) attestations.add(h.digest()) elif isinstance(attestation, (bytes,bytearray)) and len(attestation) == sig.hash_algorithm.digest_size: attestations.add(attestation) else: warnings.warn("Attested Certification element is neither a PGPSignature certification nor " + "a bytes object of size %d, ignoring"%(sig.hash_algorithm.digest_size)) sig._signature.subpackets.addnew('AttestedCertifications', hashed=True, attested_certifications=b''.join(sorted(attestations))) else: # signature options that only make sense in non-self-certifications trust = prefs.pop('trust', None) regex = prefs.pop('regex', None) if trust is not None: sig._signature.subpackets.addnew('TrustSignature', hashed=True, level=trust[0], amount=trust[1]) if regex is not None: sig._signature.subpackets.addnew('RegularExpression', hashed=True, regex=regex) return self._sign(subject, sig, **prefs) @KeyAction(KeyFlags.Certify, is_unlocked=True, is_public=False) def revoke(self, target, **prefs): """ Revoke a key, a subkey, or all current certification signatures of a User ID that were generated by this key so far. :param target: The key to revoke :type target: :py:obj:`PGPKey`, :py:obj:`PGPUID` :raises: :py:exc:`~pgpy.errors.PGPError` if the key is passphrase-protected and has not been unlocked :raises: :py:exc:`~pgpy.errors.PGPError` if the key is public :returns: :py:obj:`PGPSignature` In addition to the optional keyword arguments accepted by :py:meth:`PGPKey.sign`, the following optional keyword arguments can be used with :py:meth:`PGPKey.revoke`. :keyword reason: Defaults to :py:obj:`constants.RevocationReason.NotSpecified` :type reason: One of :py:obj:`constants.RevocationReason`. :keyword comment: Defaults to an empty string. :type comment: ``str`` """ hash_algo = prefs.pop('hash', None) if isinstance(target, PGPUID): sig_type = SignatureType.CertRevocation elif isinstance(target, PGPKey): ##TODO: check to make sure that the key that is being revoked: # - is this key # - is one of this key's subkeys # - specifies this key as its revocation key if target.is_primary: sig_type = SignatureType.KeyRevocation else: sig_type = SignatureType.SubkeyRevocation else: # pragma: no cover raise TypeError sig = PGPSignature.new(sig_type, self.key_algorithm, hash_algo, self.fingerprint.keyid, created=prefs.pop('created', None)) # signature options that only make sense when revoking reason = prefs.pop('reason', RevocationReason.NotSpecified) comment = prefs.pop('comment', "") sig._signature.subpackets.addnew('ReasonForRevocation', hashed=True, code=reason, string=comment) return self._sign(target, sig, **prefs) @KeyAction(is_unlocked=True, is_public=False) def revoker(self, revoker, **prefs): """ Generate a signature that specifies another key as being valid for revoking this key. :param revoker: The :py:obj:`PGPKey` to specify as a valid revocation key. :type revoker: :py:obj:`PGPKey` :raises: :py:exc:`~pgpy.errors.PGPError` if the key is passphrase-protected and has not been unlocked :raises: :py:exc:`~pgpy.errors.PGPError` if the key is public :returns: :py:obj:`PGPSignature` In addition to the optional keyword arguments accepted by :py:meth:`PGPKey.sign`, the following optional keyword arguments can be used with :py:meth:`PGPKey.revoker`. :keyword sensitive: If ``True``, this sets the sensitive flag on the RevocationKey subpacket. Currently, this has no other effect. :type sensitive: ``bool`` """ hash_algo = prefs.pop('hash', None) sig = PGPSignature.new(SignatureType.DirectlyOnKey, self.key_algorithm, hash_algo, self.fingerprint.keyid, created=prefs.pop('created', None)) # signature options that only make sense when adding a revocation key sensitive = prefs.pop('sensitive', False) keyclass = RevocationKeyClass.Normal | (RevocationKeyClass.Sensitive if sensitive else 0x00) sig._signature.subpackets.addnew('RevocationKey', hashed=True, algorithm=revoker.key_algorithm, fingerprint=revoker.fingerprint, keyclass=keyclass) # revocation keys should really not be revocable themselves prefs['revocable'] = False return self._sign(self, sig, **prefs) @KeyAction(is_unlocked=True, is_public=False) def bind(self, key, **prefs): """ Bind a subkey to this key. In addition to the optional keyword arguments accepted for self-signatures by :py:meth:`PGPkey.certify`, the following optional keyword arguments can be used with :py:meth:`PGPKey.bind`. :keyword crosssign: If ``False``, do not attempt a cross-signature (defaults to ``True``). Subkeys which are not capable of signing will not produce a cross-signature in any case. Setting ``crosssign`` to ``False`` is likely to produce subkeys that will be rejected by some other OpenPGP implementations. :type crosssign: ``bool`` """ hash_algo = prefs.pop('hash', None) if self.is_primary and not key.is_primary: sig_type = SignatureType.Subkey_Binding elif key.is_primary and not self.is_primary: sig_type = SignatureType.PrimaryKey_Binding else: # pragma: no cover raise PGPError sig = PGPSignature.new(sig_type, self.key_algorithm, hash_algo, self.fingerprint.keyid, created=prefs.pop('created', None)) if sig_type == SignatureType.Subkey_Binding: # signature options that only make sense in subkey binding signatures usage = prefs.pop('usage', None) if usage is not None: sig._signature.subpackets.addnew('KeyFlags', hashed=True, flags=usage) crosssig = None # if possible, have the subkey create a primary key binding signature if key.key_algorithm.can_sign and prefs.pop('crosssign', True): subkeyid = key.fingerprint.keyid if not key.is_public: crosssig = key.bind(self) elif subkeyid in self.subkeys: # pragma: no cover crosssig = self.subkeys[subkeyid].bind(self) if crosssig is None: if usage is None: raise PGPError('subkey with no key usage flags (may be used for any purpose, including signing) requires a cross-signature') if KeyFlags.Sign in usage: raise PGPError('subkey marked for signing usage requires a cross-signature') else: sig._signature.subpackets.addnew('EmbeddedSignature', hashed=False, _sig=crosssig._signature) return self._sign(key, sig, **prefs) def verify(self, subject, signature=None): """ Verify a subject with a signature using this key. :param subject: The subject to verify :type subject: ``str``, ``unicode``, ``None``, :py:obj:`PGPMessage`, :py:obj:`PGPKey`, :py:obj:`PGPUID` :param signature: If the signature is detached, it should be specified here. :type signature: :py:obj:`PGPSignature` :returns: :py:obj:`~pgpy.types.SignatureVerification` """ sspairs = [] # some type checking if not isinstance(subject, (type(None), PGPMessage, PGPKey, PGPUID, PGPSignature, six.string_types, bytes, bytearray)): raise TypeError("Unexpected subject value: {:s}".format(str(type(subject)))) if not isinstance(signature, (type(None), PGPSignature)): raise TypeError("Unexpected signature value: {:s}".format(str(type(signature)))) def _filter_sigs(sigs): _ids = {self.fingerprint.keyid} | set(self.subkeys) return [ sig for sig in sigs if sig.signer in _ids ] # collect signature(s) if signature is None: if isinstance(subject, PGPMessage): sspairs += [ (sig, subject.message) for sig in _filter_sigs(subject.signatures) ] if isinstance(subject, (PGPUID, PGPKey)): sspairs += [ (sig, subject) for sig in _filter_sigs(subject.__sig__) ] if isinstance(subject, PGPKey): # user ids sspairs += [ (sig, uid) for uid in subject.userids for sig in _filter_sigs(uid.__sig__) ] # user attributes sspairs += [ (sig, ua) for ua in subject.userattributes for sig in _filter_sigs(ua.__sig__) ] # subkey binding signatures sspairs += [ (sig, subkey) for subkey in subject.subkeys.values() for sig in _filter_sigs(subkey.__sig__) ] elif signature.signer in {self.fingerprint.keyid} | set(self.subkeys): sspairs += [(signature, subject)] if len(sspairs) == 0: raise PGPError("No signatures to verify") # finally, start verifying signatures sigv = SignatureVerification() for sig, subj in sspairs: if self.fingerprint.keyid != sig.signer and sig.signer in self.subkeys: sigv &= self.subkeys[sig.signer].verify(subj, sig) else: verified = self._key.verify(sig.hashdata(subj), sig.__sig__, getattr(hashes, sig.hash_algorithm.name)()) if verified is NotImplemented: raise NotImplementedError(sig.key_algorithm) sigv.add_sigsubj(sig, self, subj, verified) return sigv @KeyAction(KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage, is_public=True) def encrypt(self, message, sessionkey=None, **prefs): """encrypt(message[, sessionkey=None], **prefs) Encrypt a PGPMessage using this key. :param message: The message to encrypt. :type message: :py:obj:`PGPMessage` :param sessionkey: Provide a session key to use when encrypting something. Default is ``None``. If ``None``, a session key of the appropriate length will be generated randomly. .. warning:: Care should be taken when making use of this option! Session keys *absolutely need* to be unpredictable! Use the ``gen_key()`` method on the desired :py:obj:`~constants.SymmetricKeyAlgorithm` to generate the session key! :type sessionkey: ``bytes``, ``str`` :raises: :py:exc:`~errors.PGPEncryptionError` if encryption failed for any reason. :returns: A new :py:obj:`PGPMessage` with the encrypted contents of ``message`` The following optional keyword arguments can be used with :py:meth:`PGPKey.encrypt`: :keyword cipher: Specifies the symmetric block cipher to use when encrypting the message. :type cipher: :py:obj:`~constants.SymmetricKeyAlgorithm` :keyword user: Specifies the User ID to use as the recipient for this encryption operation, for the purposes of preference defaults and selection validation. :type user: ``str``, ``unicode`` """ user = prefs.pop('user', None) uid = None if user is not None: uid = self.get_uid(user) else: uid = next(iter(self.userids), None) if uid is None and self.parent is not None: uid = next(iter(self.parent.userids), None) pref_cipher = next(c for c in uid.selfsig.cipherprefs if c.is_supported) cipher_algo = prefs.pop('cipher', pref_cipher) if cipher_algo not in uid.selfsig.cipherprefs: warnings.warn("Selected symmetric algorithm not in key preferences", stacklevel=3) if message.is_compressed and message._compression not in uid.selfsig.compprefs: warnings.warn("Selected compression algorithm not in key preferences", stacklevel=3) if sessionkey is None: sessionkey = cipher_algo.gen_key() # set up a new PKESessionKeyV3 pkesk = PKESessionKeyV3() pkesk.encrypter = bytearray(binascii.unhexlify(self.fingerprint.keyid.encode('latin-1'))) pkesk.pkalg = self.key_algorithm # pkesk.encrypt_sk(self.__key__, cipher_algo, sessionkey) pkesk.encrypt_sk(self._key, cipher_algo, sessionkey) if message.is_encrypted: # pragma: no cover _m = message else: _m = PGPMessage() skedata = IntegrityProtectedSKEDataV1() skedata.encrypt(sessionkey, cipher_algo, message.__bytes__()) _m |= skedata _m |= pkesk return _m @KeyAction(is_unlocked=True, is_public=False) def decrypt(self, message): """ Decrypt a PGPMessage using this key. :param message: An encrypted :py:obj:`PGPMessage` :raises: :py:exc:`~errors.PGPError` if the key is not private, or protected but not unlocked. :raises: :py:exc:`~errors.PGPDecryptionError` if decryption fails for any other reason. :returns: A new :py:obj:`PGPMessage` with the decrypted contents of ``message``. """ if not message.is_encrypted: warnings.warn("This message is not encrypted", stacklevel=3) return message if self.fingerprint.keyid not in message.encrypters: sks = set(self.subkeys) mis = set(message.encrypters) if sks & mis: skid = list(sks & mis)[0] return self.subkeys[skid].decrypt(message) raise PGPError("Cannot decrypt the provided message with this key") pkesk = next(pk for pk in message._sessionkeys if pk.pkalg == self.key_algorithm and pk.encrypter == self.fingerprint.keyid) alg, key = pkesk.decrypt_sk(self._key) # now that we have the symmetric cipher used and the key, we can decrypt the actual message decmsg = PGPMessage() decmsg.parse(message.message.decrypt(key, alg)) return decmsg def parse(self, data): unarmored = self.ascii_unarmor(data) data = unarmored['body'] if unarmored['magic'] is not None and 'KEY' not in unarmored['magic']: raise ValueError('Expected: KEY. Got: {}'.format(str(unarmored['magic']))) if unarmored['headers'] is not None: self.ascii_headers = unarmored['headers'] # parse packets # keys will hold other keys parsed here keys = collections.OrderedDict() # orphaned will hold all non-opaque orphaned packets orphaned = [] # last holds the last non-signature thing processed ##TODO: see issue #141 and fix this better _getpkt = lambda d: (Packet(d) if d else None) # flake8: noqa # some packets are filtered out getpkt = filter(lambda p: p.header.tag != PacketTag.Trust, iter(functools.partial(_getpkt, data), None)) def pktgrouper(): class PktGrouper(object): def __init__(self): self.last = None def __call__(self, pkt): if pkt.header.tag != PacketTag.Signature: self.last = '{:02X}_{:s}'.format(id(pkt), pkt.__class__.__name__) return self.last return PktGrouper() while True: for group in iter(group for _, group in itertools.groupby(getpkt, key=pktgrouper()) if not _.endswith('Opaque')): pkt = next(group) # deal with pkt first if isinstance(pkt, Key): pgpobj = (self if self._key is None else PGPKey()) | pkt elif isinstance(pkt, (UserID, UserAttribute)): pgpobj = PGPUID() | pkt else: # pragma: no cover break # add signatures to whatever we got [ operator.ior(pgpobj, PGPSignature() | sig) for sig in group if not isinstance(sig, Opaque) ] # and file away pgpobj if isinstance(pgpobj, PGPKey): if pgpobj.is_primary: keys[(pgpobj.fingerprint.keyid, pgpobj.is_public)] = pgpobj else: keys[next(reversed(keys))] |= pgpobj elif isinstance(pgpobj, PGPUID): # parent is likely the most recently parsed primary key keys[next(reversed(keys))] |= pgpobj else: # pragma: no cover break else: # finished normally break # this will only be reached called if the inner loop hit a break warnings.warn("Warning: Orphaned packet detected! {:s}".format(repr(pkt)), stacklevel=2) # pragma: no cover orphaned.append(pkt) # pragma: no cover for pkt in group: # pragma: no cover orphaned.append(pkt) # remove the reference to self from keys [ keys.pop((getattr(self, 'fingerprint.keyid', '~'), None), t) for t in (True, False) ] # return {'keys': keys, 'orphaned': orphaned} return keys class PGPKeyring(collections_abc.Container, collections_abc.Iterable, collections_abc.Sized): def __init__(self, *args): """ PGPKeyring objects represent in-memory keyrings that can contain any combination of supported private and public keys. It can not currently be conveniently exported to a format that can be understood by GnuPG. """ super(PGPKeyring, self).__init__() self._keys = {} self._pubkeys = collections.deque() self._privkeys = collections.deque() self._aliases = collections.deque([{}]) self.load(*args) def __contains__(self, alias): aliases = set().union(*self._aliases) if isinstance(alias, six.string_types): return alias in aliases or alias.replace(' ', '') in aliases return alias in aliases # pragma: no cover def __len__(self): return len(self._keys) def __iter__(self): # pragma: no cover for pgpkey in itertools.chain(self._pubkeys, self._privkeys): yield pgpkey def _get_key(self, alias): for m in self._aliases: if alias in m: return self._keys[m[alias]] if alias.replace(' ', '') in m: return self._keys[m[alias.replace(' ', '')]] raise KeyError(alias) def _get_keys(self, alias): return [self._keys[m[alias]] for m in self._aliases if alias in m] def _sort_alias(self, alias): # remove alias from all levels of _aliases, and sort by created time and key half # so the order of _aliases from left to right: # - newer keys come before older ones # - private keys come before public ones # # this list is sorted in the opposite direction from that, because they will be placed into self._aliases # from right to left. pkids = sorted(list(set().union(m.pop(alias) for m in self._aliases if alias in m)), key=lambda pkid: (self._keys[pkid].created, self._keys[pkid].is_public)) # drop the now-sorted aliases into place for depth, pkid in enumerate(pkids): self._aliases[depth][alias] = pkid # finally, remove any empty dicts left over while {} in self._aliases: # pragma: no cover self._aliases.remove({}) def _add_alias(self, alias, pkid): # brand new alias never seen before! if alias not in self: self._aliases[-1][alias] = pkid # this is a duplicate alias->key link; ignore it elif alias in self and pkid in set(m[alias] for m in self._aliases if alias in m): pass # pragma: no cover # this is an alias that already exists, but points to a key that is not already referenced by it else: adepth = len(self._aliases) - len([None for m in self._aliases if alias in m]) - 1 # all alias maps have this alias, so increase total depth by 1 if adepth == -1: self._aliases.appendleft({}) adepth = 0 self._aliases[adepth][alias] = pkid self._sort_alias(alias) def _add_key(self, pgpkey): pkid = id(pgpkey) if pkid not in self._keys: self._keys[pkid] = pgpkey # add to _{pub,priv}keys if this is either a primary key, or a subkey without one if pgpkey.parent is None: if pgpkey.is_public: self._pubkeys.append(pkid) else: self._privkeys.append(pkid) # aliases self._add_alias(pgpkey.fingerprint, pkid) self._add_alias(pgpkey.fingerprint.keyid, pkid) self._add_alias(pgpkey.fingerprint.shortid, pkid) for uid in pgpkey.userids: self._add_alias(uid.name, pkid) if uid.comment: self._add_alias(uid.comment, pkid) if uid.email: self._add_alias(uid.email, pkid) # subkeys for subkey in pgpkey.subkeys.values(): self._add_key(subkey) def load(self, *args): r""" Load all keys provided into this keyring object. :param \*args: Each arg in ``args`` can be any of the formats supported by :py:meth:`PGPKey.from_file` and :py:meth:`PGPKey.from_blob` or a :py:class:`PGPKey` instance, or a ``list`` or ``tuple`` of these. :type \*args: ``list``, ``tuple``, ``str``, ``unicode``, ``bytes``, ``bytearray`` :returns: a ``set`` containing the unique fingerprints of all of the keys that were loaded during this operation. """ def _preiter(first, iterable): yield first for item in iterable: yield item loaded = set() for key in iter(item for ilist in iter(ilist if isinstance(ilist, (tuple, list)) else [ilist] for ilist in args) for item in ilist): keys = {} if isinstance(key, PGPKey): _key = key elif os.path.isfile(key): _key, keys = PGPKey.from_file(key) else: _key, keys = PGPKey.from_blob(key) for ik in _preiter(_key, keys.values()): self._add_key(ik) loaded |= {ik.fingerprint} | {isk.fingerprint for isk in ik.subkeys.values()} return list(loaded) @contextlib.contextmanager def key(self, identifier): """ A context-manager method. Yields the first :py:obj:`PGPKey` object that matches the provided identifier. :param identifier: The identifier to use to select a loaded key. :type identifier: :py:exc:`PGPMessage`, :py:exc:`PGPSignature`, ``str`` :raises: :py:exc:`KeyError` if there is no loaded key that satisfies the identifier. """ if isinstance(identifier, PGPMessage): for issuer in identifier.issuers: if issuer in self: identifier = issuer break if isinstance(identifier, PGPSignature): identifier = identifier.signer yield self._get_key(identifier) def fingerprints(self, keyhalf='any', keytype='any'): """ List loaded fingerprints with some optional filtering. :param keyhalf: Can be 'any', 'public', or 'private'. If 'public', or 'private', the fingerprints of keys of the the other type will not be included in the results. :type keyhalf: ``str`` :param keytype: Can be 'any', 'primary', or 'sub'. If 'primary' or 'sub', the fingerprints of keys of the the other type will not be included in the results. :type keytype: ``str`` :returns: a ``set`` of fingerprints of keys matching the filters specified. """ return {pk.fingerprint for pk in self._keys.values() if pk.is_primary in [True if keytype in ['primary', 'any'] else None, False if keytype in ['sub', 'any'] else None] if pk.is_public in [True if keyhalf in ['public', 'any'] else None, False if keyhalf in ['private', 'any'] else None]} def unload(self, key): """ Unload a loaded key and its subkeys. :param key: The key to unload. :type key: :py:obj:`PGPKey` The easiest way to do this is to select a key using :py:meth:`PGPKeyring.key` first:: with keyring.key("DSA von TestKey") as key: keyring.unload(key) """ assert isinstance(key, PGPKey) pkid = id(key) if pkid in self._keys: # remove references [ kd.remove(pkid) for kd in [self._pubkeys, self._privkeys] if pkid in kd ] # remove the key self._keys.pop(pkid) # remove aliases for m, a in [ (m, a) for m in self._aliases for a, p in m.items() if p == pkid ]: m.pop(a) # do a re-sort of this alias if it was not unique if a in self: self._sort_alias(a) # if key is a primary key, unload its subkeys as well if key.is_primary: [ self.unload(sk) for sk in key.subkeys.values() ] PGPy-0.5.4/pgpy/symenc.py000066400000000000000000000034261403641706600152020ustar00rootroot00000000000000""" symenc.py """ import six from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.ciphers import Cipher from cryptography.hazmat.primitives.ciphers import modes from .errors import PGPDecryptionError from .errors import PGPEncryptionError from .errors import PGPInsecureCipher __all__ = ['_encrypt', '_decrypt'] def _encrypt(pt, key, alg, iv=None): if iv is None: iv = b'\x00' * (alg.block_size // 8) if alg.is_insecure: raise PGPInsecureCipher("{:s} is not secure. Do not use it for encryption!".format(alg.name)) if not alg.is_supported: raise PGPEncryptionError("Cipher {:s} not supported".format(alg.name)) try: encryptor = Cipher(alg.cipher(key), modes.CFB(iv), default_backend()).encryptor() except UnsupportedAlgorithm as ex: # pragma: no cover six.raise_from(PGPEncryptionError, ex) else: return bytearray(encryptor.update(pt) + encryptor.finalize()) def _decrypt(ct, key, alg, iv=None): if iv is None: """ Instead of using an IV, OpenPGP prefixes a string of length equal to the block size of the cipher plus two to the data before it is encrypted. The first block-size octets (for example, 8 octets for a 64-bit block length) are random, and the following two octets are copies of the last two octets of the IV. """ iv = b'\x00' * (alg.block_size // 8) try: decryptor = Cipher(alg.cipher(key), modes.CFB(iv), default_backend()).decryptor() except UnsupportedAlgorithm as ex: # pragma: no cover six.raise_from(PGPDecryptionError, ex) else: return bytearray(decryptor.update(ct) + decryptor.finalize()) PGPy-0.5.4/pgpy/types.py000066400000000000000000000614701403641706600150530ustar00rootroot00000000000000""" types.py """ from __future__ import division import abc import base64 import binascii import bisect import codecs import collections import operator import os import re import warnings import weakref from enum import EnumMeta from enum import IntEnum import six from .decorators import sdproperty from .errors import PGPError __all__ = ['Armorable', 'ParentRef', 'PGPObject', 'Field', 'Header', 'MetaDispatchable', 'Dispatchable', 'SignatureVerification', 'FlagEnumMeta', 'FlagEnum', 'Fingerprint', 'SorteDeque'] if six.PY2: FileNotFoundError = IOError re.ASCII = 0 class Armorable(six.with_metaclass(abc.ABCMeta)): __crc24_init = 0x0B704CE __crc24_poly = 0x1864CFB __armor_fmt = '-----BEGIN PGP {block_type}-----\n' \ '{headers}\n' \ '{packet}\n' \ '={crc}\n' \ '-----END PGP {block_type}-----\n' # the re.VERBOSE flag allows for: # - whitespace is ignored except when in a character class or escaped # - anything after a '#' that is not escaped or in a character class is ignored, allowing for comments __armor_regex = re.compile(r"""# This capture group is optional because it will only be present in signed cleartext messages (^-{5}BEGIN\ PGP\ SIGNED\ MESSAGE-{5}(?:\r?\n) (Hash:\ (?P[A-Za-z0-9\-,]+)(?:\r?\n){2})? (?P(.*\r?\n)*(.*(?=\r?\n-{5})))(?:\r?\n) )? # armor header line; capture the variable part of the magic text ^-{5}BEGIN\ PGP\ (?P[A-Z0-9 ,]+)-{5}(?:\r?\n) # try to capture all the headers into one capture group # if this doesn't match, m['headers'] will be None (?P(^.+:\ .+(?:\r?\n))+)?(?:\r?\n)? # capture all lines of the body, up to 76 characters long, # including the newline, and the pad character(s) (?P([A-Za-z0-9+/]{1,76}={,2}(?:\r?\n))+) # capture the armored CRC24 value ^=(?P[A-Za-z0-9+/]{4})(?:\r?\n) # finally, capture the armor tail line, which must match the armor header line ^-{5}END\ PGP\ (?P=magic)-{5}(?:\r?\n)? """, flags=re.MULTILINE | re.VERBOSE) @property def charset(self): return self.ascii_headers.get('Charset', 'utf-8') @charset.setter def charset(self, encoding): self.ascii_headers['Charset'] = codecs.lookup(encoding).name @staticmethod def is_ascii(text): if isinstance(text, six.string_types): return bool(re.match(r'^[ -~\r\n]*$', text, flags=re.ASCII)) if isinstance(text, (bytes, bytearray)): return bool(re.match(br'^[ -~\r\n]*$', text, flags=re.ASCII)) raise TypeError("Expected: ASCII input of type str, bytes, or bytearray") # pragma: no cover @staticmethod def is_armor(text): """ Whether the ``text`` provided is an ASCII-armored PGP block. :param text: A possible ASCII-armored PGP block. :raises: :py:exc:`TypeError` if ``text`` is not a ``str``, ``bytes``, or ``bytearray`` :returns: Whether the text is ASCII-armored. """ if isinstance(text, (bytes, bytearray)): # pragma: no cover text = text.decode('latin-1') return Armorable.__armor_regex.search(text) is not None @staticmethod def ascii_unarmor(text): """ Takes an ASCII-armored PGP block and returns the decoded byte value. :param text: An ASCII-armored PGP block, to un-armor. :raises: :py:exc:`ValueError` if ``text`` did not contain an ASCII-armored PGP block. :raises: :py:exc:`TypeError` if ``text`` is not a ``str``, ``bytes``, or ``bytearray`` :returns: A ``dict`` containing information from ``text``, including the de-armored data. It can contain the following keys: ``magic``, ``headers``, ``hashes``, ``cleartext``, ``body``, ``crc``. """ m = {'magic': None, 'headers': None, 'body': bytearray(), 'crc': None} if not Armorable.is_ascii(text): m['body'] = bytearray(text) return m if isinstance(text, (bytes, bytearray)): # pragma: no cover text = text.decode('latin-1') m = Armorable.__armor_regex.search(text) if m is None: # pragma: no cover raise ValueError("Expected: ASCII-armored PGP data") m = m.groupdict() if m['hashes'] is not None: m['hashes'] = m['hashes'].split(',') if m['headers'] is not None: m['headers'] = collections.OrderedDict(re.findall('^(?P.+): (?P.+)$\n?', m['headers'], flags=re.MULTILINE)) if m['body'] is not None: try: m['body'] = bytearray(base64.b64decode(m['body'].encode())) except (binascii.Error, TypeError) as ex: six.raise_from(PGPError(str(ex)), ex) if m['crc'] is not None: m['crc'] = Header.bytes_to_int(base64.b64decode(m['crc'].encode())) if Armorable.crc24(m['body']) != m['crc']: warnings.warn('Incorrect crc24', stacklevel=3) return m @staticmethod def crc24(data): # CRC24 computation, as described in the RFC 4880 section on Radix-64 Conversions # # The checksum is a 24-bit Cyclic Redundancy Check (CRC) converted to # four characters of radix-64 encoding by the same MIME base64 # transformation, preceded by an equal sign (=). The CRC is computed # by using the generator 0x864CFB and an initialization of 0xB704CE. # The accumulation is done on the data before it is converted to # radix-64, rather than on the converted data. crc = Armorable.__crc24_init if not isinstance(data, bytearray): data = six.iterbytes(data) for b in data: crc ^= b << 16 for i in range(8): crc <<= 1 if crc & 0x1000000: crc ^= Armorable.__crc24_poly return crc & 0xFFFFFF @abc.abstractproperty def magic(self): """The magic string identifier for the current PGP type""" @classmethod def from_file(cls, filename): with open(filename, 'rb') as file: obj = cls() data = bytearray(os.path.getsize(filename)) file.readinto(data) po = obj.parse(data) if po is not None: return (obj, po) return obj # pragma: no cover @classmethod def from_blob(cls, blob): obj = cls() if (not isinstance(blob, six.binary_type)) and (not isinstance(blob, bytearray)): po = obj.parse(bytearray(blob, 'latin-1')) else: po = obj.parse(bytearray(blob)) if po is not None: return (obj, po) return obj # pragma: no cover def __init__(self): super(Armorable, self).__init__() self.ascii_headers = collections.OrderedDict() def __str__(self): payload = base64.b64encode(self.__bytes__()).decode('latin-1') payload = '\n'.join(payload[i:(i + 64)] for i in range(0, len(payload), 64)) return self.__armor_fmt.format( block_type=self.magic, headers=''.join('{key}: {val}\n'.format(key=key, val=val) for key, val in self.ascii_headers.items()), packet=payload, crc=base64.b64encode(PGPObject.int_to_bytes(self.crc24(self.__bytes__()), 3)).decode('latin-1') ) def __copy__(self): obj = self.__class__() obj.ascii_headers = self.ascii_headers.copy() return obj class ParentRef(object): # mixin class to handle weak-referencing a parent object @property def _parent(self): if isinstance(self.__parent, weakref.ref): return self.__parent() return self.__parent @_parent.setter def _parent(self, parent): try: self.__parent = weakref.ref(parent) except TypeError: self.__parent = parent @property def parent(self): return self._parent def __init__(self): super(ParentRef, self).__init__() self._parent = None class PGPObject(six.with_metaclass(abc.ABCMeta, object)): @staticmethod def int_byte_len(i): return (i.bit_length() + 7) // 8 @staticmethod def bytes_to_int(b, order='big'): # pragma: no cover """convert bytes to integer""" if six.PY2: # save the original type of b without having to copy any data _b = b.__class__() if order != 'little': b = reversed(b) if not isinstance(_b, bytearray): b = six.iterbytes(b) return sum(c << (i * 8) for i, c in enumerate(b)) return int.from_bytes(b, order) @staticmethod def int_to_bytes(i, minlen=1, order='big'): # pragma: no cover """convert integer to bytes""" blen = max(minlen, PGPObject.int_byte_len(i), 1) if six.PY2: r = iter(_ * 8 for _ in (range(blen) if order == 'little' else range(blen - 1, -1, -1))) return bytes(bytearray((i >> c) & 0xff for c in r)) return i.to_bytes(blen, order) @staticmethod def text_to_bytes(text): if text is None: return text # if we got bytes, just return it if isinstance(text, (bytearray, six.binary_type)): return text # if we were given a unicode string, or if we translated the string into utf-8, # we know that Python already has it in utf-8 encoding, so we can now just encode it to bytes return text.encode('utf-8') @staticmethod def bytes_to_text(text): if text is None or isinstance(text, six.text_type): return text return text.decode('utf-8') @abc.abstractmethod def parse(self, packet): """this method is too abstract to understand""" @abc.abstractmethod def __bytearray__(self): """ Returns the contents of concrete subclasses in a binary format that can be understood by other OpenPGP implementations """ def __bytes__(self): """ Return the contents of concrete subclasses in a binary format that can be understood by other OpenPGP implementations """ # this is what all subclasses will do anyway, so doing this here we can reduce code duplication significantly return bytes(self.__bytearray__()) class Field(PGPObject): @abc.abstractmethod def __len__(self): """Return the length of the output of __bytes__""" class Header(Field): @staticmethod def encode_length(l, nhf=True, llen=1): def _new_length(l): if 192 > l: return Header.int_to_bytes(l) elif 8384 > l: elen = ((l & 0xFF00) + (192 << 8)) + ((l & 0xFF) - 192) return Header.int_to_bytes(elen, 2) return b'\xFF' + Header.int_to_bytes(l, 4) def _old_length(l, llen): return Header.int_to_bytes(l, llen) if llen > 0 else b'' return _new_length(l) if nhf else _old_length(l, llen) @sdproperty def length(self): return self._len @length.register(int) def length_int(self, val): self._len = val @length.register(six.binary_type) @length.register(bytearray) def length_bin(self, val): def _new_len(b): def _parse_len(a, offset=0): # returns (the parsed length, size of length field, whether the length was of partial type) fo = a[offset] if 192 > fo: return (self.bytes_to_int(a[offset:offset + 1]), 1, False) elif 224 > fo: # >= 192 is implied dlen = self.bytes_to_int(b[offset:offset + 2]) return (((dlen - (192 << 8)) & 0xFF00) + ((dlen & 0xFF) + 192), 2, False) elif 255 > fo: # >= 224 is implied # this is a partial-length header return (1 << (fo & 0x1f), 1, True) elif 255 == fo: return (self.bytes_to_int(b[offset + 1:offset + 5]), 5, False) else: # pragma: no cover raise ValueError("Malformed length: 0x{:02x}".format(fo)) part_len, size, partial = _parse_len(b) del b[:size] if partial: total = part_len while partial: part_len, size, partial = _parse_len(b, total) del b[total:total + size] total += part_len self._len = total else: self._len = part_len def _old_len(b): if self.llen > 0: self._len = self.bytes_to_int(b[:self.llen]) del b[:self.llen] else: # pragma: no cover self._len = 0 _new_len(val) if self._lenfmt == 1 else _old_len(val) @sdproperty def llen(self): l = self.length lf = self._lenfmt if lf == 1: # new-format length if 192 > l: return 1 elif 8384 > self.length: # >= 192 is implied return 2 else: return 5 else: # old-format length ##TODO: what if _llen needs to be (re)computed? return self._llen @llen.register(int) def llen_int(self, val): if self._lenfmt == 0: self._llen = {0: 1, 1: 2, 2: 4, 3: 0}[val] def __init__(self): super(Header, self).__init__() self._len = 1 self._llen = 1 self._lenfmt = 1 self._partial = False class MetaDispatchable(abc.ABCMeta): """ MetaDispatchable is a metaclass for objects that subclass Dispatchable """ _roots = set() """ _roots is a set of all currently registered RootClass class objects A RootClass is successfully registered if the following things are true: - it inherits (directly or indirectly) from Dispatchable - __typeid__ == -1 """ _registry = {} """ _registry is the Dispatchable class registry. It uses the following format: { (RootClass, None): OpaqueClass }: denotes the default ("opaque") for a given RootClass. An OpaqueClass is successfully registered as such provided the following conditions are met: - it inherits directly from a RootClass - __typeid__ is None { (RootClass, TypeID): SubClass }: denotes the class that handles the type given in TypeID a SubClass is successfully registered as such provided the following conditions are met: - it inherits (directly or indirectly) from a RootClass - __typeid__ is a positive int - the given typeid is not already registered { (RootClass, TypeID): VerSubClass }: denotes that a given TypeID has multiple versions, and that this is class' subclasses handle those. A VerSubClass is registered identically to a normal SubClass. { (RootClass, TypeID, Ver): VerSubClass }: denotes the class that handles the type given in TypeID and the version of that type given in Ver a Versioned SubClass is successfully registered as such provided the following conditions are met: - it inherits from a VerSubClass - __ver__ > 0 - the given typeid/ver combination is not already registered """ def __new__(mcs, name, bases, attrs): # NOQA ncls = super(MetaDispatchable, mcs).__new__(mcs, name, bases, attrs) if not hasattr(ncls.__typeid__, '__isabstractmethod__'): if ncls.__typeid__ == -1 and not issubclass(ncls, tuple(MetaDispatchable._roots)): # this is a root class MetaDispatchable._roots.add(ncls) elif issubclass(ncls, tuple(MetaDispatchable._roots)) and ncls.__typeid__ != -1: for rcls in [ root for root in MetaDispatchable._roots if issubclass(ncls, root) ]: if (rcls, ncls.__typeid__) not in MetaDispatchable._registry: MetaDispatchable._registry[(rcls, ncls.__typeid__)] = ncls if (ncls.__ver__ is not None and ncls.__ver__ > 0 and (rcls, ncls.__typeid__, ncls.__ver__) not in MetaDispatchable._registry): MetaDispatchable._registry[(rcls, ncls.__typeid__, ncls.__ver__)] = ncls # finally, return the new class object return ncls def __call__(cls, packet=None): # NOQA def _makeobj(cls): obj = object.__new__(cls) obj.__init__() return obj if packet is not None: if cls in MetaDispatchable._roots: rcls = cls elif issubclass(cls, tuple(MetaDispatchable._roots)): # pragma: no cover rcls = next(root for root in MetaDispatchable._roots if issubclass(cls, root)) ##TODO: else raise an exception of some kind, but this should never happen header = rcls.__headercls__() header.parse(packet) ncls = None if (rcls, header.typeid) in MetaDispatchable._registry: ncls = MetaDispatchable._registry[(rcls, header.typeid)] if ncls.__ver__ == 0: if header.__class__ != ncls.__headercls__: nh = ncls.__headercls__() nh.__dict__.update(header.__dict__) try: nh.parse(packet) except Exception as ex: six.raise_from(PGPError(str(ex)), ex) header = nh if (rcls, header.typeid, header.version) in MetaDispatchable._registry: ncls = MetaDispatchable._registry[(rcls, header.typeid, header.version)] else: # pragma: no cover ncls = None if ncls is None: ncls = MetaDispatchable._registry[(rcls, None)] obj = _makeobj(ncls) obj.header = header try: obj.parse(packet) except Exception as ex: six.raise_from(PGPError(str(ex)), ex) else: obj = _makeobj(cls) return obj class Dispatchable(six.with_metaclass(MetaDispatchable, PGPObject)): @abc.abstractproperty def __headercls__(self): # pragma: no cover return False @abc.abstractproperty def __typeid__(self): # pragma: no cover return False __ver__ = None class SignatureVerification(object): _sigsubj = collections.namedtuple('sigsubj', ['verified', 'by', 'signature', 'subject']) @property def good_signatures(self): """ A generator yielding namedtuples of all signatures that were successfully verified in the operation that returned this instance. The namedtuple has the following attributes: ``sigsubj.verified`` - ``bool`` of whether the signature verified successfully or not. ``sigsubj.by`` - the :py:obj:`~pgpy.PGPKey` that was used in this verify operation. ``sigsubj.signature`` - the :py:obj:`~pgpy.PGPSignature` that was verified. ``sigsubj.subject`` - the subject that was verified using the signature. """ for s in [ i for i in self._subjects if i.verified ]: yield s @property def bad_signatures(self): # pragma: no cover """ A generator yielding namedtuples of all signatures that were not verified in the operation that returned this instance. The namedtuple has the following attributes: ``sigsubj.verified`` - ``bool`` of whether the signature verified successfully or not. ``sigsubj.by`` - the :py:obj:`~pgpy.PGPKey` that was used in this verify operation. ``sigsubj.signature`` - the :py:obj:`~pgpy.PGPSignature` that was verified. ``sigsubj.subject`` - the subject that was verified using the signature. """ for s in [ i for i in self._subjects if not i.verified ]: yield s def __init__(self): """ Returned by :py:meth:`.PGPKey.verify` Can be compared directly as a boolean to determine whether or not the specified signature verified. """ super(SignatureVerification, self).__init__() self._subjects = [] def __contains__(self, item): return item in {ii for i in self._subjects for ii in [i.signature, i.subject]} def __len__(self): return len(self._subjects) def __bool__(self): return all(s.verified for s in self._subjects) def __nonzero__(self): return self.__bool__() def __and__(self, other): if not isinstance(other, SignatureVerification): raise TypeError(type(other)) self._subjects += other._subjects return self def __repr__(self): return "".format(verified=str(bool(self))) def add_sigsubj(self, signature, by, subject=None, verified=False): self._subjects.append(self._sigsubj(verified, by, signature, subject)) class FlagEnumMeta(EnumMeta): def __and__(self, other): return { f for f in iter(self) if f.value & other } def __rand__(self, other): # pragma: no cover return self & other if six.PY2: class FlagEnum(IntEnum): __metaclass__ = FlagEnumMeta else: namespace = FlagEnumMeta.__prepare__('FlagEnum', (IntEnum,)) FlagEnum = FlagEnumMeta('FlagEnum', (IntEnum,), namespace) class Fingerprint(str): """ A subclass of ``str``. Can be compared using == and != to ``str``, ``unicode``, and other :py:obj:`Fingerprint` instances. Primarily used as a key for internal dictionaries, so it ignores spaces when comparing and hashing """ @property def keyid(self): return str(self).replace(' ', '')[-16:] @property def shortid(self): return str(self).replace(' ', '')[-8:] def __new__(cls, content): if isinstance(content, Fingerprint): return content # validate input before continuing: this should be a string of 40 hex digits content = content.upper().replace(' ', '') if not bool(re.match(r'^[A-F0-9]{40}$', content)): raise ValueError("Expected: String of 40 hex digits") # store in the format: "AAAA BBBB CCCC DDDD EEEE FFFF 0000 1111 2222 3333" # ^^ note 2 spaces here spaces = [ ' ' if i != 4 else ' ' for i in range(10) ] chunks = [ ''.join(g) for g in six.moves.zip_longest(*[iter(content)] * 4) ] content = ''.join(j for i in six.moves.zip_longest(chunks, spaces, fillvalue='') for j in i).strip() return str.__new__(cls, content) def __eq__(self, other): if isinstance(other, Fingerprint): return str(self) == str(other) if isinstance(other, (six.text_type, bytes, bytearray)): if isinstance(other, (bytes, bytearray)): # pragma: no cover other = other.decode('latin-1') other = str(other).replace(' ', '') return any([self.replace(' ', '') == other, self.keyid == other, self.shortid == other]) return False # pragma: no cover def __ne__(self, other): return not (self == other) def __hash__(self): return hash(str(self.replace(' ', ''))) def __bytes__(self): return binascii.unhexlify(six.b(self.replace(' ', ''))) class SorteDeque(collections.deque): """A deque subclass that tries to maintain sorted ordering using bisect""" def insort(self, item): i = bisect.bisect_left(self, item) self.rotate(- i) self.appendleft(item) self.rotate(i) def resort(self, item): # pragma: no cover if item in self: # if item is already in self, see if it is still in sorted order. # if not, re-sort it by removing it and then inserting it into its sorted order i = bisect.bisect_left(self, item) if i == len(self) or self[i] is not item: self.remove(item) self.insort(item) else: # if item is not in self, just insert it in sorted order self.insort(item) def check(self): # pragma: no cover """re-sort any items in self that are not sorted""" for unsorted in iter(self[i] for i in range(len(self) - 2) if not operator.le(self[i], self[i + 1])): self.resort(unsorted) PGPy-0.5.4/pyproject.toml000066400000000000000000000001321403641706600152560ustar00rootroot00000000000000[build-system] requires = ["setuptools", "wheel"] build-backend = "setuptools.build_meta" PGPy-0.5.4/requirements-rtd.txt000066400000000000000000000000611403641706600164160ustar00rootroot00000000000000-r requirements.txt Sphinx<2 sphinx-better-theme PGPy-0.5.4/requirements-test.txt000066400000000000000000000001661403641706600166120ustar00rootroot00000000000000-r requirements.txt pytest pytest-cov pytest-ordering flake8 pep8-naming # NOTE: gpg is not here on purpose currently PGPy-0.5.4/requirements.txt000066400000000000000000000001521403641706600156300ustar00rootroot00000000000000cryptography>=2.6 enum34; python_version < '3.4' pyasn1 six>=1.9.0 singledispatch; python_version < '3.4' PGPy-0.5.4/setup.cfg000066400000000000000000000036151403641706600141740ustar00rootroot00000000000000[metadata] name = PGPy version = 0.5.4 author = Michael Greene author_email = mgreene@securityinnovation.com maintainer = Security Innovation maintainer_email = opensource@securityinnovation.com license = BSD description = Pretty Good Privacy for Python keywords = OpenPGP, PGP, Pretty Good Privacy, GPG, GnuPG, openpgp, pgp, gnupg, gpg, encryption, signature url = https://github.com/SecurityInnovation/PGPy project_urls = Documentation = https://pgpy.readthedocs.io/en/latest/ Bug Tracker = https://github.com/SecurityInnovation/PGPy/issues long_description = file: README.rst long_description_content_type = text/x-rst classifiers = Development Status :: 4 - Beta Operating System :: POSIX :: Linux Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Intended Audience :: Developers Programming Language :: Python Programming Language :: Python :: 3.9 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.5 Programming Language :: Python :: 3.4 Programming Language :: Python :: 2.7 Programming Language :: Python :: Implementation :: CPython Topic :: Security Topic :: Security :: Cryptography Topic :: Software Development :: Libraries Topic :: Software Development :: Libraries :: Python Modules License :: OSI Approved :: BSD License [options] packages = pgpy pgpy.packet pgpy.packet.subpackets install_requires = cryptography>=2.6 pyasn1 six>=1.9.0 singledispatch; python_version < '3.4' enum34; python_version < '3.4' setup_requires = setuptools wheel python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* # doc_requires = # sphinx # sphinx-better-theme [build_sphinx] source-dir = docs/source build-dir = docs/build all_files = 1 [bdist_wheel] universal = 1 PGPy-0.5.4/setup.py000066400000000000000000000000461403641706600140600ustar00rootroot00000000000000from setuptools import setup setup() PGPy-0.5.4/test_load_asc_bench.py000066400000000000000000000124321403641706600166650ustar00rootroot00000000000000#!/usr/bin/env python import asyncio import bisect import collections import itertools import os import sys from progressbar import ProgressBar, AnimatedMarker, Timer, Bar, Percentage, Widget import pgpy from pgpy.packet import Packet from pgpy.types import Exportable ascfiles = [ os.path.abspath(os.path.expanduser(f)) for f in sys.argv[1:] if os.path.exists(os.path.abspath(os.path.expanduser(f))) ] if len(ascfiles) == 0: sys.stderr.write("Please specify one or more ASCII-armored files to load\n") sys.exit(-1) for a in [ os.path.abspath(os.path.expanduser(a)) for a in sys.argv[1:] if a not in ascfiles ]: sys.stderr.write("Error: {} does not exist\n".write()) class Mebibyte(int): iec = {1: 'B', 1024: 'KiB', 1024**2: 'MiB', 1024**3: 'GiB', 1024**4: 'TiB', 1024**5: 'PiB', 1024**6: 'EiB', 1024**7: 'ZiB', 1024**8: 'YiB'} iecl = [1, 1024, 1024**2, 1024**3, 1024**4, 1024**5, 1024**6, 1024**7, 1024**8] # custom format class for human readable IEC byte formatting def __format__(self, spec): # automatically format based on size iiec = max(0, min(bisect.bisect_right(self.iecl, int(self)), len(self.iecl))) ieck = self.iecl[iiec - 1] return '{:,.2f} {:s}'.format(int(self) / ieck, self.iec[ieck]) @asyncio.coroutine def _dospinner(pbar): for i in pbar(itertools.cycle(range(100))): try: yield from asyncio.shield(asyncio.sleep(0.005)) except asyncio.CancelledError: print("") break @asyncio.coroutine def _load_pubring(ascfile, future): with open(ascfile, 'r') as ppr: a = yield from asyncio.get_event_loop().run_in_executor(None, ppr.read) future.set_result(a) @asyncio.coroutine def _unarmor(a, future): b = yield from asyncio.get_event_loop().run_in_executor(None, pgpy.types.Exportable.ascii_unarmor, a) future.set_result(b) _b = bytearray() loop = asyncio.get_event_loop() for ascfile in ascfiles: ascfile = os.path.abspath(ascfile) if not os.path.isfile(ascfile): sys.stderr.write('Error: {} does not exist'.format(ascfile)) continue load_bar = ProgressBar(widgets=["Reading {} ({}): ".format(ascfile, Mebibyte(os.path.getsize(ascfile))), AnimatedMarker()]) unarmor_bar = ProgressBar(widgets=["Unarmoring data: ", AnimatedMarker()]) a = asyncio.Future() b = asyncio.Future() lbp = asyncio.Task(_dospinner(load_bar)) asyncio.Task(_load_pubring(ascfile, a)) loop.run_until_complete(a) _a = a.result() lbp.cancel() uap = asyncio.Task(_dospinner(unarmor_bar)) asyncio.Task(_unarmor(_a, b)) loop.run_until_complete(b) _b += b.result()['body'] uap.cancel() loop.stop() print("\n") packets = [] _mv = len(_b) class BetterCounter(Widget): def __init__(self, pktlist, iec=False, format='{:,}'): self.list = pktlist self.iec = iec self.format = format def update(self, pbar): if self.iec: return self.format.format(Mebibyte(len(self.list))) return self.format.format(len(self.list)) pb3w = [BetterCounter(packets, False, '{:,} pkts'), '|', BetterCounter(_b, True, '{:,} rem.'), '|', Timer("%s"), '|', Percentage(), Bar()] pbar3 = ProgressBar(maxval=_mv, widgets=pb3w).start() while len(_b) > 0: olen = len(_b) pkt = Packet(_b) # if len(packets) == 10132: # a=0 # try: # pkt = Packet(_b) # # except: # print("\n\tSomething went wrong!") # print("\tBad packet followed packet #{:,d}".format(len(packets))) # print("\tLast packet was: {:s} (tag {:d}) ({:,d} bytes)".format(packets[-1].__class__.__name__, packets[-1].header.tag, packets[-1].header.length)) # print("\t{:,d} bytes left unparsed".format(len(_b))) # print("\tFailed packet consumed {:,d} bytes".format(olen - len(_b))) # raise # # if (olen - len(_b)) != len(pkt.header) + pkt.header.length: # print("Incorrect number of bytes consumed. Got: {:,}. Expected: {:,}".format((olen - len(_b)), (len(pkt.header) + pkt.header.length))) # print("Bad packet was: {cls:s}, {id:d}, {ver:s}".format(cls=pkt.__class__.__name__, id=pkt.header.typeid, ver=str(pkt.header.version) if hasattr(pkt.header, 'version') else '')) # print("loaded: " + str(len(packets))) packets.append(pkt) pbar3.update(_mv - len(_b)) pbar3.finish() print("\n\n") print('Parsed Packet Stats\n') pcnts = collections.Counter(['{cls:s} v{v:d}'.format(cls=c.__class__.__name__, v=c.version) if hasattr(c, 'version') else c.__class__.__name__ for c in packets if not isinstance(c, pgpy.packet.Opaque)] + ['Opaque [{:02d}]{:s}'.format(c.header.tag, '[v{:d}]'.format(c.header.version) if hasattr(c.header, 'version') else '') for c in packets if isinstance(c, pgpy.packet.Opaque)]) ml = max(5, max([len(s) for s in pcnts.keys()])) mcl = max(5, max([len("{:,}".format(c)) for c in pcnts.values()])) print('Class{0: <{pad1}} Count\n' \ '====={0:=<{pad1}} ====={0:=<{pad2}}'.format('', pad1=(ml - 5), pad2=(mcl - 5))) for pc, cnt in sorted(pcnts.items(), key=lambda x: x[1], reverse=True): print('{cls:{pad1}} {count: <{pad2},}'.format(pad1=ml, pad2=mcl, cls=pc, count=cnt)) print("") PGPy-0.5.4/tests/000077500000000000000000000000001403641706600135105ustar00rootroot00000000000000PGPy-0.5.4/tests/conftest.py000066400000000000000000000045051403641706600157130ustar00rootroot00000000000000"""PGPy conftest""" import pytest import glob try: import gpg except ImportError: gpg = None import os import sys from distutils.version import LooseVersion from cryptography.hazmat.backends import openssl openssl_ver = LooseVersion(openssl.backend.openssl_version_text().split(' ')[1]) gpg_ver = LooseVersion('0') gnupghome = os.path.join(os.path.dirname(__file__), 'gnupghome') if gpg: gpgme_ver = gpg.core.check_version() # ensure external commands we need to run exist # set the CWD and add to sys.path if we need to os.chdir(os.path.join(os.path.abspath(os.path.dirname(__file__)), os.pardir)) if os.getcwd() not in sys.path: sys.path.insert(0, os.getcwd()) else: sys.path.insert(0, sys.path.pop(sys.path.index(os.getcwd()))) if os.path.join(os.getcwd(), 'tests') not in sys.path: sys.path.insert(1, os.path.join(os.getcwd(), 'tests')) # pytest hooks # pytest_configure # called after command line options have been parsed and all plugins and initial conftest files been loaded. def pytest_configure(config): print("== PGPy Test Suite ==") if gpg: # clear out gnupghome clear_globs = [os.path.join(gnupghome, 'private-keys-v1.d', '*.key'), os.path.join(gnupghome, '*.kbx*'), os.path.join(gnupghome, '*.gpg*'), os.path.join(gnupghome, '.*'), os.path.join(gnupghome, 'random_seed')] for fpath in iter(f for cg in clear_globs for f in glob.glob(cg)): os.unlink(fpath) # get the GnuPG version gpg_ver.parse(gpg.core.get_engine_info()[0].version) # check that there are no keys loaded, now with gpg.Context(offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) assert len(list(c.keylist())) == 0 assert len(list(c.keylist(secret=True))) == 0 else: # we're not running integration tests print("running without integration tests") # if we're on Travis, this is an error if os.getenv('TRAVIS_PYTHON_VERSION'): sys.exit(1) # display the working directory and the OpenSSL/GPG/pgpdump versions print("Working Directory: " + os.getcwd()) print("Using OpenSSL " + str(openssl_ver)) print("Using GnuPG " + str(gpg_ver)) print("") PGPy-0.5.4/tests/gnupghome/000077500000000000000000000000001403641706600155015ustar00rootroot00000000000000PGPy-0.5.4/tests/gnupghome/gpg-agent.conf000066400000000000000000000000301403641706600202120ustar00rootroot00000000000000allow-loopback-pinentry PGPy-0.5.4/tests/gnupghome/gpg.conf000066400000000000000000000003761403641706600171330ustar00rootroot00000000000000# GnuPG options for PGPy testing # always expert expert trust-model always # don't try to auto-locate keys except in the local keyring(s) no-auto-key-locate # some display options list-options show-keyring keyid-format long no-greeting verbose verbose PGPy-0.5.4/tests/test_00_exports.py000066400000000000000000000025271403641706600171320ustar00rootroot00000000000000""" check the export list to ensure only the public API is exported by pgpy.__init__ """ import pytest import importlib import inspect modules = ['pgpy.constants', 'pgpy.decorators', 'pgpy.errors', 'pgpy.pgp', 'pgpy.symenc', 'pgpy.types', 'pgpy.packet.fields', 'pgpy.packet.packets', 'pgpy.packet.types', 'pgpy.packet.subpackets.signature', 'pgpy.packet.subpackets.types', 'pgpy.packet.subpackets.userattribute'] def get_module_objs(module): # return a set of strings that represent the names of objects defined in that module return { n for n, o in inspect.getmembers(module, lambda m: inspect.getmodule(m) is module) } | ({'FlagEnum',} if module is importlib.import_module('pgpy.types') else set()) # dirty workaround until six fixes metaclass stuff to support EnumMeta in Python >= 3.6 def get_module_all(module): return set(getattr(module, '__all__', set())) def test_pgpy_all(): import pgpy # just check that everything in pgpy.__all__ is actually there assert set(pgpy.__all__) <= { n for n, _ in inspect.getmembers(pgpy) } @pytest.mark.parametrize('modname', modules) def test_exports(modname): module = importlib.import_module(modname) assert get_module_all(module) == get_module_objs(module) PGPy-0.5.4/tests/test_01_packetfields.py000066400000000000000000000354731403641706600200730ustar00rootroot00000000000000""" test field parsing """ import pytest import itertools from pgpy.constants import HashAlgorithm from pgpy.constants import String2KeyType from pgpy.constants import SymmetricKeyAlgorithm from pgpy.constants import S2KGNUExtension from pgpy.packet.fields import String2Key from pgpy.packet.types import Header from pgpy.packet.subpackets import Signature from pgpy.packet.subpackets import UserAttribute from pgpy.packet.subpackets.types import Header as HeaderSP from pgpy.packet.subpackets.types import Opaque as OpaqueSP _trailer = b'\xde\xca\xff\xba\xdd' _tag = bytearray(b'\xc2') pkt_headers = [ # new format # 1 byte length - 191 _tag + b'\xbf' + (b'\x00' * 191) + _trailer, # 2 byte length - 192 _tag + b'\xc0\x00' + (b'\x00' * 192) + _trailer, # 2 byte length - 8383 _tag + b'\xdf\xff' + (b'\x00' * 8383) + _trailer, # 5 byte length - 8384 _tag + b'\xff\x00\x00 \xc0' + (b'\x00' * 8384) + _trailer, # old format # 1 byte length - 255 bytearray(b'\x88') + b'\xff' + (b'\x00' * 255) + _trailer, # 2 byte length - 256 bytearray(b'\x89') + b'\x01\x00' + (b'\x00' * 256) + _trailer, # 4 byte length - 65536 bytearray(b'\x8a') + b'\x00\x01\x00\x00' + (b'\x00' * 65536) + _trailer, ] subpkt_headers = [ # 1 byte length - 191 bytearray(b'\xbf' + b'\x00' + (b'\x00' * 190)), # 2 byte length - 192 bytearray(b'\xc0\x00' + b'\x00' + (b'\x00' * 191)), # 2 byte length - 8383 bytearray(b'\xdf\xff' + b'\x00' + (b'\x00' * 8382)), # 5 byte length - 8384 bytearray(b'\xff\x00\x00 \xc0' + b'\x00' + (b'\x00' * 0x8383)), # 5 byte length - 65535 bytearray(b'\xff\x00\x00\xff\xff' + b'\x00' + (b'\x00' * 65534)), ] class TestHeaders(object): @pytest.mark.parametrize('pheader', pkt_headers) def test_packet_header(self, pheader): b = pheader[:] h = Header() h.parse(pheader) assert h.tag == 0x02 assert h.length == len(pheader) - len(_trailer) assert pheader[h.length:] == _trailer assert len(h) == len(b) - len(pheader) assert h.__bytes__() == b[:len(h)] @pytest.mark.parametrize('spheader', subpkt_headers) def test_subpacket_header(self, spheader): h = HeaderSP() h.parse(spheader) assert 65537 > h.length > 1 assert len(h) == len(h.__bytes__()) _sspclasses = { # 0x00: 'Opaque', # 0x01: 'Opaque', 0x02: 'CreationTime', 0x03: 'SignatureExpirationTime', 0x04: 'ExportableCertification', 0x05: 'TrustSignature', 0x06: 'RegularExpression', 0x07: 'Revocable', # 0x08: 'Opaque', 0x09: 'KeyExpirationTime', # 0x0a: 'AdditionalDecryptionKey', ##TODO: parse this, then uncomment 0x0b: 'PreferredSymmetricAlgorithms', 0x0c: 'RevocationKey', # 0x0d: 'Opaque', # 0x0e: 'Opaque', # 0x0f: 'Opaque', 0x10: 'Issuer', # 0x11: 'Opaque', 0x12: 'Opaque', # reserved # 0x13: 'Opaque', 0x14: 'NotationData', 0x15: 'PreferredHashAlgorithms', 0x16: 'PreferredCompressionAlgorithms', 0x17: 'KeyServerPreferences', 0x18: 'PreferredKeyServer', 0x19: 'PrimaryUserID', 0x1a: 'Policy', 0x1b: 'KeyFlags', 0x1c: 'SignersUserID', 0x1d: 'ReasonForRevocation', 0x1e: 'Features', # 0x1f: 'Target', ##TODO: obtain one of these ##TODO: parse this, then uncomment 0x20: 'EmbeddedSignature', 0x21: 'IssuerFingerprint', 0x23: 'IntendedRecipient', 0x25: 'AttestedCertifications', # 0x64-0x6e: Private or Experimental 0x64: 'Opaque', 0x65: 'Opaque', 0x66: 'Opaque', 0x67: 'Opaque', 0x68: 'Opaque', 0x69: 'Opaque', 0x6a: 'Opaque', 0x6b: 'Opaque', 0x6c: 'Opaque', 0x6d: 'Opaque', 0x6e: 'Opaque', } _uaspclasses = { 0x01: 'Image' } _ssps = [ # 0x02 - creation time b'\x05\x02?z\xf7\x13', # 0x03 - expiration time b'\x05\x03\x00\x12u\x00', # 0x04 - exportable certification b'\x02\x04\x00', # 0x05 b'\x03\x05\x01x', # 0x06 b'\x1d\x06<[^>]+[@.]liebenzell\\.org>$\x00', # 0x07 b'\x02\x07\x00', # 0x08 # 0x09 b'\x05\t\x01\xe13\x80', # 0x0a b'\x17\n\x00\x11M,\x9e,\xee~&\rK\xbd\x9b[\x1b`\xbcu\x0c\xefW\x06', # 0x0b b'\x05\x0b\x07\n\x03\x04', # 0x0c b'\x17\x0c\x80\x119\x06\xf8\xf6\x98d\x9e\xbePG\xd0\xba\x11\xed\xa7\xd0!<\xa1\x1b', # 0x10 b"\t\x10\n'Z\xb6\xb4\xbc\xa5\xd7", # 0x12 b'\x05\x12R/\xe2d', # 0x14 b'\x87\x14\x80\x00\x00\x00\x00\x10\x00nsignotes@grep.be"http://www.grep.be/gpg/CF62318D5BBE' b'D48F33ACD5431B0006256FB29164/0138DA92EDFFB27DD270F86DB475E207BAB58229.asc"', # 0x15 b'\x03\x15\x03\x02', # 0x16 b'\x03\x16\x02\x01', # 0x17 b'\x02\x17\x80', # 0x18 b'\x19\x18hkp://fakekey.server.tld', # 0x19 b'\x02\x19\x01', # 0x1a b'\x15\x1ahttp://www.blaap.org', # 0x1b b'\x02\x1b#', # 0x1c b' \x1cSander Temme ', # 0x1d b'\x02\x1d\x00', # 0x1e b'\x02\x1e\x01', # 0x20 b"\xc0] \x04\x19\x01\n\x00\x06\x05\x02S\x9a6\x06\x00\n\t\x10\x19q\xf7\xb8\x80g\xdd\x07\xd20" b"\x07\xfd\x19\xbb\xea;6|\xdb1\xf3\xbc\xfbZ\x1d\xb6\xcfY\xe6&\xe9\xed\xf1O\xdc\x84\xdd\xe1" b"\x88\xff\xb9\xba\x1a\xe9\x8d\x16K\xd2\xb4\xf49\x7f(\xc9\xe8/\xf6\x87\x0f\xef\xb7*\xf9'r{E" b"\xf3\x07?\xcb\xffm\x87\x86&H\xee\xc4\xbc\xf1L\x177\x92\xdb\xf9I\x16Q\xf6\x9ei\xf56z\x0f\xff" b"^\x92\x88Kh\xbd; \x86\xa5\xbaL\xa2\xda\x93\xae\x10\xd1Y\xa5\xa7\xb4)*\xf6\xa1,]\xd1\xe3\\" b"\xc3l3\xecA\xec&\x145\xe1\xc4\xd0\x15y\xb2\xf8\x0c\x0e\xd3_[\x1f\x0fM\x98\xa8J\xb3\xd9?\xa4" b"\xb3\x16\xee8\xad/\x07\xea\x7f\xad\x1a\x0f\xbe\x06\x94\xa51\xf6@\xae\xcdy\x92B\x1c\xd5\x04z" b"\xbf\xe9\xbc\x9c\xac\x99W6\x81\xad\xe0\x81\xb4\x89n\xd0_\x1c\x92\xbe\xf6\x1cmn\xe92_\x86\xcf" b"\xb0v\x1f\x9dk%\xbd<\x0c\x1e\x91\x0c\xec\\\xdc\x8cCu\xd8N\xf2\x82E\x00\xc8rnSY\x1b\xa0%\x13" b"\xc0$Q+\xd3\xd0\xd8 \x0c\xe9\xafI5&\xe5\xc1!\xaf", # 0x21 b'\x16!\x04\xeb\xc8\x8a\x94\xac\xb1\x10\xf1\xbe?\xe3\xc1+GK\xb0 \x84\xc7\x12', # 0x65 b'\x07eGPG\x00\x01\x01', ] sig_subpkts = [bytearray(sp) + _trailer for sp in _ssps] class TestSignatureSubPackets(object): @pytest.mark.parametrize('sigsubpacket', sig_subpkts) def test_load(self, sigsubpacket): spb = sigsubpacket[:] sp = Signature(spb) assert spb == _trailer assert len(sp) == len(sigsubpacket) - len(_trailer) assert len(sp) == len(sp.__bytes__()) assert sp.__bytes__() == bytes(sigsubpacket[:-len(_trailer)]) if sp.header.typeid in _sspclasses: assert sp.__class__.__name__ == _sspclasses[sp.header.typeid] else: assert isinstance(sp, OpaqueSP) _uassps = [ # 0x01 b'\xc3\xfd\x01\x10\x00\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xd8\xff' b'\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x84\x00\xff\xff\xff' b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\xff\xff\xff\xff' b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\x11\x08\x00x' b'\x00x\x03\x01\x11\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x01\xa2\x00\x00\x01\x05\x01\x01\x01' b'\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x10' b'\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05' b'\x12!1A\x06\x13Qa\x07"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17' b'\x18\x19\x1a%&\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a' b'\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5' b'\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9' b'\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\x01' b'\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05' b'\x06\x07\x08\t\n\x0b\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02w\x00' b'\x01\x02\x03\x11\x04\x05!1\x06\x12AQ\x07aq\x13"2\x81\x08\x14B\x91\xa1\xb1\xc1\t#3R\xf0\x15' b'br\xd1\n\x16$4\xe1%\xf1\x17\x18\x19\x1a&\'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x82' b'\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6' b'\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca' b'\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5' b'\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00?\x00\x92\x80\n\x00(' b'\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n' b'\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80' b'\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02' b'\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0' b'\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x04\xc8\x1dH\xa0\x03' b'#\xd4~t\x00\xb4\x00P\x02d\x0e\xa6\x80\x0c\x83\xd0\x8a\x00Z\x00:P\x02dz\x8f\xccP\x02\xd0' b'\x01@\x05\x00\x14\x00P\x01@\x11cs\x1c\xfb\xd0\x03\xb6\x0fS@\r\x19V\xc7j\x00{\x1c\x0f~\xd4' b'\x00\xc0\xb9\xe4\x9e\xb4\x00\xa5;\x8c\xd0\x02\xa1\xc8\xe7\xb5\x005\xb9`>\x9f\xce\x80\x1d' b'\xb0z\x9a\x00i\x05\x0eA\xa0\t\x01\xc8\x07\xd6\x80\x16\x80\n\x00(\x00\xa0\x08\x81\x01\x89>' b'\xff\x00\xce\x80\x1d\xbdh\x01\xbfy\xb3\xd8P\x00\xfdG\xd2\x80%\xa0\x06\xeeQ\xde\x80\x14\x10' b'zP\x04m\xf7\x87\xe1\xfc\xe8\x01\xfb\xd6\x80\x18\xc7v\x00\xa0\x05q\xf2\x8fj\x00z\x9c\x80h' b'\x01\x87\xe6\x7f\xa7\xf4\xa0\t(\x00\xa0\x08\x80\x05\x8e}\xff\x00\x9d\x00I\xb5}\x05\x00/N' b'\x94\x01\x1b\x8e\x87\xf0\xa0\x07\x83\x91\x9a\x00B\xab\xd4\x8a\x00ju4\x00\x8d\xf7\x87\xe1' b'\xfc\xe8\x02M\xab\xe8(\x00\x00\x0e\x82\x80\x14\xf21@\x11)\xdb\xb8\x1f\xf2h\x01\xc8:\x9fZ' b'\x00}\x00\x14\x00\xc0\xa41=\xb9\xfdh\x01\xf4\x00P\x02\x11\x9e\r\x003k\x0e\x86\x80\x0c9\xeb' b'\xd3\xfc\xfaP\x02\xa8 \x9c\xd0\x00T\x96\x07\xb7\x1f\xa5\x00>\x80\n\x00(\x02\'\x1f7\x1d\xe8' b'\x02@01@\x0b@\x05\x00\x14\x00P\x01@\x05\x00\x14\x00P\x01@\x05\x00\x14\x00P\x01@\t\x81\x9c' b'\xf7\xa0\x05\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02' b'\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0' b'\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00' b'\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(\x00\xa0\x02\x80\n\x00(' b'\x00\xa0\x02\x80?\xff\xd9', ] ua_subpkts = [bytearray(sp) + _trailer for sp in _uassps] class TestUserAttributeSubPackets(object): @pytest.mark.parametrize('uasubpacket', ua_subpkts) def test_load(self, uasubpacket): spb = uasubpacket[:] sp = UserAttribute(spb) assert spb == _trailer assert len(sp) == len(uasubpacket) - len(_trailer) assert len(sp) == len(sp.__bytes__()) assert sp.__bytes__() == uasubpacket[:-len(_trailer)] if sp.header.typeid in _uaspclasses: assert sp.__class__.__name__ == _uaspclasses[sp.header.typeid] else: assert isinstance(sp, OpaqueSP) _s2k_parts = [ # usage byte is always \xff b'\xff', # symmetric cipher algorithm list b'\x01\x02\x03\x04\x07\x08\x09\x0B\x0C\x0D', # specifier # b'\x00', (simple) # b'\x01', (iterated) # b'\x03', (salted) # hash algorithm list b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B', ] _iv = b'\xDE\xAD\xBE\xEF\xDE\xAD\xBE\xEF' _salt = b'\xC0\xDE\xC0\xDE\xC0\xDE\xC0\xDE' _count = b'\x10' # expands from 0x10 to 2048 _gnu_scserials = [ # standard 16 bytes serial bytearray(range(16)), # shorter serial b'\x42\x43\x44\x45' ] # simple S2Ks sis2ks = [bytearray(i) + _iv for i in itertools.product(*(_s2k_parts[:2] + [b'\x00'] + _s2k_parts[2:]))] # salted S2Ks sas2ks = [bytearray(i) + _salt + _iv for i in itertools.product(*(_s2k_parts[:2] + [b'\x01'] + _s2k_parts[2:]))] # iterated S2Ks is2ks = [bytearray(i) + _salt + _count + _iv for i in itertools.product(*(_s2k_parts[:2] + [b'\x03'] + _s2k_parts[2:]))] # GNU extension S2Ks gnus2ks = [bytearray(b'\xff\x00\x65\x00GNU' + i) for i in ([b'\x01'] + [b'\x02' + bytearray([len(s)]) + s for s in _gnu_scserials])] class TestString2Key(object): @pytest.mark.parametrize('sis2k', sis2ks) def test_simple_string2key(self, sis2k): b = sis2k[:] s = String2Key() s.parse(sis2k) assert len(sis2k) == 0 assert len(s) == len(b) assert s.__bytes__() == b assert bool(s) assert s.halg in HashAlgorithm assert s.encalg in SymmetricKeyAlgorithm assert s.specifier == String2KeyType.Simple assert s.iv == _iv @pytest.mark.parametrize('sas2k', sas2ks) def test_salted_string2key(self, sas2k): b = sas2k[:] s = String2Key() s.parse(sas2k) assert len(sas2k) == 0 assert len(s) == len(b) assert s.__bytes__() == b assert bool(s) assert s.halg in HashAlgorithm assert s.encalg in SymmetricKeyAlgorithm assert s.specifier == String2KeyType.Salted assert s.salt == _salt assert s.iv == _iv @pytest.mark.parametrize('is2k', is2ks) def test_iterated_string2key(self, is2k): b = is2k[:] s = String2Key() s.parse(is2k) assert len(is2k) == 0 assert len(s) == len(b) assert s.__bytes__() == b assert bool(s) assert s.halg in HashAlgorithm assert s.encalg in SymmetricKeyAlgorithm assert s.specifier == String2KeyType.Iterated assert s.salt == _salt assert s.count == 2048 assert s.iv == _iv @pytest.mark.parametrize('gnus2k', gnus2ks) def test_gnu_extension_string2key(self, gnus2k): b = gnus2k[:] s = String2Key() s.parse(gnus2k) assert len(gnus2k) == 0 assert len(s) == len(b) assert s.__bytes__() == b assert bool(s) assert s.encalg == SymmetricKeyAlgorithm.Plaintext assert s.specifier == String2KeyType.GNUExtension assert s.gnuext in S2KGNUExtension if s.gnuext == S2KGNUExtension.Smartcard: assert s.scserial is not None and len(s.scserial) <= 16 PGPy-0.5.4/tests/test_01_types.py000066400000000000000000000045051403641706600165710ustar00rootroot00000000000000# coding=utf-8 """ test types """ import pytest from pgpy.types import PGPObject text = { # some basic utf-8 test strings - these should all pass 'english': u'The quick brown fox jumped over the lazy dog', # this hiragana pangram comes from http://www.columbia.edu/~fdc/utf8/ 'hiragana': u'いろはにほへど ちりぬるを\n' u'わがよたれぞ つねならむ\n' u'うゐのおくやま けふこえて\n' u'あさきゆめみじ ゑひもせず', 'poo': u'Hello, \U0001F4A9!', } # some alternate encodings to try # these should fail encoded_text = { # try some alternate encodings as well # 'crunch the granite of science' 'cyrillic': u'грызть гранит науки'.encode('iso8859_5'), # 'My hovercraft is full of eels' 'cp865': u'Mit luftpudefartøj er fyldt med ål'.encode('cp865'), } # test harness for pgpy.types.PGPObject, since it defines a couple of abstract methods class FakePGPObject(PGPObject): @classmethod def new(cls, text): obj = FakePGPObject() obj.data = cls.text_to_bytes(text) return obj def __init__(self): self.data = bytearray() def __bytearray__(self): return bytearray(b'_fake_') + self.data def parse(self, packet): self.data = packet class TestPGPObject(object): @pytest.mark.regression(issue=154) @pytest.mark.parametrize('text', [v for _, v in sorted(text.items())], ids=sorted(text.keys())) def test_text_to_bytes(self, text): pgpo = FakePGPObject.new(text) assert pgpo.__bytearray__() == bytearray(b'_fake_') + bytearray(text, 'utf-8') @pytest.mark.regression(issue=154) @pytest.mark.parametrize('encoded_text', [v for _, v in sorted(encoded_text.items())], ids=sorted(encoded_text.keys())) def test_text_to_bytes_encodings(self, encoded_text): pgpo = FakePGPObject.new(encoded_text) # this should fail with pytest.raises(UnicodeDecodeError): pgpo.data.decode('utf-8') def test_text_to_bytes_none(self): assert PGPObject.text_to_bytes(None) is None def test_bytes_to_text_none(self): assert PGPObject.bytes_to_text(None) is None def test_bytes_to_text_text(self): assert PGPObject.bytes_to_text('asdf') == 'asdf' PGPy-0.5.4/tests/test_02_packets.py000066400000000000000000000045431403641706600170620ustar00rootroot00000000000000""" test parsing packets """ import pytest import glob import os from pgpy.packet import Packet from pgpy.packet import PubKeyV4, PubSubKeyV4, PrivKeyV4, PrivSubKeyV4 from pgpy.packet import Opaque # import pgpy.packet.fields _trailer = b'\xde\xca\xff\xba\xdd' _pclasses = { (0x01, 3): 'PKESessionKeyV3', (0x02, 4): 'SignatureV4', (0x03, 4): 'SKESessionKeyV4', (0x04, 3): 'OnePassSignatureV3', (0x05, 4): 'PrivKeyV4', (0x06, 4): 'PubKeyV4', (0x07, 4): 'PrivSubKeyV4', 0x08: 'CompressedData', 0x09: 'SKEData', 0x0A: 'Marker', 0x0B: 'LiteralData', 0x0C: 'Trust', 0x0D: 'UserID', (0x0E, 4): 'PubSubKeyV4', 0x11: 'UserAttribute', (0x12, 1): 'IntegrityProtectedSKEDataV1', 0x13: 'MDC', } def binload(f): with open(f, 'rb') as ff: buf = bytearray(os.fstat(ff.fileno()).st_size) ff.readinto(buf) return buf pktfiles = sorted(glob.glob('tests/testdata/packets/[0-9]*')) class TestPacket(object): @pytest.mark.parametrize('packet', pktfiles, ids=[os.path.basename(f) for f in pktfiles]) def test_load(self, packet): b = binload(packet) + _trailer _b = b[:] p = Packet(_b) # parsed all bytes assert _b == _trailer # length is computed correctly assert p.header.length + len(p.header) == len(p) if packet not in ('tests/testdata/packets/11.partial.literal',): assert len(p) == len(b) - len(_trailer) assert len(p.__bytes__()) == len(b) - len(_trailer) # __bytes__ output is correct assert p.__bytes__() == b[:-len(_trailer)] # instantiated class is what we expected if hasattr(p.header, 'version') and (p.header.tag, p.header.version) in _pclasses: # versioned packet assert p.__class__.__name__ == _pclasses[(p.header.tag, p.header.version)] elif (not hasattr(p.header, 'version')) and p.header.tag in _pclasses: # unversioned packet assert p.__class__.__name__ in _pclasses[p.header.tag] else: # fallback to opaque assert isinstance(p, Opaque) # if this is a key, ensure len(p.keymaterial) == len(bytes(p.keymaterial)) if isinstance(p, (PubKeyV4, PubSubKeyV4, PrivKeyV4, PrivSubKeyV4)): assert len(p.keymaterial) == len(p.keymaterial.__bytes__()) PGPy-0.5.4/tests/test_03_armor.py000066400000000000000000000327151403641706600165530ustar00rootroot00000000000000""" test (de)armoring of PGP blocks """ import pytest import glob import os from datetime import datetime from pgpy.constants import HashAlgorithm from pgpy.constants import PubKeyAlgorithm from pgpy.constants import SignatureType from pgpy.pgp import PGPKey from pgpy.pgp import PGPMessage from pgpy.pgp import PGPSignature from pgpy.types import Armorable blocks = sorted(glob.glob('tests/testdata/blocks/*.asc')) block_attrs = { 'tests/testdata/blocks/message.ascii.asc': [('encrypters', set()), ('filename', 'ascii'), ('is_compressed', False), ('is_encrypted', False), ('is_signed', False), ('issuers', set()), ('message', "This is stored, textually!\r\n"), ('signers', set()), ('type', 'literal'),], 'tests/testdata/blocks/message.compressed.asc': [('encrypters', set()), ('filename', 'lit'), ('is_compressed', True), ('is_encrypted', False), ('is_signed', False), ('issuers', set()), ('message', b"This is stored, literally\\!\n\n"), ('signers', set()), ('type', 'literal'),], 'tests/testdata/blocks/message.literal.asc': [('encrypters', set()), ('filename', 'lit'), ('is_compressed', False), ('is_encrypted', False), ('is_signed', False), ('issuers', set()), ('message', b"This is stored, literally\\!\n\n"), ('signers', set()), ('type', 'literal'),], 'tests/testdata/blocks/message.onepass.asc': [('encrypters', set()), ('filename', 'lit'), ('is_compressed', False), ('is_encrypted', False), ('is_signed', True), ('issuers', {'2A834D8E5918E886'}), ('message', b"This is stored, literally\\!\n\n"), ('signers', {'2A834D8E5918E886'}), ('type', 'literal'),], 'tests/testdata/blocks/message.two_onepass.asc': [('encrypters', set()), ('filename', 'lit'), ('is_compressed', False), ('is_encrypted', False), ('is_signed', True), ('issuers', {'2A834D8E5918E886', 'A5DCDC966453140E'}), ('message', b"This is stored, literally\\!\n\n"), ('signers', {'2A834D8E5918E886', 'A5DCDC966453140E'}), ('type', 'literal'),], 'tests/testdata/blocks/message.signed.asc': [('encrypters', set()), ('filename', 'lit'), ('is_compressed', False), ('is_encrypted', False), ('is_signed', True), ('issuers', {'2A834D8E5918E886'}), ('message', b"This is stored, literally\\!\n\n"), ('signers', {'2A834D8E5918E886'}), ('type', 'literal'),], 'tests/testdata/blocks/cleartext.asc': [('encrypters', set()), ('is_compressed', False), ('is_encrypted', False), ('is_signed', True), ('issuers', {'2A834D8E5918E886'}), ('message', "This is stored, literally\\!\n"), ('signers', {'2A834D8E5918E886'}), ('type', 'cleartext'),], 'tests/testdata/blocks/cleartext.twosigs.asc': [('encrypters', set()), ('is_compressed', False), ('is_encrypted', False), ('is_signed', True), ('issuers', {'2A834D8E5918E886', 'A5DCDC966453140E'}), ('message', "This is stored, literally\\!\n"), ('signers', {'2A834D8E5918E886', 'A5DCDC966453140E'}), ('type', 'cleartext'),], 'tests/testdata/blocks/message.encrypted.asc': [('encrypters', {'EEE097A017B979CA'}), ('is_compressed', False), ('is_encrypted', True), ('is_signed', False), ('issuers', {'EEE097A017B979CA'}), ('signers', set()), ('type', 'encrypted')], 'tests/testdata/blocks/message.encrypted.signed.asc': [('encrypters', {'EEE097A017B979CA'}), ('is_compressed', False), ('is_encrypted', True), ('is_signed', False), ('issuers', {'EEE097A017B979CA'}), ('signers', set()), ('type', 'encrypted')], 'tests/testdata/blocks/message.ecc.encrypted.asc': [('encrypters', {'77CEB7A34089AB73'}), ('is_compressed', False), ('is_encrypted', True), ('is_signed', False), ('issuers', {'77CEB7A34089AB73'}), ('signers', set()), ('type', 'encrypted')], 'tests/testdata/blocks/revochiio.asc': [('created', datetime(2014, 9, 11, 22, 55, 53)), ('fingerprint', "AE15 9FF3 4C1A 2426 B7F8 0F1A 560C F308 EF60 CFA3"), ('expires_at', datetime(2018, 9, 12, 1, 0, 59)), ('is_expired', True), ('is_primary', True), ('is_protected', False), ('is_public', True), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.RSAEncryptOrSign), ('magic', "PUBLIC KEY BLOCK"), ('parent', None), ('signers', {'560CF308EF60CFA3'}),], 'tests/testdata/blocks/expyro.asc': [('created', datetime(1970, 1, 1)), ('expires_at', datetime(1970, 1, 2)), ('fingerprint', '24EB C1B0 29B1 FCF8 29A5 C150 1A48 291A FB91 A533'), ('is_expired', True),], 'tests/testdata/blocks/rsapubkey.asc': [('created', datetime(2014, 7, 23, 21, 19, 24)), ('expires_at', None), ('fingerprint', "F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36"), ('is_expired', False), ('is_primary', True), ('is_protected', False), ('is_public', True), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.RSAEncryptOrSign), ('magic', "PUBLIC KEY BLOCK"), ('parent', None), ('signers', set()),], 'tests/testdata/blocks/rsaseckey.asc': [('created', datetime(2014, 7, 23, 21, 19, 24)), ('expires_at', None), ('fingerprint', "F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36"), ('is_expired', False), ('is_primary', True), ('is_protected', False), ('is_public', False), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.RSAEncryptOrSign), ('magic', "PRIVATE KEY BLOCK"), ('parent', None), ('signers', set()),], 'tests/testdata/blocks/rsasignature.asc': [('__sig__', b'\x70\x38\x79\xd0\x58\x70\x58\x7b\x50\xe6\xab\x8f\x9d\xc3\x46\x2c\x5a\x6b\x98\x96\xcf' b'\x3b\xa3\x79\x13\x08\x6d\x90\x9d\x67\xd2\x48\x7d\xd7\x1a\xa5\x98\xa7\x8f\xca\xe3\x24' b'\xd4\x19\xab\xe5\x45\xc5\xff\x21\x0c\x72\x88\x91\xe6\x67\xd7\xe5\x00\xb3\xf5\x55\x0b' b'\xd0\xaf\x77\xb3\x7e\xa4\x79\x59\x06\xa2\x05\x44\x9d\xd2\xa9\xcf\xb1\xf8\x03\xc1\x90' b'\x81\x87\x36\x1a\xa6\x5c\x79\x98\xfe\xdb\xdd\x23\x54\x69\x92\x2f\x0b\xc4\xee\x2a\x61' b'\x77\x35\x59\x6e\xb2\xe2\x1b\x80\x61\xaf\x2d\x7a\x64\x38\xfe\xe3\x95\xcc\xe8\xa4\x05' b'\x55\x5d'), ('cipherprefs', []), ('compprefs', []), ('created', datetime.utcfromtimestamp(1402615373)), ('embedded', False), ('exportable', True), ('features', set()), ('hash2', b'\xc4\x24'), ('hashprefs', []), ('hash_algorithm', HashAlgorithm.SHA512), ('is_expired', False), ('key_algorithm', PubKeyAlgorithm.RSAEncryptOrSign), ('key_flags', set()), ('keyserver', ''), ('keyserverprefs', []), ('magic', "SIGNATURE"), ('notation', {}), ('policy_uri', ''), ('revocable', True), ('revocation_key', None), ('signer', 'FCAE54F74BA27CF7'), ('type', SignatureType.BinaryDocument)], 'tests/testdata/blocks/eccpubkey.asc': [('created', datetime(2010, 9, 17, 20, 33, 49)), ('expires_at', None), ('fingerprint', "502D 1A53 65D1 C0CA A699 4539 0BA5 2DF0 BAA5 9D9C"), ('is_expired', False), ('is_primary', True), ('is_protected', False), ('is_public', True), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.ECDSA), ('magic', "PUBLIC KEY BLOCK"), ('parent', None), ('signers', set()),], 'tests/testdata/blocks/eccseckey.asc': [('created', datetime(2010, 9, 17, 20, 33, 49)), ('expires_at', None), ('fingerprint', "502D 1A53 65D1 C0CA A699 4539 0BA5 2DF0 BAA5 9D9C"), ('is_expired', False), ('is_primary', True), ('is_protected', True), ('is_public', False), ('is_unlocked', False), ('key_algorithm', PubKeyAlgorithm.ECDSA), ('magic', "PRIVATE KEY BLOCK"), ('parent', None), ('signers', set()),], 'tests/testdata/blocks/dsaseckey.asc': [('created', datetime(2017, 2, 21, 19, 21, 41)), ('expires_at', None), ('fingerprint', "2B5B BB14 3BA0 B290 DCEE 6668 B798 AE89 9087 7201"), ('is_expired', False), ('is_primary', True), ('is_protected', True), ('is_public', False), ('is_unlocked', False), ('key_algorithm', PubKeyAlgorithm.DSA),], 'tests/testdata/blocks/dsapubkey.asc': [('created', datetime(2017, 2, 21, 19, 21, 41)), ('expires_at', None), ('fingerprint', "2B5B BB14 3BA0 B290 DCEE 6668 B798 AE89 9087 7201"), ('is_expired', False), ('is_primary', True), ('is_protected', False), ('is_public', True), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.DSA),], 'tests/testdata/blocks/openpgp.js.pubkey.asc': [('created', datetime(2016, 6, 2, 21, 57, 13)), ('expires_at', None), ('fingerprint', "C7C3 8ECE E94A 4AD3 2DDB 064E 14AB 44C7 4D1B DAB8"), ('is_expired', False), ('is_primary', True), ('is_protected', False), ('is_public', True), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.RSAEncryptOrSign), ('magic', "PUBLIC KEY BLOCK"), ('parent', None), ('signers', set()), ], 'tests/testdata/blocks/openpgp.js.seckey.asc': [('created', datetime(2016, 6, 2, 21, 57, 13)), ('expires_at', None), ('fingerprint', "C7C3 8ECE E94A 4AD3 2DDB 064E 14AB 44C7 4D1B DAB8"), ('is_expired', False), ('is_primary', True), ('is_protected', False), ('is_public', False), ('is_unlocked', True), ('key_algorithm', PubKeyAlgorithm.RSAEncryptOrSign), ('magic', "PRIVATE KEY BLOCK"), ('parent', None), ('signers', set()), ], 'tests/testdata/blocks/signature.expired.asc': [('created', datetime(2014, 9, 28, 20, 54, 42)), ('is_expired', True),], 'tests/testdata/blocks/signature.non-exportable.asc': [('created', datetime(2017, 2, 21, 20, 43, 34)), ('exportable', False),] } # generic block tests class TestBlocks(object): @pytest.mark.parametrize('block', blocks, ids=[os.path.basename(f) for f in blocks]) def test_load_blob(self, block): with open(block) as bf: bc = bf.read() if 'SIGNATURE' in bc.splitlines()[0]: p = PGPSignature() elif 'KEY' in bc.splitlines()[0]: p = PGPKey() elif 'MESSAGE' in bc.splitlines()[0]: p = PGPMessage() else: pytest.skip("not ready for file '{}'".format(os.path.basename(block))) assert False # load ASCII p.parse(bc) # check str output # assert str(p) == bc # now check attrs assert block in block_attrs for attr, val in block_attrs[block]: attrval = getattr(p, attr) # this is probably more helpful than just 'assert attrval == val' if attrval != val: raise AssertionError('expected block.{attr:s} = {aval}; got block.{attr:s} = {rval}' ''.format(attr=attr, aval=val, rval=attrval)) armored = glob.glob('tests/testdata/*/*.asc') txt = glob.glob('tests/testdata/files/*.txt') binary = glob.glob('tests/testdata/files/*.bin') raw = txt + binary # armor matching test class TestMatching(object): @pytest.mark.parametrize('armored', armored, ids=[os.path.basename(f) for f in armored]) def test_is_armor(self, armored): with open(armored) as af: ac = af.read() assert Armorable.is_armor(ac) @pytest.mark.parametrize('text', raw, ids=[os.path.basename(f) for f in raw]) def test_not_armor(self, text): mode = 'r' if text in txt else 'rb' with open(text, mode) as tf: tc = tf.read() assert not Armorable.is_armor(tc) PGPy-0.5.4/tests/test_04_PGP_objects.py000066400000000000000000000274771403641706600176040ustar00rootroot00000000000000""" test the functionality of PGPKeyring """ import pytest import glob import os import six from pgpy import PGPKey from pgpy import PGPKeyring from pgpy import PGPMessage from pgpy import PGPSignature from pgpy import PGPUID from pgpy.types import Fingerprint @pytest.fixture def abe_image(): with open('tests/testdata/abe.jpg', 'rb') as abef: abebytes = bytearray(os.path.getsize('tests/testdata/abe.jpg')) abef.readinto(abebytes) return PGPUID.new(abebytes) _msgfiles = sorted(glob.glob('tests/testdata/messages/*.asc')) class TestPGPMessage(object): @pytest.mark.parametrize('msgfile', _msgfiles, ids=[os.path.basename(f) for f in _msgfiles]) def test_load_from_file(self, msgfile): # TODO: figure out a good way to verify that all went well here, because # PGPy reorders signatures sometimes, and also unwraps compressed messages # so comparing str(msg) to the contents of msgfile doesn't actually work msg = PGPMessage.from_file(msgfile) with open(msgfile, 'r') as mf: mt = mf.read() assert len(str(msg)) == len(mt) @pytest.fixture def un(): return PGPUID.new(six.u('Temperair\xe9e Youx\'seur')) @pytest.fixture def unc(): return PGPUID.new(six.u('Temperair\xe9e Youx\'seur'), comment=six.u('\u2603')) @pytest.fixture def une(): return PGPUID.new(six.u('Temperair\xe9e Youx\'seur'), email='snowman@not.an.email.addre.ss') @pytest.fixture def unce(): return PGPUID.new(six.u('Temperair\xe9e Youx\'seur'), comment=six.u('\u2603'), email='snowman@not.an.email.addre.ss') @pytest.fixture def abe(): return PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='abraham.lincoln@whitehouse.gov') class TestPGPUID(object): def test_userid(self, abe): assert abe.name == 'Abraham Lincoln' assert abe.comment == 'Honest Abe' assert abe.email == 'abraham.lincoln@whitehouse.gov' assert abe.image is None def test_userphoto(self, abe_image): assert abe_image.name == "" assert abe_image.comment == "" assert abe_image.email == "" with open('tests/testdata/abe.jpg', 'rb') as abef: abebytes = bytearray(os.path.getsize('tests/testdata/abe.jpg')) abef.readinto(abebytes) assert abe_image.image == abebytes def test_format(self, un, unc, une, unce): assert six.u("{:s}").format(un) == six.u('Temperair\xe9e Youx\'seur') assert six.u("{:s}").format(unc) == six.u('Temperair\xe9e Youx\'seur (\u2603)') assert six.u("{:s}").format(une) == six.u('Temperair\xe9e Youx\'seur ') assert six.u("{:s}").format(unce) == six.u('Temperair\xe9e Youx\'seur (\u2603) ') _keyfiles = sorted(glob.glob('tests/testdata/blocks/*key*.asc')) _fingerprints = {'dsapubkey.asc': '2B5BBB143BA0B290DCEE6668B798AE8990877201', 'dsaseckey.asc': '2B5BBB143BA0B290DCEE6668B798AE8990877201', 'eccpubkey.asc': '502D1A5365D1C0CAA69945390BA52DF0BAA59D9C', 'eccseckey.asc': '502D1A5365D1C0CAA69945390BA52DF0BAA59D9C', 'openpgp.js.pubkey.asc': 'C7C38ECEE94A4AD32DDB064E14AB44C74D1BDAB8', 'openpgp.js.seckey.asc': 'C7C38ECEE94A4AD32DDB064E14AB44C74D1BDAB8', 'rsapubkey.asc': 'F4294BC8094A7E0585C85E8637473B3758C44F36', 'rsaseckey.asc': 'F4294BC8094A7E0585C85E8637473B3758C44F36',} class TestPGPKey(object): @pytest.mark.parametrize('kf', _keyfiles, ids=[os.path.basename(f) for f in _keyfiles]) def test_load_from_file(self, kf): key, _ = PGPKey.from_file(kf) assert key.fingerprint == _fingerprints[os.path.basename(kf)] @pytest.mark.parametrize('kf', _keyfiles, ids=[os.path.basename(f) for f in _keyfiles]) def test_load_from_str(self, kf): with open(kf, 'r') as tkf: key, _ = PGPKey.from_blob(tkf.read()) assert key.fingerprint == _fingerprints[os.path.basename(kf)] @pytest.mark.regression(issue=140) @pytest.mark.parametrize('kf', _keyfiles, ids=[os.path.basename(f) for f in _keyfiles]) def test_load_from_bytes(self, kf): with open(kf, 'rb') as tkf: key, _ = PGPKey.from_blob(tkf.read()) assert key.fingerprint == _fingerprints[os.path.basename(kf)] @pytest.mark.regression(issue=140) @pytest.mark.parametrize('kf', _keyfiles, ids=[os.path.basename(f) for f in _keyfiles]) def test_load_from_bytearray(self, kf): tkb = bytearray(os.stat(kf).st_size) with open(kf, 'rb') as tkf: tkf.readinto(tkb) key, _ = PGPKey.from_blob(tkb) assert key.fingerprint == _fingerprints[os.path.basename(kf)] @pytest.mark.parametrize('kf', sorted(filter(lambda f: not f.endswith('enc.asc'), glob.glob('tests/testdata/keys/*.asc')))) def test_save(self, kf): # load the key and export it back to binary key, _ = PGPKey.from_file(kf) pgpyblob = key.__bytes__() # try loading the exported key reloaded, _ = PGPKey.from_file(kf) assert pgpyblob == reloaded.__bytes__() @pytest.fixture(scope='module') def keyring(): return PGPKeyring() class TestPGPKeyring(object): def test_load(self, keyring): # load from filenames keys = keyring.load(glob.glob('tests/testdata/*test.asc'), glob.glob('tests/testdata/signatures/*.key.asc')) # keys assert all(isinstance(k, Fingerprint) for k in keys) # __len__ assert len(keys) == 10 assert len(keyring) == 16 # __contains__ # RSA von TestKey selectors = ["F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36", "37473B3758C44F36", "58C44F36", "RSA von TestKey", "rsa@test.key"] for selector in selectors: assert selector in keyring # DSA von TestKey selectors = ["EBC8 8A94 ACB1 10F1 BE3F E3C1 2B47 4BB0 2084 C712", "2B474BB02084C712", "2084C712", "DSA von TestKey", "dsa@test.key"] for selector in selectors: assert selector in keyring # fingerprints filtering # we have 10 keys assert len(keyring.fingerprints()) == 10 # 10 public halves, 6 private halves assert len(keyring.fingerprints(keyhalf='public')) == 10 assert len(keyring.fingerprints(keyhalf='private')) == 6 # we have 5 primary keys; 5 public and 2 private assert len(keyring.fingerprints(keytype='primary')) == 5 assert len(keyring.fingerprints(keytype='primary', keyhalf='public')) == 5 assert len(keyring.fingerprints(keytype='primary', keyhalf='private')) == 2 # and the other 5; 5 public and 4 private assert len(keyring.fingerprints(keytype='sub')) == 5 assert len(keyring.fingerprints(keytype='sub', keyhalf='public')) == 5 assert len(keyring.fingerprints(keytype='sub', keyhalf='private')) == 4 # now test sorting: rvt = keyring._get_keys("RSA von TestKey") assert len(rvt) == 2 assert not rvt[0].is_public assert rvt[1].is_public @pytest.mark.parametrize('kf', _keyfiles, ids=[os.path.basename(f) for f in _keyfiles]) def test_load_key_instance(self, keyring, kf): key, _ = PGPKey.from_file(kf) keys = keyring.load(key) assert key.fingerprint in keyring for uid in key.userids: if uid.name != "": assert uid.name in keyring if uid.email != "": assert uid.email in keyring with keyring.key(key.fingerprint) as loaded_key: assert loaded_key.fingerprint == key.fingerprint def test_select_fingerprint(self, keyring): for fp, name in [("F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36", "RSA von TestKey"), (six.u("F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36"), six.u("RSA von TestKey")), (Fingerprint("F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36"), "RSA von TestKey"), ("EBC8 8A94 ACB1 10F1 BE3F E3C1 2B47 4BB0 2084 C712", "DSA von TestKey"), (six.u("EBC8 8A94 ACB1 10F1 BE3F E3C1 2B47 4BB0 2084 C712"), six.u("DSA von TestKey")), (Fingerprint("EBC8 8A94 ACB1 10F1 BE3F E3C1 2B47 4BB0 2084 C712"), "DSA von TestKey"),]: with keyring.key(fp) as key: assert key.fingerprint == fp assert key.userids[0].name == name def test_select_keyid(self, keyring): with keyring.key("37473B3758C44F36") as rsa: assert rsa.userids[0].name == "RSA von TestKey" with keyring.key("2B474BB02084C712") as dsa: assert dsa.userids[0].name == "DSA von TestKey" def test_select_shortid(self, keyring): with keyring.key("58C44F36") as rsa: assert rsa.userids[0].name == "RSA von TestKey" with keyring.key("2084C712") as dsa: assert dsa.userids[0].name == "DSA von TestKey" def test_select_name(self, keyring): with keyring.key("RSA von TestKey") as rsa: assert rsa.userids[0].name == "RSA von TestKey" with keyring.key("DSA von TestKey") as dsa: assert dsa.userids[0].name == "DSA von TestKey" def test_select_comment(self, keyring): with keyring.key("2048-bit RSA") as rsa: assert rsa.userids[0].name == "RSA von TestKey" with keyring.key("2048-bit DSA") as dsa: assert dsa.userids[0].name == "DSA von TestKey" def test_select_email(self, keyring): with keyring.key("rsa@test.key") as rsa: assert rsa.userids[0].name == "RSA von TestKey" with keyring.key("dsa@test.key") as dsa: assert dsa.userids[0].name == "DSA von TestKey" def test_select_pgpsignature(self, keyring): sig = PGPSignature() with open('tests/testdata/signatures/debian-sid.sig.asc', 'r') as sigf: sig.parse(sigf.read()) with keyring.key(sig) as sigkey: assert sigkey.fingerprint.keyid == sig.signer def test_select_pgpmessage(self, keyring): m1 = PGPMessage() with open('tests/testdata/messages/message.rsa.cast5.asc', 'r') as m1f: m1.parse(m1f.read()) with keyring.key(m1) as rsakey: assert rsakey.fingerprint == "00EC FAF5 48AE B655 F861 8193 EEE0 97A0 17B9 79CA" assert rsakey.parent.fingerprint == "F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36" def test_unload_key(self, keyring): with keyring.key("Test Repository Signing Key") as key: keyring.unload(key) # is the key and its subkeys actually gone? assert id(key) not in keyring._keys for pkid in iter(id(sk) for sk in key.subkeys.values()): assert pkid not in keyring._keys # aliases # userid components assert "Test Repository Signing Key" not in keyring assert "KUS" not in keyring assert "usc-kus@securityinnovation.com" not in keyring # fingerprints assert "513B 160A A994 8C1F 3D77 952D CE57 0774 D0FD CA20" not in keyring # keyid(s) assert "CE570774D0FDCA20" not in keyring # shortids assert "D0FDCA20" not in keyring def test_unload_key_half(self, keyring): with keyring.key('RSA von TestKey') as key: keyring.unload(key) # key was unloaded for real assert id(key) not in keyring._keys # but it was not a unique alias, because we only unloaded half of the key # userid components assert 'RSA von TestKey' in keyring assert '2048-bit RSA' in keyring assert 'rsa@test.key' in keyring # fingerprint, keyid, shortid assert 'F429 4BC8 094A 7E05 85C8 5E86 3747 3B37 58C4 4F36' in keyring assert '37473B3758C44F36' in keyring assert '58C44F36' in keyring PGPy-0.5.4/tests/test_04_copy.py000066400000000000000000000061501403641706600164000ustar00rootroot00000000000000""" test copying PGP objects """ from __future__ import print_function import pytest import copy import glob import inspect import os.path import six import pgpy from pgpy import PGPSignature, PGPUID, PGPMessage, PGPKey _keys = glob.glob('tests/testdata/keys/*.1.pub.asc') + glob.glob('tests/testdata/keys/*.1.sec.asc') _msgs = [ 'tests/testdata/messages/message.{}.asc'.format(f) for f in ['signed', 'rsa.cast5.no-mdc', 'rsa.dsa.pass.aes']] def sig(): return PGPSignature.from_file('tests/testdata/blocks/rsasignature.asc') def uid(): return PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='abraham.lincoln@whitehouse.gov') def key(fn): key, _ = PGPKey.from_file(fn) return key def walk_obj(obj, prefix=""): from enum import Enum for name, val in inspect.getmembers(obj): if hasattr(obj.__class__, name): continue yield '{}{}'.format(prefix, name), val if not isinstance(val, Enum): for n, v in walk_obj(val, prefix="{}{}.".format(prefix, name)): yield n, v def check_id(obj): from datetime import datetime from enum import Enum # do some type checking to determine if we should check the identity of an object member # these types are singletons if isinstance(obj, (Enum, bool, type(None))): return False # these types are immutable if isinstance(obj, (six.string_types, datetime)): return False # integers are kind of a special case. # ints that do not exceed sys.maxsize are singletons, and in either case are immutable # this shouldn't apply to MPIs, though, which are subclasses of int if isinstance(obj, int) and not isinstance(obj, pgpy.packet.types.MPI): return False return True def ksort(key): # return a tuple of key, key.count('.') so we get a descending alphabetical, ascending depth ordering return key, key.count('.') objs = [sig(), uid(),] + [PGPMessage.from_file(m) for m in _msgs] + [key(f) for f in _keys] cids = ['sig', 'uid',] + [os.path.basename(m) for m in _msgs] + [os.path.basename(f) for f in _keys] @pytest.mark.parametrize('obj', objs, ids=cids) def test_copy_obj(request, obj): obj2 = copy.copy(obj) objflat = {name: val for name, val in walk_obj(obj, '{}.'.format(request.node.callspec.id))} obj2flat = {name: val for name, val in walk_obj(obj2, '{}.'.format(request.node.callspec.id))} for k in sorted(objflat, key=ksort): print("checking attribute: {} ".format(k), end="") if isinstance(objflat[k], pgpy.types.SorteDeque): print("[SorteDeque] ", end="") assert len(objflat[k]) == len(obj2flat[k]) if not isinstance(objflat[k], (pgpy.types.PGPObject, pgpy.types.SorteDeque)): print("[{} ]".format(type(objflat[k])), end="") assert objflat[k] == objflat[k], k # check identity, but only types that should definitely be copied if check_id(objflat[k]): print("[id] {}".format(type(objflat[k]))) assert objflat[k] is not obj2flat[k], "{}: {}".format(type(objflat[k]), k) else: print() PGPy-0.5.4/tests/test_05_actions.py000066400000000000000000001154141403641706600170730ustar00rootroot00000000000000# coding=utf-8 """ test doing things with keys/signatures/etc """ import pytest from conftest import gpg_ver, gnupghome import copy import glob try: import gpg except ImportError: gpg = None import itertools import os import time import warnings from datetime import datetime, timedelta from pgpy import PGPKey from pgpy import PGPMessage from pgpy import PGPSignature from pgpy import PGPUID from pgpy._curves import _openssl_get_supported_curves from pgpy.constants import CompressionAlgorithm from pgpy.constants import EllipticCurveOID from pgpy.constants import Features from pgpy.constants import HashAlgorithm from pgpy.constants import KeyFlags from pgpy.constants import KeyServerPreferences from pgpy.constants import PubKeyAlgorithm from pgpy.constants import RevocationReason from pgpy.constants import SignatureType from pgpy.constants import SymmetricKeyAlgorithm from pgpy.packet import Packet from pgpy.packet.packets import PrivKeyV4 from pgpy.packet.packets import PrivSubKeyV4 enc_msgs = [ PGPMessage.from_file(f) for f in sorted(glob.glob('tests/testdata/messages/message*.pass*.asc')) ] class TestPGPMessage(object): @staticmethod def gpg_message(msg): ret = None with gpg.Context(offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) msg, _ = c.verify(gpg.Data(string=str(msg))) ret = bytes(msg) return ret @staticmethod def gpg_decrypt(msg, passphrase): try: ret = None with gpg.Context(armor=True, offline=True, pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, file_name='/usr/bin/gpg', home_dir=gnupghome) mtxt, decres, _ = c.decrypt(gpg.Data(string=str(msg)), passphrase=passphrase.encode('utf-8'), verify=False) assert decres ret = bytes(mtxt) return ret except gpg.errors.GPGMEError: # if we got here, it's because gpgme/gpg-agent are not respecting the call to gpgme_set_passphrase_cb # gpg-agent tries to pop the pinentry program instead, which does not work in a CI environment with no TTY # I got tired of fighting with it to try to make it work, so here we are with a bypass, instead return msg.decrypt(passphrase).message.encode('utf-8') @pytest.mark.parametrize('comp_alg,sensitive', itertools.product(CompressionAlgorithm, [False, True])) def test_new(self, comp_alg, sensitive): mtxt = u"This is a new message!" msg = PGPMessage.new(mtxt, compression=comp_alg, sensitive=sensitive) assert isinstance(msg, PGPMessage) assert msg.filename == ('_CONSOLE' if sensitive else '') assert msg.is_sensitive is sensitive assert msg.type == 'literal' assert msg.message == mtxt assert msg._compression == comp_alg if gpg: # see if GPG can parse our message assert self.gpg_message(msg).decode('utf-8') == mtxt @pytest.mark.parametrize('comp_alg,sensitive,path', itertools.product(CompressionAlgorithm, [False, True], sorted(glob.glob('tests/testdata/files/literal*')))) def test_new_from_file(self, comp_alg, sensitive, path): msg = PGPMessage.new(path, file=True, compression=comp_alg, sensitive=sensitive) assert isinstance(msg, PGPMessage) assert msg.filename == ('_CONSOLE' if sensitive else os.path.basename(path)) assert msg.type == 'literal' assert msg.is_sensitive is sensitive if gpg: with open(path, 'rb') as tf: mtxt = tf.read() # see if GPG can parse our message assert self.gpg_message(msg) == mtxt @pytest.mark.regression(issue=154) # @pytest.mark.parametrize('cleartext', [False, True]) def test_new_non_unicode(self): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず' msg = PGPMessage.new(text.encode('jisx0213'), encoding='jisx0213') assert msg.type == 'literal' assert msg.message == text.encode('jisx0213') if gpg: # see if GPG can parse our message assert self.gpg_message(msg).decode('jisx0213') == text @pytest.mark.regression(issue=154) def test_new_non_unicode_cleartext(self): # this message text comes from http://www.columbia.edu/~fdc/utf8/ text = u'色は匂へど 散りぬるを\n' \ u'我が世誰ぞ 常ならむ\n' \ u'有為の奥山 今日越えて\n' \ u'浅き夢見じ 酔ひもせず' msg = PGPMessage.new(text.encode('jisx0213'), cleartext=True, encoding='jisx0213') assert msg.type == 'cleartext' assert msg.message == text def test_add_marker(self): msg = PGPMessage.new(u"This is a new message") marker = Packet(bytearray(b'\xa8\x03\x50\x47\x50')) msg |= marker @pytest.mark.parametrize('enc_msg', enc_msgs, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/messages/message*.pass*.asc'))]) def test_decrypt_passphrase_message(self, enc_msg): decmsg = enc_msg.decrypt("QwertyUiop") assert isinstance(decmsg, PGPMessage) assert decmsg is not enc_msg try: assert decmsg.message == b"This is stored, literally\\!\n\n" except AssertionError: # TODO: handle the BCPG-encrypted messages more gracefully assert decmsg.message == ('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pretium ' 'libero id orci interdum pretium. Cras at arcu in leo facilisis tincidunt ac ' 'sed lorem. Quisque quis varius quam. Integer gravida quam non cursus ' 'suscipit. Vivamus placerat convallis leo, nec lobortis ipsum. Sed fermentum ' 'ipsum sed tellus consequat elementum. Fusce id congue orci, at molestie ex.' '\n\n' 'Phasellus vel sagittis mauris. Ut in vehicula ipsum. Nullam facilisis ' 'molestie diam, in fermentum justo interdum id. Donec vestibulum tristique ' 'sapien nec rhoncus. Suspendisse venenatis consectetur mollis. Phasellus ' 'fringilla tortor non ligula malesuada, in vehicula mauris efficitur. Duis ' 'pulvinar eleifend est nec fringilla. Nunc elit nulla, sodales quis ' 'ullamcorper sit amet, elementum vitae justo. In pretium leo sit amet risus ' 'pharetra, ac tincidunt sem varius.' '\n\n' 'Nunc fermentum id risus sed lobortis. Sed id vulputate arcu. In ac quam sed ' 'nulla semper ullamcorper. Donec eleifend quam at dolor dictum, ut efficitur ' 'tortor dapibus. Nunc maximus quam non erat aliquet, quis blandit nibh ' 'sollicitudin. Fusce aliquam est enim, nec mattis orci scelerisque nec. ' 'Nullam venenatis eget elit consectetur sagittis. \n') @pytest.mark.parametrize('comp_alg', CompressionAlgorithm) def test_encrypt_passphrase(self, comp_alg): mtxt = "This message is to be encrypted" msg = PGPMessage.new(mtxt, compression=comp_alg) assert not msg.is_encrypted encmsg = msg.encrypt("QwertyUiop") assert isinstance(encmsg, PGPMessage) assert encmsg.is_encrypted assert encmsg.type == 'encrypted' # decrypt with PGPy decmsg = encmsg.decrypt("QwertyUiop") assert isinstance(decmsg, PGPMessage) assert decmsg.type == msg.type assert decmsg.is_compressed == msg.is_compressed assert decmsg.message == mtxt assert decmsg._compression == msg._compression if gpg: # decrypt with GPG via python-gnupg assert self.gpg_decrypt(encmsg, 'QwertyUiop').decode('utf-8') == decmsg.message def test_encrypt_passphrase_2(self): mtxt = "This message is to be encrypted" msg = PGPMessage.new(mtxt) assert not msg.is_encrypted sk = SymmetricKeyAlgorithm.AES256.gen_key() encmsg = msg.encrypt("QwertyUiop", sessionkey=sk).encrypt("AsdfGhjkl", sessionkey=sk) assert isinstance(encmsg, PGPMessage) assert encmsg.is_encrypted assert encmsg.type == 'encrypted' # decrypt with PGPy only, since GnuPG can't do multiple passphrases for passwd in ["QwertyUiop", "AsdfGhjkl"]: decmsg = encmsg.decrypt(passwd) assert isinstance(decmsg, PGPMessage) assert decmsg.type == msg.type assert decmsg.is_compressed assert decmsg.message == mtxt @pytest.fixture(scope='module') def userphoto(): with open('tests/testdata/pgp.jpg', 'rb') as pf: pbytes = bytearray(os.fstat(pf.fileno()).st_size) pf.readinto(pbytes) return PGPUID.new(pbytes) # TODO: add more keyspecs pkeyspecs = ((PubKeyAlgorithm.RSAEncryptOrSign, 1024), (PubKeyAlgorithm.DSA, 1024), (PubKeyAlgorithm.ECDSA, EllipticCurveOID.NIST_P256), (PubKeyAlgorithm.EdDSA, EllipticCurveOID.Ed25519),) skeyspecs = ((PubKeyAlgorithm.RSAEncryptOrSign, 1024), (PubKeyAlgorithm.DSA, 1024), (PubKeyAlgorithm.ElGamal, 1024), (PubKeyAlgorithm.ECDSA, EllipticCurveOID.SECP256K1), (PubKeyAlgorithm.ECDH, EllipticCurveOID.Brainpool_P256), (PubKeyAlgorithm.EdDSA, EllipticCurveOID.Ed25519), (PubKeyAlgorithm.ECDH, EllipticCurveOID.Curve25519),) class TestPGPKey_Management(object): # test PGPKey management actions, e.g.: # - key/subkey generation # - adding/removing UIDs # - adding/removing signatures # - protecting/unlocking keys = {} def gpg_verify_key(self, key): with gpg.Context(offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) data, vres = c.verify(gpg.Data(string=str(key))) assert vres @pytest.mark.run('first') @pytest.mark.parametrize('alg,size', pkeyspecs) def test_gen_key(self, alg, size): # create a primary key with a UID uid = PGPUID.new('Test Key', '{}.{}'.format(alg.name, size), 'user@localhost.local') key = PGPKey.new(alg, size) if alg is PubKeyAlgorithm.ECDSA: # ECDSA keys require larger hash digests key.add_uid(uid, hashes=[HashAlgorithm.SHA384]) else: key.add_uid(uid, hashes=[HashAlgorithm.SHA224]) assert uid in key # self-verify the key assert key.verify(key) self.keys[(alg, size)] = key if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_gen_key') @pytest.mark.parametrize('pkspec,skspec', itertools.product(pkeyspecs, skeyspecs), ids=['{}-{}-{}'.format(pk[0].name, sk[0].name, sk[1]) for pk, sk in itertools.product(pkeyspecs, skeyspecs)]) def test_add_subkey(self, pkspec, skspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) alg, size = skspec if not alg.can_gen: pytest.xfail('Key algorithm {} not yet supported'.format(alg.name)) if isinstance(size, EllipticCurveOID) and ((not size.can_gen) or size.curve.name not in _openssl_get_supported_curves()): pytest.xfail('Curve {} not yet supported'.format(size.curve.name)) key = self.keys[pkspec] subkey = PGPKey.new(*skspec) # before adding subkey to key, the key packet should be a PrivKeyV4, not a PrivSubKeyV4 assert isinstance(subkey._key, PrivKeyV4) assert not isinstance(subkey._key, PrivSubKeyV4) key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications}) # now that we've added it, it should be a PrivSubKeyV4 assert isinstance(subkey._key, PrivSubKeyV4) # self-verify with warnings.catch_warnings(): warnings.simplefilter('ignore') assert key.verify(subkey) sv = key.verify(key) assert sv assert subkey in sv if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_add_subkey') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_add_altuid(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) key = self.keys[pkspec] uid = PGPUID.new('T. Keyerson', 'Secondary UID', 'testkey@localhost.local') expiration = datetime.utcnow() + timedelta(days=2) # add all of the sbpackets that only work on self-certifications with warnings.catch_warnings(): warnings.simplefilter('ignore') key.add_uid(uid, usage=[KeyFlags.Certify, KeyFlags.Sign], ciphers=[SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.Camellia256], hashes=[HashAlgorithm.SHA384], compression=[CompressionAlgorithm.ZLIB], key_expiration=expiration, keyserver_flags={KeyServerPreferences.NoModify}, keyserver='about:none', primary=False) sig = uid.selfsig assert sig.type == SignatureType.Positive_Cert assert sig.cipherprefs == [SymmetricKeyAlgorithm.AES256, SymmetricKeyAlgorithm.Camellia256] assert sig.hashprefs == [HashAlgorithm.SHA384] assert sig.compprefs == [CompressionAlgorithm.ZLIB] assert sig.features == {Features.ModificationDetection} assert sig.key_expiration == expiration - key.created assert sig.keyserver == 'about:none' assert sig.keyserverprefs == {KeyServerPreferences.NoModify} assert uid.is_primary is False if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_add_altuid') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_add_photo(self, pkspec, userphoto): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # add a photo key = self.keys[pkspec] photo = copy.copy(userphoto) with warnings.catch_warnings(): warnings.simplefilter('ignore') key.add_uid(photo) if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_add_photo') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_revoke_altuid(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # add revoke altuid key = self.keys[pkspec] altuid = key.get_uid('T. Keyerson') revsig = key.revoke(altuid) altuid |= revsig @pytest.mark.run(after='test_remove_altuid') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_remove_altuid(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # remove the UID added in test_add_altuid key = self.keys[pkspec] key.del_uid('T. Keyerson') assert not key.get_uid('T. Keyerson') @pytest.mark.run(after='test_remove_altuid') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_add_revocation_key(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # add a revocation key rev = self.keys[next(pks for pks in pkeyspecs if pks != pkspec)] key = self.keys[pkspec] revsig = key.revoker(rev) key |= revsig assert revsig in key if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_add_revocation_key') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_protect(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # add a passphrase key = self.keys[pkspec] assert key.is_protected is False key.protect('There Are Many Like It, But This Key Is Mine', SymmetricKeyAlgorithm.AES256, HashAlgorithm.SHA256) assert key.is_protected assert key.is_unlocked is False if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_protect') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_unlock(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # unlock the key using the passphrase key = self.keys[pkspec] assert key.is_protected assert key.is_unlocked is False with key.unlock('There Are Many Like It, But This Key Is Mine') as _unlocked: assert _unlocked.is_unlocked @pytest.mark.run(after='test_unlock') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_change_passphrase(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # change the passphrase on the key key = self.keys[pkspec] with key.unlock('There Are Many Like It, But This Key Is Mine') as ukey: ukey.protect('This Password Has Been Changed', ukey._key.keymaterial.s2k.encalg, ukey._key.keymaterial.s2k.halg) @pytest.mark.run(after='test_change_passphrase') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_unlock2(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # unlock the key using the updated passphrase key = self.keys[pkspec] with key.unlock('This Password Has Been Changed') as ukey: assert ukey.is_unlocked @pytest.mark.run(after='test_unlock2') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_pub_from_sec(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # get the public half of the key priv = self.keys[pkspec] pub = priv.pubkey assert pub.is_public assert pub.fingerprint == priv.fingerprint for skid, subkey in priv.subkeys.items(): assert skid in pub.subkeys assert pub.subkeys[skid].is_public assert len(subkey._key) == len(subkey._key.__bytes__()) if gpg: # try to verify with GPG self.gpg_verify_key(pub) @pytest.mark.run(after='test_pub_from_spec') @pytest.mark.parametrize('pkspec,skspec', itertools.product(pkeyspecs, skeyspecs), ids=['{}-{}-{}'.format(pk[0].name, sk[0].name, sk[1]) for pk, sk in itertools.product(pkeyspecs, skeyspecs)]) def test_revoke_subkey(self, pkspec, skspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) alg, size = skspec if not alg.can_gen: pytest.xfail('Key algorithm {} not yet supported'.format(alg.name)) if isinstance(size, EllipticCurveOID) and ((not size.can_gen) or size.curve.name not in _openssl_get_supported_curves()): pytest.xfail('Curve {} not yet supported'.format(size.curve.name)) # revoke the subkey key = self.keys[pkspec] # pub = key.pubkey subkey = next(sk for si, sk in key.subkeys.items() if (sk.key_algorithm, sk.key_size) == skspec) with key.unlock('This Password Has Been Changed') as ukey: rsig = ukey.revoke(subkey, sigtype=SignatureType.SubkeyRevocation) assert 'ReasonForRevocation' in rsig._signature.subpackets subkey |= rsig # verify with PGPy assert key.verify(subkey, rsig) assert rsig in subkey.revocation_signatures if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_revoke_subkey') @pytest.mark.parametrize('pkspec', pkeyspecs, ids=[str(a) for a, s in pkeyspecs]) def test_revoke_key(self, pkspec): if pkspec not in self.keys: pytest.skip('Keyspec {} not in keys; must not have generated'.format(pkspec)) # revoke the key key = self.keys[pkspec] with key.unlock('This Password Has Been Changed') as ukey: rsig = ukey.revoke(key, sigtype=SignatureType.KeyRevocation, reason=RevocationReason.Retired, comment="But you're so oooold") assert 'ReasonForRevocation' in rsig._signature.subpackets key |= rsig # verify with PGPy assert key.verify(key, rsig) assert rsig in key.revocation_signatures if gpg: # try to verify with GPG self.gpg_verify_key(key) @pytest.mark.run(after='test_revoke_key') def test_revoke_key_with_revoker(self): pytest.skip("not implemented yet") @pytest.fixture(scope='module') def string(): return "This string will be signed" @pytest.fixture(scope='module') def message(): return PGPMessage.new("This is a message!", compression=CompressionAlgorithm.Uncompressed) @pytest.fixture(scope='module') def ctmessage(): return PGPMessage.new("This is a cleartext message!", cleartext=True) @pytest.fixture(scope='module') def sessionkey(): # return SymmetricKeyAlgorithm.AES128.gen_key() return b'\x9d[\xc1\x0e\xec\x01k\xbc\xf4\x04UW\xbb\xfb\xb2\xb9' @pytest.fixture(scope='module') def abe(): uid = PGPUID.new('Abraham Lincoln', comment='Honest Abe', email='abraham.lincoln@whitehouse.gov') with open('tests/testdata/abe.jpg', 'rb') as abef: abebytes = bytearray(os.fstat(abef.fileno()).st_size) abef.readinto(abebytes) uphoto = PGPUID.new(abebytes) # Abe is pretty oldschool, so he uses a DSA primary key # normally he uses an ElGamal subkey for encryption, but PGPy doesn't support that yet, so he's settled for RSA for now key = PGPKey.new(PubKeyAlgorithm.DSA, 1024) subkey = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 1024) key.add_uid(uid, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA224, HashAlgorithm.SHA1], ciphers=[SymmetricKeyAlgorithm.AES128, SymmetricKeyAlgorithm.Camellia128, SymmetricKeyAlgorithm.CAST5], compression=[CompressionAlgorithm.ZLIB]) key.add_uid(uphoto) key.add_subkey(subkey, usage={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}) return key @pytest.fixture(scope='module') def targette_pub(): return PGPKey.from_file('tests/testdata/keys/targette.pub.rsa.asc')[0] @pytest.fixture(scope='module') def targette_sec(): return PGPKey.from_file('tests/testdata/keys/targette.sec.rsa.asc')[0] seckeys = [ PGPKey.from_file(f)[0] for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc')) ] pubkeys = [ PGPKey.from_file(f)[0] for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc')) ] class TestPGPKey_Actions(object): sigs = {} msgs = {} def gpg_verify(self, subject, sig=None, pubkey=None): # verify with GnuPG with gpg.Context(armor=True, offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) # do we need to import the key? if pubkey: try: c.get_key(pubkey.fingerprint) except gpg.errors.KeyNotFound: key_data = gpg.Data(string=str(pubkey)) gpg.core.gpgme.gpgme_op_import(c.wrapped, key_data) print(list(c.keylist())) vargs = [gpg.Data(string=str(subject))] if sig is not None: vargs += [gpg.Data(string=str(sig))] _, vres = c.verify(*vargs) assert vres def gpg_decrypt(self, message, privkey): try: ret = None # decrypt with GnuPG with gpg.Context(armor=True, offline=True, pinentry_mode=gpg.constants.PINENTRY_MODE_LOOPBACK) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) # do we need to import the key? try: c.get_key(privkey.fingerprint, True) except gpg.errors.KeyNotFound: key_data = gpg.Data(string=str(privkey)) gpg.core.gpgme.gpgme_op_import(c.wrapped, key_data) pt, _, _ = c.decrypt(gpg.Data(string=str(message)), verify=False) ret = bytes(pt) return ret except gpg.errors.GPGMEError: # if we got here, it's because gpg is screwing with us. The tests seem to pass everywhere except in the buildd. # Until I can find a better fix, here's another bypass return privkey.decrypt(message).message.encode('utf-8') # test non-management PGPKey actions using existing keys, i.e.: # - signing/verifying # - encryption/decryption def test_sign_string(self, targette_sec, targette_pub, string): # test signing a string # test with all possible subpackets sig = targette_sec.sign(string, user=targette_sec.userids[0].name, expires=timedelta(seconds=30), revocable=False, notation={'Testing': 'This signature was generated during unit testing', 'cooldude': bytearray(b'\xc0\x01\xd0\x0d')}, policy_uri='about:blank') assert sig.type == SignatureType.BinaryDocument assert sig.notation == {'Testing': 'This signature was generated during unit testing', 'cooldude': bytearray(b'\xc0\x01\xd0\x0d')} assert sig.revocable is False assert sig.policy_uri == 'about:blank' # assert sig.sig.signer_uid == "{:s}".format(sec.userids[0]) assert next(iter(sig._signature.subpackets['SignersUserID'])).userid == "{:s}".format(targette_sec.userids[0]) # if not sig.is_expired: # time.sleep((sig.expires_at - datetime.utcnow()).total_seconds()) assert sig.is_expired is False self.sigs['string'] = sig if gpg: # verify with GnuPG self.gpg_verify(string, sig, targette_pub) @pytest.mark.run(after='test_sign_string') def test_verify_string(self, targette_pub, string): # verify the signature on the string sig = self.sigs['string'] sv = targette_pub.verify(string, sig) assert sv assert sig in sv def test_sign_message(self, targette_sec, targette_pub, message): # test signing a message sig = targette_sec.sign(message) assert sig.type == SignatureType.BinaryDocument assert sig.revocable assert sig.is_expired is False message |= sig if gpg: # verify with GnuPG self.gpg_verify(message, pubkey=targette_pub) @pytest.mark.run(after='test_sign_message') def test_verify_message(self, targette_pub, message): # test verifying a signed message sv = targette_pub.verify(message) assert sv assert len(sv) > 0 def test_sign_ctmessage(self, targette_sec, targette_pub, ctmessage): # test signing a cleartext message expire_at = datetime.utcnow() + timedelta(days=1) sig = targette_sec.sign(ctmessage, expires=expire_at) assert sig.type == SignatureType.CanonicalDocument assert sig.revocable assert sig.is_expired is False ctmessage |= sig if gpg: # verify with GnuPG self.gpg_verify(ctmessage, pubkey=targette_pub) @pytest.mark.run(after='test_sign_ctmessage') def test_verify_ctmessage(self, targette_pub, ctmessage): # test verifying a signed cleartext message sv = targette_pub.verify(ctmessage) assert sv assert len(sv) > 0 @pytest.mark.parametrize('sec', seckeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))]) def test_sign_timestamp(self, sec): # test creating a timestamp signature with warnings.catch_warnings(): warnings.simplefilter('ignore') sig = sec.sign(None) assert sig.type == SignatureType.Timestamp self.sigs[(sec._key.fingerprint.keyid, 'timestamp')] = sig @pytest.mark.run(after='test_sign_timestamp') @pytest.mark.parametrize('pub', pubkeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))]) def test_verify_timestamp(self, pub): # test verifying a timestamp signature sig = self.sigs[(pub._key.fingerprint.keyid, 'timestamp')] with warnings.catch_warnings(): warnings.simplefilter('ignore') sv = pub.verify(None, sig) assert sv assert sig in sv @pytest.mark.parametrize('sec', seckeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))]) def test_sign_standalone(self, sec): # test creating a standalone signature with warnings.catch_warnings(): warnings.simplefilter('ignore') sig = sec.sign(None, notation={"cheese status": "standing alone"}) assert sig.type == SignatureType.Standalone assert sig.notation == {"cheese status": "standing alone"} self.sigs[(sec._key.fingerprint.keyid, 'standalone')] = sig @pytest.mark.run(after='test_sign_standalone') @pytest.mark.parametrize('pub', pubkeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))]) def test_verify_standalone(self, pub): # test verifying a standalone signature sig = self.sigs[(pub._key.fingerprint.keyid, 'standalone')] with warnings.catch_warnings(): warnings.simplefilter('ignore') sv = pub.verify(None, sig) assert sv assert sig in sv @pytest.mark.parametrize('pkspec', pkeyspecs) def test_verify_invalid_sig(self, pkspec, string): # test verifying an invalid signature u = PGPUID.new('asdf') k = PGPKey.new(*pkspec) k.add_uid(u, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA1]) # sign the string with extra characters, so that verifying just string fails sig = k.sign(string + 'asdf') sv = k.pubkey.verify(string, sig) assert not sv assert sig in sv def test_verify_expired_sig(self, targette_sec, targette_pub, string): # test verifyigg an expired signature expire_soon = timedelta(seconds=1) sig = targette_sec.sign(string, expires=expire_soon) # wait a bit to allow sig to expire time.sleep(1.1) sv = targette_pub.verify(string, sig) assert sv assert sig in sv assert sig.is_expired @pytest.mark.parametrize('sec', seckeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))]) def test_certify_uid(self, sec, abe): # sign the uid userid = abe.userids[0] with warnings.catch_warnings(): warnings.simplefilter('ignore') # test with all possible subpackets sig = sec.certify(userid, SignatureType.Casual_Cert, trust=(1, 60), regex='(.*)', exportable=True,) userid |= sig assert sig.type == SignatureType.Casual_Cert assert sig.exportable assert ({sec.fingerprint.keyid} | set(sec.subkeys)) & userid.signers @pytest.mark.run(after='test_certify_uid') @pytest.mark.parametrize('pub', pubkeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))]) def test_verify_userid(self, pub, abe): # verify the signatures on a photo uid userid = abe.userids[0] sv = pub.verify(userid) assert sv assert len(sv) > 0 @pytest.mark.parametrize('sec', seckeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc'))]) def test_certify_photo(self, sec, abe): # sign a photo uid userphoto = abe.userattributes[0] userphoto |= sec.certify(userphoto) @pytest.mark.run(after='test_certify_photo') @pytest.mark.parametrize('pub', pubkeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))]) def test_verify_photo(self, pub, abe): # verify the signatures on a photo uid userphoto = abe.userattributes[0] sv = pub.verify(userphoto) assert sv assert len(sv) > 0 def test_self_certify_key(self, abe): # add an 0x1f signature with notation with warnings.catch_warnings(): warnings.simplefilter('ignore') sig = abe.certify(abe, notation={'Notice': 'This key has been self-frobbed!'}) assert sig.type == SignatureType.DirectlyOnKey assert sig.notation == {'Notice': 'This key has been self-frobbed!'} abe |= sig @pytest.mark.parametrize('pub', pubkeys, ids=[os.path.basename(f) for f in sorted(glob.glob('tests/testdata/keys/*.pub.asc'))]) def test_verify_key(self, pub, abe): # verify the signatures on a key sv = pub.verify(abe) assert sv assert len(list(sv.good_signatures)) > 0 def test_gpg_import_abe(self, abe): if gpg is None: pytest.skip('integration test') # verify all of the things we did to Abe's key with GnuPG in one fell swoop self.gpg_verify(abe) @pytest.mark.parametrize('pub,cipher', itertools.product(pubkeys, sorted(SymmetricKeyAlgorithm)), ids=['{}:{}-{}'.format(pk.key_algorithm.name, pk.key_size, c.name) for pk, c in itertools.product(pubkeys, sorted(SymmetricKeyAlgorithm))]) def test_encrypt_message(self, pub, cipher): if pub.key_algorithm in {PubKeyAlgorithm.DSA}: pytest.skip('Asymmetric encryption only implemented for RSA/ECDH currently') if cipher in {SymmetricKeyAlgorithm.Plaintext, SymmetricKeyAlgorithm.Twofish256, SymmetricKeyAlgorithm.IDEA}: pytest.xfail('Symmetric cipher {} not supported for encryption'.format(cipher)) # test encrypting a message mtxt = "This message will have been encrypted" msg = PGPMessage.new(mtxt) with warnings.catch_warnings(): warnings.simplefilter('ignore') emsg = pub.encrypt(msg, cipher=cipher) self.msgs[(pub.fingerprint, cipher)] = emsg @pytest.mark.run(after='test_encrypt_message') @pytest.mark.parametrize('sf,cipher', itertools.product(sorted(glob.glob('tests/testdata/keys/*.sec.asc')), sorted(SymmetricKeyAlgorithm))) def test_decrypt_message(self, sf, cipher): # test decrypting a message sec, _ = PGPKey.from_file(sf) if (sec.fingerprint, cipher) not in self.msgs: pytest.skip('Message not present; see test_encrypt_message skip or xfail reason') emsg = self.msgs[(sec.fingerprint, cipher)] with warnings.catch_warnings(): warnings.simplefilter('ignore') dmsg = sec.decrypt(emsg) assert dmsg.message == "This message will have been encrypted" # now check with GnuPG, if possible if gpg_ver < '2.1' and sec.key_algorithm in {PubKeyAlgorithm.ECDSA, PubKeyAlgorithm.ECDH}: # GnuPG prior to 2.1.x does not support EC* keys, so skip this step return if gpg: assert self.gpg_decrypt(emsg, sec).decode('utf-8') == dmsg.message @pytest.mark.run(after='test_encrypt_message') @pytest.mark.parametrize('sf,cipher', itertools.product(sorted(glob.glob('tests/testdata/keys/*.sec.asc')), sorted(SymmetricKeyAlgorithm))) def test_sign_encrypted_message(self, sf, cipher): # test decrypting a message sec, _ = PGPKey.from_file(sf) if (sec.fingerprint, cipher) not in self.msgs: pytest.skip('Message not present; see test_encrypt_message skip or xfail reason') emsg = self.msgs[(sec.fingerprint, cipher)] with warnings.catch_warnings(): warnings.simplefilter('ignore') emsg |= sec.sign(emsg) assert emsg.is_signed assert emsg.is_encrypted assert isinstance(next(iter(emsg)), PGPSignature) def test_gpg_ed25519_verify(self, abe): # test verification of Ed25519 signature generated by GnuPG pubkey, _ = PGPKey.from_file('tests/testdata/keys/ecc.2.pub.asc') sig = PGPSignature.from_file('tests/testdata/signatures/ecc.2.sig.asc') assert pubkey.verify("This is a test signature message", sig) def test_gpg_cv25519_decrypt(self, abe): # test the decryption of X25519 generated by GnuPG seckey, _ = PGPKey.from_file('tests/testdata/keys/ecc.2.sec.asc') emsg = PGPMessage.from_file('tests/testdata/messages/message.ecdh.cv25519.asc') with warnings.catch_warnings(): warnings.simplefilter('ignore') dmsg = seckey.decrypt(emsg) assert bytes(dmsg.message) == b"This message will have been encrypted" PGPy-0.5.4/tests/test_10_exceptions.py000066400000000000000000000365031403641706600176110ustar00rootroot00000000000000""" explicitly test error scenarios """ import pytest import glob import warnings from pgpy import PGPKey from pgpy import PGPKeyring from pgpy import PGPMessage from pgpy import PGPSignature from pgpy import PGPUID from pgpy.constants import EllipticCurveOID from pgpy.constants import HashAlgorithm from pgpy.constants import KeyFlags from pgpy.constants import PubKeyAlgorithm from pgpy.constants import SymmetricKeyAlgorithm from pgpy.packet import Packet from pgpy.types import Armorable from pgpy.types import PGPObject from pgpy.types import Fingerprint from pgpy.types import SignatureVerification from pgpy.errors import PGPError from pgpy.errors import PGPDecryptionError from pgpy.errors import PGPEncryptionError from pgpy.errors import PGPInsecureCipher def _read(f, mode='r'): with open(f, mode) as ff: return ff.read() @pytest.fixture(scope='module') def rsa_sec(): return PGPKey.from_file('tests/testdata/keys/rsa.1.sec.asc')[0] @pytest.fixture(scope='module') def rsa_enc(): return PGPKey.from_file('tests/testdata/keys/rsa.1.enc.asc')[0] @pytest.fixture(scope='module') def rsa_pub(): return PGPKey.from_file('tests/testdata/keys/rsa.1.pub.asc')[0] @pytest.fixture(scope='module') def targette_sec(): return PGPKey.from_file('tests/testdata/keys/targette.sec.rsa.asc')[0] @pytest.fixture(scope='module') def targette_pub(): return PGPKey.from_file('tests/testdata/keys/targette.pub.rsa.asc')[0] @pytest.fixture(scope='module') def temp_subkey(): return PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) @pytest.fixture(scope='module') def temp_key(): u = PGPUID.new('User') k = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) k.add_uid(u, usage={KeyFlags.Certify, KeyFlags.Sign}, hashes=[HashAlgorithm.SHA1]) sk = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 512) k.add_subkey(sk, usage={KeyFlags.EncryptCommunications}) return k key_algs = [ pka for pka in PubKeyAlgorithm if pka.can_gen and not pka.deprecated ] key_algs_unim = [ pka for pka in PubKeyAlgorithm if not pka.can_gen and not pka.deprecated ] key_algs_rsa_depr = [ pka for pka in PubKeyAlgorithm if pka.deprecated and pka is not PubKeyAlgorithm.FormerlyElGamalEncryptOrSign ] key_algs_badsizes = { PubKeyAlgorithm.RSAEncryptOrSign: [256], PubKeyAlgorithm.DSA: [512], PubKeyAlgorithm.ECDSA: [curve for curve in EllipticCurveOID if not curve.can_gen], PubKeyAlgorithm.ECDH: [curve for curve in EllipticCurveOID if not curve.can_gen], } badkeyspec = [ (alg, size) for alg in key_algs_badsizes.keys() for size in key_algs_badsizes[alg] ] class TestArmorable(object): # some basic test cases specific to the Armorable mixin class def test_malformed_base64(self): # 'asdf' base64-encoded becomes 'YXNkZg==' # remove one of the pad characters and we should get a PGPError data = '-----BEGIN PGP SOMETHING-----\n' \ '\n' \ 'YXNkZg=\n' \ '=ZEO6\n' \ '-----END PGP SOMETHING-----\n' with pytest.raises(PGPError): Armorable.ascii_unarmor(data) class TestMetaDispatchable(object): # test a couple of error cases in MetaDispatchable that affect all packet classes def test_parse_bytes_typeerror(self): # use a marker packet, but don't wrap it in a bytearray to get a TypeError data = b'\xa8\x03\x50\x47\x50' with pytest.raises(TypeError): Packet(data) def test_parse_versioned_header_exception(self): # cause an exception during parsing a versioned header by not including the version field data = bytearray(b'\xc1\x01') with pytest.raises(PGPError): Packet(data) def test_parse_packet_exceptions(self): # use a signature packet with fuzzed fields to get some exceptions # original packet is a DSA signature data = bytearray(b'\xc2F\x04\x00\x11\x01\x00\x06\x05\x02W\x16\x80\xb0\x00\n\t\x10G\x15FH\x97D\xbc\x0b46\x00' b'\x9fD\xbc\xd7\x87`\xe0\xfeT\x05\xcd\x82\xf5\x9ae\xa9\xb5\x01ii,\x00\x9d\x14\x0b<)\xb4\xc3' b'\x81iu\n\xe3W\xe2\x03\xb1\xc3\xd8p\x89W') def fuzz_pkt(slice, val, exc_type): d = data[:] d[slice] = val if exc_type is not None: with pytest.raises(exc_type): Packet(d) else: Packet(d) # ensure the base packet works, first Packet(data[:]) class WhatException(Exception): pass # unexpected signature type fuzz_pkt(3, 0x7f, PGPError) # unexpected pubkey algorithm fuzz_pkt(4, 0x64, PGPError) # unexpected hash algorithm - does not raise an exception during parsing fuzz_pkt(5, 0x64, None) class TestPGPKey(object): def test_unlock_pubkey(self, rsa_pub, recwarn): with rsa_pub.unlock("QwertyUiop") as _unlocked: assert _unlocked is rsa_pub w = recwarn.pop(UserWarning) assert str(w.message) == "Public keys cannot be passphrase-protected" assert w.filename == __file__ def test_unlock_not_protected(self, rsa_sec, recwarn): with rsa_sec.unlock("QwertyUiop") as _unlocked: assert _unlocked is rsa_sec w = recwarn.pop(UserWarning) assert str(w.message) == "This key is not protected with a passphrase" assert w.filename == __file__ def test_protect_pubkey(self, rsa_pub, recwarn): rsa_pub.protect('QwertyUiop', SymmetricKeyAlgorithm.CAST5, HashAlgorithm.SHA1) w = recwarn.pop(UserWarning) assert str(w.message) == "Public keys cannot be passphrase-protected" assert w.filename == __file__ def test_protect_protected_key(self, rsa_enc, recwarn): rsa_enc.protect('QwertyUiop', SymmetricKeyAlgorithm.CAST5, HashAlgorithm.SHA1) w = recwarn.pop(UserWarning) assert str(w.message) == "This key is already protected with a passphrase - " \ "please unlock it before attempting to specify a new passphrase" assert w.filename == __file__ def test_unlock_wrong_passphrase(self, rsa_enc): with pytest.raises(PGPDecryptionError): with rsa_enc.unlock('ClearlyTheWrongPassword'): pass def test_sign_protected_key(self, rsa_enc): with pytest.raises(PGPError), warnings.catch_warnings(): warnings.simplefilter('ignore') rsa_enc.sign("asdf") def test_verify_wrongkey(self, rsa_pub): wrongkey, _ = PGPKey.from_file('tests/testdata/signatures/aptapproval-test.key.asc') sig = PGPSignature.from_file('tests/testdata/signatures/debian-sid.sig.asc') with pytest.raises(PGPError): wrongkey.verify(_read('tests/testdata/signatures/debian-sid.subj'), sig) def test_decrypt_unencrypted_message(self, rsa_sec, recwarn): lit = PGPMessage.new('tests/testdata/lit', file=True) rsa_sec.decrypt(lit) w = recwarn.pop(UserWarning) assert str(w.message) == "This message is not encrypted" assert w.filename == __file__ def test_decrypt_wrongkey(self, targette_sec): msg = PGPMessage.from_file('tests/testdata/messages/message.rsa.cast5.asc') with pytest.raises(PGPError): targette_sec.decrypt(msg) def test_decrypt_protected_key(self, rsa_enc, rsa_pub): with pytest.raises(PGPError), warnings.catch_warnings(): warnings.simplefilter('ignore') emsg = rsa_pub.encrypt(PGPMessage.new("asdf")) rsa_enc.decrypt(emsg) def test_or_typeerror(self, rsa_sec): with pytest.raises(TypeError): rsa_sec |= 12 def test_contains_valueerror(self, rsa_sec): with pytest.raises(TypeError): 12 in rsa_sec def test_fail_del_uid(self, rsa_sec): with pytest.raises(KeyError): rsa_sec.del_uid("ASDFDSGSAJGKSAJG") def test_encrypt_bad_cipher(self, rsa_pub, recwarn): rsa_pub.subkeys['EEE097A017B979CA'].encrypt(PGPMessage.new('asdf'), cipher=SymmetricKeyAlgorithm.CAST5) w = recwarn.pop(UserWarning) assert str(w.message) == "Selected symmetric algorithm not in key preferences" assert w.filename == __file__ w = recwarn.pop(UserWarning) assert str(w.message) == "Selected compression algorithm not in key preferences" assert w.filename == __file__ def test_sign_bad_prefs(self, rsa_sec, recwarn): rsa_sec.subkeys['2A834D8E5918E886'].sign(PGPMessage.new('asdf'), hash=HashAlgorithm.MD5) w = recwarn.pop(UserWarning) assert str(w.message) == "Selected hash algorithm not in key preferences" assert w.filename == __file__ def test_verify_typeerror(self, rsa_sec): with pytest.raises(TypeError): rsa_sec.verify(12) with pytest.raises(TypeError): rsa_sec.verify("asdf", signature=12) def test_verify_nosigs(self, rsa_sec): msg = PGPMessage.new('tests/testdata/lit') with pytest.raises(PGPError): rsa_sec.verify(msg) def test_verify_invalid(self, rsa_sec): with warnings.catch_warnings(): warnings.simplefilter('ignore') sig = rsa_sec.sign("Text 1") assert not rsa_sec.verify("Text 2", sig) def test_parse_wrong_magic(self): keytext = _read('tests/testdata/keys/rsa.1.sec.asc').replace('KEY', 'EKY') key = PGPKey() with pytest.raises(ValueError): key.parse(keytext) def test_parse_wrong_crc24(self, recwarn): keytext = _read('tests/testdata/keys/rsa.1.sec.asc').splitlines() keytext[-2] = "=abcd" keytext = '\n'.join(keytext) key = PGPKey() key.parse(keytext) w = recwarn.pop(UserWarning) assert str(w.message) == "Incorrect crc24" assert w.filename == __file__ def test_empty_key_action(self): key = PGPKey() with pytest.raises(PGPError): key.sign('asdf') def test_new_key_no_uid_action(self): key = PGPKey.new(PubKeyAlgorithm.RSAEncryptOrSign, 1024) with pytest.raises(PGPError): key.sign('asdf') @pytest.mark.parametrize('badkey', badkeyspec, ids=['{}:{}'.format(alg.name, size if isinstance(size, int) else size.name) for alg, size in badkeyspec]) def test_new_key_invalid_size(self, badkey): key_alg, key_size = badkey with pytest.raises(ValueError): PGPKey.new(key_alg, key_size) @pytest.mark.parametrize('key_alg_unim', key_algs_unim, ids=[alg.name for alg in key_algs_unim]) def test_new_key_unimplemented_alg(self, key_alg_unim): with pytest.raises(NotImplementedError): PGPKey.new(key_alg_unim, 512) @pytest.mark.parametrize('key_alg_rsa_depr', key_algs_rsa_depr, ids=[alg.name for alg in key_algs_rsa_depr]) def test_new_key_deprecated_rsa_alg(self, key_alg_rsa_depr, recwarn): k = PGPKey.new(key_alg_rsa_depr, 512) w = recwarn.pop() assert str(w.message) == '{:s} is deprecated - generating key using RSAEncryptOrSign'.format(key_alg_rsa_depr.name) # assert w.filename == __file__ assert k.key_algorithm == PubKeyAlgorithm.RSAEncryptOrSign def test_set_pubkey_on_pubkey(self, rsa_pub, targette_pub): with pytest.raises(TypeError): rsa_pub.pubkey = targette_pub def test_set_wrong_pubkey(self, rsa_sec, targette_pub): with pytest.raises(ValueError): rsa_sec.pubkey = targette_pub def test_set_pubkey_already_set(self, rsa_sec, rsa_pub): rsa_sec.pubkey = rsa_pub assert rsa_sec._sibling is not None assert rsa_sec._sibling() is rsa_pub with pytest.raises(ValueError): rsa_sec.pubkey = rsa_pub def test_set_pubkey_privkey(self, rsa_sec, targette_sec): with pytest.raises(TypeError): rsa_sec.pubkey = targette_sec def test_add_subkey_to_pubkey(self, rsa_pub, temp_subkey): with pytest.raises(PGPError): rsa_pub.add_subkey(temp_subkey) def test_add_pubsubkey_to_key(self, rsa_sec, temp_subkey): pubtemp = temp_subkey.pubkey with pytest.raises(PGPError): rsa_sec.add_subkey(pubtemp) def test_add_key_with_subkeys_as_subkey(self, rsa_sec, temp_key): with pytest.raises(PGPError): rsa_sec.add_subkey(temp_key) class TestPGPKeyring(object): kr = PGPKeyring(_read('tests/testdata/pubtest.asc')) def test_key_keyerror(self): with pytest.raises(KeyError): with self.kr.key('DEADBEA7CAFED00D'): pass class TestPGPMessage(object): def test_decrypt_unsupported_algorithm(self): msg = PGPMessage.from_file('tests/testdata/message.enc.twofish.asc') with pytest.raises(PGPDecryptionError): msg.decrypt("QwertyUiop") def test_decrypt_wrongpass(self): msg = PGPMessage.from_file(next(f for f in glob.glob('tests/testdata/messages/message*.pass*.asc'))) with pytest.raises(PGPDecryptionError): msg.decrypt("TheWrongPassword") def test_decrypt_unencrypted(self): msg = PGPMessage.from_file('tests/testdata/messages/message.signed.asc') with pytest.raises(PGPError): msg.decrypt("Password") def test_encrypt_unsupported_algorithm(self): lit = PGPMessage.new('tests/testdata/lit') with pytest.raises(PGPEncryptionError): lit.encrypt("QwertyUiop", cipher=SymmetricKeyAlgorithm.Twofish256) def test_encrypt_insecure_cipher(self): msg = PGPMessage.new('asdf') with pytest.raises(PGPInsecureCipher): msg.encrypt('QwertyUiop', cipher=SymmetricKeyAlgorithm.IDEA) def test_encrypt_sessionkey_wrongtype(self): msg = PGPMessage.new('asdf') with pytest.raises(TypeError): msg.encrypt('asdf', sessionkey=0xabdf1234abdf1234, cipher=SymmetricKeyAlgorithm.AES128) def test_parse_wrong_magic(self): msgtext = _read('tests/testdata/messages/message.signed.asc').replace('MESSAGE', 'EMSSAGE') msg = PGPMessage() with pytest.raises(ValueError): msg.parse(msgtext) class TestPGPSignature(object): @pytest.mark.parametrize('inp', [12, None]) def test_or_typeerror(self, inp): with pytest.raises(TypeError): PGPSignature() | inp def test_parse_wrong_magic(self): sigtext = _read('tests/testdata/blocks/signature.expired.asc').replace('SIGNATURE', 'SIGANTURE') sig = PGPSignature() with pytest.raises(ValueError): sig.parse(sigtext) def test_parse_wrong_contents(self): notsigtext = _read('tests/testdata/blocks/message.compressed.asc').replace('MESSAGE', 'SIGNATURE') sig = PGPSignature() with pytest.raises(ValueError): sig.parse(notsigtext) class TestPGPUID(object): def test_or_typeerror(self): u = PGPUID.new("Asdf Qwert") with pytest.raises(TypeError): u |= 12 class TestSignatureVerification(object): def test_and_typeerror(self): with pytest.raises(TypeError): sv = SignatureVerification() & 12 class TestFingerprint(object): def test_bad_input(self): with pytest.raises(ValueError): Fingerprint("ABCDEFG") with pytest.raises(ValueError): Fingerprint("ABCD EFGH IJKL MNOP QRST UVWX YZ01 2345 6789 AABB") PGPy-0.5.4/tests/test_99_regressions.py000066400000000000000000000737221403641706600200200ustar00rootroot00000000000000""" I've got 99 problems but regression testing ain't one """ from conftest import gpg_ver, gnupghome try: import gpg except ImportError: gpg = None import os import datetime import pytest import glob import warnings from pgpy import PGPKey from pgpy.types import Armorable @pytest.mark.regression(issue=56) def test_reg_bug_56(): # some imports only used by this regression test import hashlib from datetime import datetime from pgpy.pgp import PGPSignature from pgpy.constants import HashAlgorithm from pgpy.constants import PubKeyAlgorithm from pgpy.constants import SignatureType from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import padding # do a regression test on issue #56 # re-create a signature that would have been encoded improperly as with issue #56 # and see if it fails to verify or not # this was the old seckeys/TestRSA-2048.key sec = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "\n" \ "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\n" \ "iz54ZFyNdQ==\n" \ "=WLpc\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" pub = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" \ "\n" \ "mQENBFOaNYoBCAC9FDOrASOxJoo3JhwCCln4wPy+A/UY1H0OYlc+MMolSwev2uDj\n" \ "nnwmt8ziNTjLuLEh3AnKjDWA9xvY5NW2ZkB6Edo6HQkquKLH7AkpLd82kiTWHdOw\n" \ "OH7OWQpz7z2z6e40wwHEduhyGcZ/Ja/A0+6GIb/2YFKlkwfnT92jtB94W//mL6wu\n" \ "LOkZMoU/CS/QatervzAf9VCemvAR9NI0UJc7Y0RC1B/1cBTQAUg70EhjnmJkqyYx\n" \ "yWqaXyfX10dsEX3+MyiP1kvUDfFwhdeL7E2H9sbFE5+MC9Eo99/Qezv3QoXzH2Tj\n" \ "bTun+QMVkbM92dj70KiExAJya9lSLZGCoOrDABEBAAG0M1Rlc3RSU0EtMjA0OCAo\n" \ "VEVTVElORy1VU0UtT05MWSkgPGVtYWlsQGFkZHJlc3MudGxkPokBNwQTAQoAIQUC\n" \ "U5o1igIbIwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRDA8iEODxk9zYQPB/4+\n" \ "kZlIwLE27J7IiZSkk+4T5CPrASxoSsRMadUvoHc0eiZIlQD2Gu05oQcm4kZojJAz\n" \ "Mv12rLtk+ZPwVOZU/TUxPYwuEyJP4keFJEW9P0GiURAvYQRQCbQ5IOlIkZ0tPotb\n" \ "010Ej3u5rHAiVCvh/cxF16UhkXknf/wgDDWErfGIMaaruAIr0G05p4Q2G/NLgBcc\n" \ "owSgFFfWprg3zfNPEQhH/qNs8O5mByniMZk4n2TsKGlX6eT9RrfJVQhSLoQXxYik\n" \ "MtiZTki4yPUhTQev62KWHQcY6zNV2p9VQ24NUhVCIBnZ0CLkm38QFsS5flWVGat5\n" \ "kraHTXxvffz7yGHJiFkiuQENBFOaNYoBCADBPjB83l1O2m/Nr5KDm6/BwKfrRsoJ\n" \ "DmMZ8nNHNUc/zK4RI4EFKkr35PSmgbA8yOlaSDWVz9zuKyOtb8Nohct2/lrac8zI\n" \ "+b4enZ/Z6qehoAdY1t4QYmA2PebKuerBXjIF1RWsPQDpu3GIZw4oBbdu5oUGB4I9\n" \ "yIepindM2b2I9dlY3ct4uhRbBmXPFcslmJ1K4pCurXvr4Po4DCcWqUmsGUQQbI1G\n" \ "UyAzSad7u9y3CRqhHFwzyFRRfl+/mgB2a6XvbGlG5Dkp1g7T/HIVJu+zv58AQkFw\n" \ "+ABuWNKCXa3TB51bkiBQlkRTSAu2tVZ8hVGZE+wUw0o9rLiy6mldFvbLABEBAAGJ\n" \ "AR8EGAEKAAkFAlOaNYoCGwwACgkQwPIhDg8ZPc1uDwf/SGoiZHjUsTWm4gZgZCzA\n" \ "jOpZs7dKjLL8Wm5G3HTFIGX0O8HCzQJARWq05N6EYmI4nPXxu08ba30SubybSeFU\n" \ "+iAPymqm2YNXrE2RwLWko78M0r9enUep6SvbGKnukPG7lz/33PsxIVyATfMmcmzV\n" \ "4chyC7pICTwgHv/zC3S/k7GoS82Z39LO4R4aDa4aubNq6mx4eHUd0MSnYud1IzRx\n" \ "D8cPxh9fCdoW0OpddqKNczAvO4bl5wwDafrEa7HpIX/sMVMZXo2h6TkitdLCdEfk\n" \ "tgEjS0hTsFtfwsXt9TKi1x3HJIbcm8t78ubpWXepB/iNKVzv4punFHhKiz54ZFyN\n" \ "dQ==\n" \ "=lqIH\n" \ "-----END PGP PUBLIC KEY BLOCK-----\n" # load the keypair above sk = PGPKey() sk.parse(sec) pk = PGPKey() pk.parse(pub) sigsubject = bytearray(b"Hello!I'm a test document.I'm going to get signed a bunch of times.KBYE!") sig = PGPSignature.new(SignatureType.BinaryDocument, PubKeyAlgorithm.RSAEncryptOrSign, HashAlgorithm.SHA512, sk.fingerprint.keyid) sig._signature.subpackets['h_CreationTime'][-1].created = datetime(2014, 8, 6, 23, 28, 51) sig._signature.subpackets.update_hlen() hdata = sig.hashdata(sigsubject) sig._signature.hash2 = hashlib.new('sha512', hdata).digest()[:2] # create the signature signature = sk.__key__.__privkey__().sign(hdata, padding.PKCS1v15(), hashes.SHA512()) sig._signature.signature.from_signer(signature) sig._signature.update_hlen() # check encoding assert sig._signature.signature.md_mod_n.to_mpibytes()[2:3] != b'\x00' # with PGPy assert pk.verify(sigsubject, sig) if gpg: # with GnuPG with gpg.Context(armor=True, offline=True) as c: c.set_engine_info(gpg.constants.PROTOCOL_OpenPGP, home_dir=gnupghome) # import the key key_data = gpg.Data(string=pub) gpg.core.gpgme.gpgme_op_import(c.wrapped, key_data) _, vres = c.verify(gpg.Data(string=sigsubject.decode('latin-1')), gpg.Data(string=str(sig))) assert vres # load mixed keys separately so they do not overwrite "single algo" keys in the _seckeys mapping _seckeys = {sk.key_algorithm.name: sk for sk in (PGPKey.from_file(f)[0] for f in sorted(glob.glob('tests/testdata/keys/*.sec.asc')) if 'keys/mixed' not in f)} _mixed1 = PGPKey.from_file('tests/testdata/keys/mixed.1.sec.asc')[0] seckm = [ _seckeys['DSA']._key, # DSA private key packet _seckeys['DSA'].subkeys['1FD6D5D4DA0170C4']._key, # ElGamal private key packet _seckeys['RSAEncryptOrSign']._key, # RSA private key packet _seckeys['ECDSA']._key, # ECDSA private key packet _seckeys['ECDSA'].subkeys['A81B93FD16BD9806']._key, # ECDH private key packet _seckeys['EdDSA']._key, # EdDSA private key packet _seckeys['EdDSA'].subkeys['AFC377493D8E897D']._key, # Curve25519 private key packet _mixed1._key, # RSA private key packet _mixed1.subkeys['B345506C90A428C5']._key, # ECDH Curve25519 private key packet ] @pytest.mark.regression(issue=172) @pytest.mark.parametrize('keypkt', seckm, ids=[sk.pkalg.name for sk in seckm]) def test_check_checksum(keypkt): # this test is dirty and simple # take the key packet provided, and store the key material checksum # recompute the checksum, and ensure they match goodsum = keypkt.keymaterial.chksum[:] keypkt.keymaterial._compute_chksum() assert goodsum == keypkt.keymaterial.chksum @pytest.mark.regression(issue=183) def test_decrypt_unsigned_message(): from pgpy import PGPKey, PGPMessage from pgpy.errors import PGPError # these keys are small because the regression test doesn't really need the security # if you're reading this, *DO NOT GENERATE RSA KEYS THIS SMALL* # also, it's probably better to sign-then-encrypt rather than encrypt-then-sign decrypt_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xcA4BFlKzk4BAgDL9E6Lpzq9yNhRP49HXeOSYTz4DPI1A2wxwI97qjZFsJ2lJ2aV\n" \ "SYFpbuS6DEPaya+98HQ6xM7o2PhbUnHqcXHzABEBAAEAAf9U/XOVwpQ57e4mvWPJ\n" \ "i5h/sUGk5FAyQ0Dc4q9oCyAenaIIe5npbsR+oKmUHwJ5wWgfrTaxvAkBl15kMtSN\n" \ "VItBAQDv/8BdIdW2Bc9+qvCtC2xiUJ/3Rd+eyXMZhn4VMdA8sQEA2Y1aRBpWjHo9\n" \ "g9KydxAewt8LUwchRHeonMmILuZ58eMBALP8euss11ELnjDOLrgRP2swnOTTTk3b\n" \ "P6aV8/rbcEXOUgPNG1JlZ3Jlc3NvIEVuY3J5cHRlciAoUFIjMTgzKcJrBBMBAgAV\n" \ "BQJZSs6CAhsOAgsHAhUCAhYAAh4BAAoJEA2I8KkOVzh/+IMCAI308quFk/lJXPF/\n" \ "bpvwwgFa9bRdIzl07Qu+3oQcEm+1cu6ivznewIEmQclSUpSLjXrS/LysQSAQye+J\n" \ "PgSEalQ=\n" \ "=Sg/Y\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" sign_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xcA4BFlKzkMBAgDQZA3bao1qo3XkuUDOaFm1x5TkAAMUUUxtmj+dSR0wl7uRzxWm\n" \ "8naFpsJ1Mah/I8RlS1oZizaDI7BzbOvGUGjLABEBAAEAAf95RBAQQ/QhPxfmzqrY\n" \ "sj6qGocZGqywERMxoJYuOBLFaCjdT8xk0syI0LOCetwDmUWerUPWO52w9T5Gj295\n" \ "YUDpAQD7DSmifDMssvG5F9JYWdKobEwWxVsjyaYR/vbH/1Iy3QEA1H+e66Jz1ERl\n" \ "yPLyl4E5chwO2l+VMxiFod3Dvo8C68cA/0GWJIdK0NzSNZwS6wFabZg2R1pZWxJJ\n" \ "B0tsI0EqbUgNTiXNGFJlZ3Jlc3NvIFNpZ25lciAoUFIjMTgzKcJoBBMBAgASBQJZ\n" \ "Ss53AhsCAhUCAhYAAh4BAAoJED6S3OqHJjksTzQCAM73UuXFtM2qXp4zfOGYEMsj\n" \ "gcKFuFFLyNOhPZo6REeJC7o2+9d7Mwys8wVNTuS3D3o1h49QpYYNjYlgNSZ85pU=\n" \ "=DBkI\n" \ "-----END PGP PRIVATE KEY BLOCK-----\n" msg = "-----BEGIN PGP MESSAGE-----\n" \ "Version: PGPy v0.4.2\n" \ "\n" \ "xA0DAAIBPpLc6ocmOSwAwUwDDYjwqQ5XOH8BAfwOTH6C/lk5bQevArYnrf0q3Dde\n" \ "JDjM/otBckiTS8kvFz1XFfQhIDkZl+fDcRwDFNe9+JKLqOM4jU6FIUwToYgz0ksB\n" \ "f6iZ80U0dzHGtvmEzYSnsYWAglik0ch/E9tyNq/lryrLnrxWu7V26wPfI1TISuKd\n" \ "U+w1HPGoH8ugo6GkeqBdeED6gJfKEm1qgrHCXAQAAQIABgUCWUrVMQAKCRA+ktzq\n" \ "hyY5LLcHAgDHYjKVbpd5/FV4+CZ0H5yTnrD/vZ+QebDC7CmOM7f1Q5L1AdG/K1rr\n" \ "+Ud/YHq3NVk5UGU0LDfjdBwVaJmOjEUx\n" \ "=ITfp\n" \ "-----END PGP MESSAGE-----\n" dkey, _ = PGPKey.from_blob(decrypt_key) skey, _ = PGPKey.from_blob(sign_key) encmsg = PGPMessage.from_blob(msg) # this should work decmsg = dkey.decrypt(encmsg) assert decmsg.message == "Regression Test for PR#183" # this should raise PGPError, not PGPDecryptionError with pytest.raises(PGPError): skey.decrypt(encmsg) @pytest.mark.regression(194) def test_pubkey_subkey_parent(): from pgpy import PGPKey # import this small key that has a subkey keyblob = ('-----BEGIN PGP PRIVATE KEY BLOCK-----\n' 'Version: PGPy v0.4.2\n' '\n' 'xcA4BFlULU4BAgDeq2bKPPOBzdgd1WF3RBQ0E0kkZbTfpgZjamDzdb6gfQ5TcBhs\n' 'drI4XpxWOV3DorbsZ8Usj4zHx/XmLNCmxwqvABEBAAEAAgCSO76l0qGY/baQ4THB\n' 'QdSC3qeKX8EJn99SKurA+PLYMg6IxLGBpWYIK8tT68xpqQ5ZwE9GodZ2QjfOVz2R\n' 'o4IBAQD/UjtthEtyiMA1CDCPEksfIyd0QDjt82C19MSeqau8WQEA30LydxkjlvgH\n' 'u5/uWVGqoFWhhfw5hDrYy72L6EbCfkcA/2csk7uGw/yg2MDUTlDwdokn1DLGkt/+\n' 'Q/fPAMYvX6gvVoXNFVJlZ3Jlc3NvIChJc3N1ZSAjMTk0KcJrBBMBAgAVBQJZVC3O\n' 'AhsDAgsHAhUCAhYAAh4BAAoJEC4sMTkKIj+F8ywB/AqaNHwi8xM1Rg99mOSib1zi\n' 'jlXALY8pOrNU7Nqtc/6oks+49WeVW5zpE1vl1JPm2WYzvCEnE1KffdyjNR0bQ1XH\n' 'wDgEWVQtUQECAKsWCdSRh6YDP9yuSonfHpBfUzRD/EQvpNnUDiTclV9w6RPMZYk9\n' 'o5oUQTumPKnznsovLpNmIm48DCALMzdTzH0AEQEAAQACAJDfsKNYOM3Toph03pmx\n' 'XmhS0FpJ16zFy4rJjtCYGcUerUqRQ1ehXIY9Ig9J5LitJXThrP4dvUlRCWUcxxl6\n' '9eEBANOiM8ktXW0bPZfBKunWn7ajA0PMBKG8p2d9iBCawBbbAQDO88L8V0cxCRvH\n' '8L1J4gsttPWDOnhw5z8Dq4Zv5U3thwD/WwE0miqfEpYAmkhc0g7lHf6l7qo+SrUZ\n' 'ZKl0GLPLKKFRscK9BBgBAgAJBQJZVC3mAhsMAGgJEC4sMTkKIj+FXSAEGQECAAYF\n' 'AllULeYACgkQCK0qxtsEtqzY7QIAoayZGB78eaImQVOpTLX2jnaDR2UY7NtUy6YI\n' 'XMSumCeZj+n+BexmUm6x2kqg0FJLRwAE4i+rnvFA0HHX40/9d221AgCzUxHuHjKP\n' 'b5wNW20vanc6b6ZMi52MyhluXAIdnvgPkPEzVIS+gGOX2DeT4TXAdosKfD1o5qS7\n' 'ANRbocmpDuO3\n' '=UjzO\n' '-----END PGP PRIVATE KEY BLOCK-----\n') privkey, _ = PGPKey.from_blob(keyblob) pubkey = privkey.pubkey assert pubkey.subkeys['08AD2AC6DB04B6AC'].parent is pubkey cleartext_sigs = ['tests/testdata/messages/cleartext.oneline.signed.asc', 'tests/testdata/messages/cleartext.empty.signed.asc'] cleartexts = [r'This is stored, literally\!', ''] @pytest.mark.regression(issue=192) @pytest.mark.parametrize('sf,cleartext', zip(cleartext_sigs, cleartexts), ids=[os.path.basename(f) for f in cleartext_sigs]) def test_oneline_cleartext(sf, cleartext): with open(sf) as of: oc = of.read() dearmor = Armorable.ascii_unarmor(oc) # It is a signature assert dearmor['magic'] == 'SIGNATURE' # No newline at the end assert dearmor['cleartext'] == cleartext @pytest.mark.regression(issue=199) def test_armorable_empty_str(): with pytest.raises(ValueError, match='Expected: ASCII-armored PGP data'): Armorable.ascii_unarmor('') @pytest.mark.regression(issue=226) def test_verify_subkey_revocation_signature(): keyblob = ('-----BEGIN PGP PUBLIC KEY BLOCK-----\n' '\n' 'mI0EWgtKbAEEAOEjq2UsapzI996tHhvGB7mJTo1sneUso20vz5VluECI0Xv0nr0j\n' 'BfknMFNeuPRR5sopgnrYT2ezJxp60D1NFaKgDh0z0qv9spk9FTP4YtaE5pfZRk3l\n' 'iGgyY7WiJBhKLb7ne3PeG8mtju4T+9ejbN4hVx1Vz9WHKkLGeBGkOcYZABEBAAG0\n' 'HVRlc3QgUmV2b2NhdGlvbiA8YWJjQGRlZi5naGk+iM4EEwEIADgWIQRIuXHQYB9/\n' 'm0hHY/8zq5Y87Iwq4QUCWgtKbAIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAK\n' 'CRAzq5Y87Iwq4RKuA/46Zg3OSmRPJJNQegoDGLGwj81sgrLFPVDV2dSAxYPiGH3j\n' 'JNM760NS51FLHQvxwa9XV9/4xzL9jqsV8vD+lX5aphZS6h2olPAy9CP2FK8KFrv1\n' 'Rap2y9D68LStDv2jFyEYEGCCvon3Ff6O2PxwG98xkaskBPH6knGjK6rrMvYI/7iN\n' 'BFoLSmwBBACbGvXVtDH4aTJ3UbN/3UnLKb05ogmZDpkx8A2qGnUu1QvIxqi56emU\n' 'TfbxKv8jne0qas0IJ1OWrcTAuPvwgH4TJERAkngxzdYXR6ZHEO3/L8s0XSLobW5E\n' 'nsGnFw/PG5Lrxv1YA7nBlCKennrlaU9iiUguOUK7SW7To1SOojTOcQARAQABiLYE\n' 'KAEIACAWIQRIuXHQYB9/m0hHY/8zq5Y87Iwq4QUCWgtKuAIdAwAKCRAzq5Y87Iwq\n' '4eFnA/4oOnM7kjgIYqs2TgAxuddMabx1US9yYZDG097Nxfw1DFJoFOg4ozrrWNRz\n' 'F3AHo7Ocue288VYIJtjH4KB2vGAYdWq8j6bywW7t4Be2WsU4MCJqETxS+3Gv65B6\n' 'NBq4Y8lJvKO/cwsqYI6XWsJsmnVns0XOdv/k6ZouVdpUu5Fpr4i2BBgBCAAgFiEE\n' 'SLlx0GAff5tIR2P/M6uWPOyMKuEFAloLSmwCGwwACgkQM6uWPOyMKuFrOAP/ZemA\n' 'yfU6zSfiReQ5fsiQhiy2jZx+JVweZ0ESgDuIvT4tlB4WK87OcITd40rTalGezRuE\n' 'fhi3IcnDc7L+kBGNhP3IY8IFVNYGqfowIYLl/RX+3BUjuaDpunO9kIBrhm0WrC6Y\n' '+padVqwTFNFteQR0N9BW1qNf7HB20BCaElxGCuI=\n' '=EoFv\n' '-----END PGP PUBLIC KEY BLOCK-----\n') pubkey, _ = PGPKey.from_blob(keyblob) subkey = pubkey.subkeys['8ABD4FB3046BBCF8'] revsig = subkey._signatures[1] assert pubkey.verify(subkey, revsig) @pytest.mark.regression(issue=243) def test_preference_unsupported_ciphers(): from pgpy import PGPMessage keyblob = ('-----BEGIN PGP PUBLIC KEY BLOCK-----\n' '\n' 'mQENBFtKbSQBCADDMwreTvJkDQkgB+n0GsNbMFKEjPYGKP365y5w+FlJ2zg69F3W\n' 'ituYFQcTwuge2XSh58k/XHln+MwjNc5cDQaWLtMuyJbRvLK+8MdpdYlzrlyrsgDI\n' 'L/1PAlGMVWB83Iu2kxqc0ppTxwsltAcvRJBE+9oSiWRACQviDmX5LeBmPoGqM93w\n' 'LeN3QT/tu26rxha374HPgSqqNR13r3xl7gQre+pA3jmNQqwzPnEmUKN3hO852NAw\n' 'QOPbf4yTCcbeZ6iZ/h0mW4DvbLiPbzUsXRvgTo3X/kzJD+ZnznvJvjcKrkXzaOAp\n' 'qt6Nd1LmWyv5h7gBYgBNaQONFeMl9MVBFUflABEBAAG0GnRlc3RrZXkgPHRlc3RA\n' 'ZXhhbXBsZS5jb20+iQFPBBMBCAA5AhsDAh4BAheAFiEEL7Bmz7+mS4Q3LDSMbIbe\n' 'TttFc4wFAltKbXsFCwoJCAcGFQoJCAsCBRYCAwEAAAoJEGyG3k7bRXOMI34IAINL\n' 'bYmZ95RgVX98+tjBAliV9xZaaxu4xpY8vz4pCwwFj9QBMxkzmITC1yb/Vav6pLFK\n' 'UISLGeOUqskVg9uQn8YGSnRaKoxetL894o0jGLyQF6ujF4OFhbfRlaLbNACDQqg0\n' 'bzV1E+s6RsnbwR7aFlOcgz5m/j7+c9t/BnZ4qOYBW85iLyzQA4BgTBSocdyom3EA\n' 'osCNY4tFuySFlOF34OLu1k8y9RP0KsJJptEdIwEqSxRKuQ5KTbopx9kvxVfOOwgy\n' 'RVYuP/OQrc/MQPGSC0Rmh/iCNEsTOIxcwnotmyRd8qDpw/EBj1a0iWxzPYOzXoEQ\n' 'Ff2ipWRkzS3AyWVJJxi5AQ0EW0ptJAEIAJXwfVD+3oSLPedMBvpfnveu/LjFvxJk\n' 'ohawApu63JzJNXoRpjeBhox073iEjeSbvq/pJ/+y0t6KkFZXoXgpqACGDNjPpojk\n' '6YTo6Da7GpyXefhKyH4IQ9Lbd9UIEhOKfktXTJfR/EoCZb+rmTm0WnjwkwOAVdQv\n' 'vuMRm8Hc39xn+Mt0CV+0KcYHhNfK+A2XU6bZkHuwaTzxTaotmeLeCgC+BA2Phwxp\n' 'BIhkSNE8ayYLN0VBPraw28xONzNV5e6f8RWNoGTDQxhZflmvIGz/XO5wo1DV1G0k\n' 'VIR49brAmrapqpCW7XWhuuupVbrpbjRUa+c4G03tySXQXUTdA3etH0EAEQEAAYkB\n' 'NgQYAQgAIBYhBC+wZs+/pkuENyw0jGyG3k7bRXOMBQJbSm0kAhsMAAoJEGyG3k7b\n' 'RXOMKbMIAKymk6Fe1qpjXtK56jpMurz1wBL0/twQbvtKQlgMBNdro0MX30xKGXh1\n' 'rCEIV3ls7CJnUm2NEeqFPzFZhsZS2FkgDXXT20K3S6nscv8xlF2z+jktK2RY6oCJ\n' 'Lgw447Rgjw5ARgW2XNrGRzapAf4KBgcyO1KtTCbjh8leg4Fs1O7B8EbiBvoeUJR0\n' 'wj2xNG4cOHoWN7Zjv8lLsJn60+ZbTeU25ghybmt7WjCs4ht7TZmamerLPzrFvP2c\n' 'ftLsb17HhrBPdfs42SsD8A816JDM7PcJWujlDV9FPJgoVjndK+4Jfpg9b4jOBA7J\n' '7zeGuobtKdS9Y97BVFNtTPZK66YUIEQ=\n' '=lGIy\n' '-----END PGP PUBLIC KEY BLOCK-----\n') pubkey, _ = PGPKey.from_blob(keyblob) msg = PGPMessage.new('asdf') with warnings.catch_warnings(): warnings.simplefilter('ignore') pubkey.encrypt(msg) @pytest.mark.regression(issue=291) def test_sig_timezone(): from pgpy import PGPKey, PGPSignature # from https://tools.ietf.org/html/draft-bre-openpgp-samples-00#section-2.2: alice_sec = '''-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Alice's OpenPGP Transferable Secret Key lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA /3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb Pnn+We1aTBhaGa86AQ== =n8OM -----END PGP PRIVATE KEY BLOCK----- ''' alice_key, _ = PGPKey.from_blob(alice_sec) class FixedOffset(datetime.tzinfo): def __init__(self, hours, name): self.__offset = datetime.timedelta(hours=hours) self.__name = name def utcoffset(self, dt): return self.__offset def tzname(self, dt): return self.__name def dst(self, dt): return datetime.timedelta(0) # America/New_York during DST: tz = FixedOffset(-4, 'EDT') # 2019-10-20T09:18:11-0400 when = datetime.datetime.fromtimestamp(1571577491, tz) pgpsig = alice_key.sign('this is a test', created=when) roundtrip = PGPSignature.from_blob(str(pgpsig)) assert pgpsig.created.utctimetuple() == roundtrip.created.utctimetuple() @pytest.mark.regression def test_ops_order(): from pgpy import PGPKey, PGPMessage # from https://tools.ietf.org/html/draft-bre-openpgp-samples-00#section-2.2: alice_sec = '''-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Alice's OpenPGP Transferable Secret Key lFgEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U b7O1u10AAP9XBeW6lzGOLx7zHH9AsUDUTb2pggYGMzd0P3ulJ2AfvQ4RtCZBbGlj ZSBMb3ZlbGFjZSA8YWxpY2VAb3BlbnBncC5leGFtcGxlPoiQBBMWCAA4AhsDBQsJ CAcCBhUKCQgLAgQWAgMBAh4BAheAFiEE64W7X6M6deFelE5j8jFVDE9H444FAl2l nzoACgkQ8jFVDE9H447pKwD6A5xwUqIDprBzrHfahrImaYEZzncqb25vkLV2arYf a78A/R3AwtLQvjxwLDuzk4dUtUwvUYibL2sAHwj2kGaHnfICnF0EXEcE6RIKKwYB BAGXVQEFAQEHQEL/BiGtq0k84Km1wqQw2DIikVYrQrMttN8d7BPfnr4iAwEIBwAA /3/xFPG6U17rhTuq+07gmEvaFYKfxRB6sgAYiW6TMTpQEK6IeAQYFggAIBYhBOuF u1+jOnXhXpROY/IxVQxPR+OOBQJcRwTpAhsMAAoJEPIxVQxPR+OOWdABAMUdSzpM hzGs1O0RkWNQWbUzQ8nUOeD9wNbjE3zR+yfRAQDbYqvtWQKN4AQLTxVJN5X5AWyb Pnn+We1aTBhaGa86AQ== =n8OM -----END PGP PRIVATE KEY BLOCK----- ''' bob_sec = '''-----BEGIN PGP PRIVATE KEY BLOCK----- Comment: Bob's OpenPGP Transferable Secret Key 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 =miES -----END PGP PRIVATE KEY BLOCK----- ''' alice_key, _ = PGPKey.from_blob(alice_sec) bob_key, _ = PGPKey.from_blob(bob_sec) msg = PGPMessage.new('this is a test') sig1 = alice_key.sign(msg) sig2 = bob_key.sign(msg) msg |= sig1 msg |= sig2 it = iter(msg) assert sig2.signer == next(it).signer # OPS 1 assert sig1.signer == next(it).signer # OPS 2 next(it) # skip contents assert sig1 == next(it) assert sig2 == next(it) @pytest.mark.regression(issue=341) def test_spurious_dash_escapes(): from pgpy import PGPKey, PGPMessage message_data = r'''-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1,SHA256 - This is stored, literally\! -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) iJwEAQECAAYFAlQaCpEACgkQBM3VPIdAqKYrhwQAyQhwiqrR6oZ5fTBm4JyCOEND 72Kxbaz1i9Qh0jv7DmgRjb4udh95UQ8U0qVnmnhA8E2deKeDcWTS4fzUkU6J9OdH /GPHpL9QEtOJ7xifzJsnKaNJVynmNMtYOqHQ9gCmXx7jM2ngxbTKBT8YZlSLMUdO uoUFKrJGv0LWlSWHkeOJARwEAQECAAYFAlQaCpEACgkQKoNNjlkY6IYrhwf/ZnMN yKIVxGl+5/9oovvgz2MtGt9B09xRg4BqD+lUDshzQUvQIjBXZ7ZEGSWqerRymZDg ZzHpb1lv9oAOVU8f1qsMQJJkiz7Q+xu5FfgAp0WzMHJNy4QOmB4Kw/7UbTwdUXzw EzKwbJ8Eg97vJgYdfqUZLu949dwJvyYZzGDdkbrnsaZ8H29XkKXNMlMinDQjvFBR djgkILl3ZIdC3p+KechV3uYsqwje2qNEo69KukihPhzCe9o6/Yub5gdC+DSQDGl4 uPjk0zXjds4G5J5Jd5g4o7vhDWs8InxX4AcLfD6lH1XQ1VCZBpucun5CVsU3dUAv yvO7C7FubDu1GUxdbYheBAERCAAGBQJUGgqRAAoJEKXc3JZkUxQOZ+IA/3KI8Mnl k3jfpRQcvtSYFlU9WZk9SqZX6xirnV7Hloq6AP9ZlivPrJdWmjRyyShkMNgP/c63 cjMX82ahGPUVlyMP4A== =bcSu -----END PGP SIGNATURE----- ''' key = PGPKey.from_file('tests/testdata/keys/rsa.1.pub.asc')[0] message = PGPMessage.from_blob(message_data) assert key.verify(message) PGPy-0.5.4/tests/testdata/000077500000000000000000000000001403641706600153215ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/abe.jpg000066400000000000000000000303731403641706600165600ustar00rootroot00000000000000JFIFaiDs̈5LX`B`;Bd2F˴"ig*zm S pK_N`iŞ]jLod<Y2SR?`?׋?I|/xwN$<$\bM/ú-ck~akeufDռ? ]G:мY$i z|ܤ]g$i$,,Hi) 7rCidsG4ϹYķ)}0 FkD2ܿ;s˧xVy ̊BX)R$/.I3Ǻi~ʟ/>2iuأxuˍbxT)Z5n$AK 0Ur]“N׿FE)7^M]O1/ x(RQ q[^}PEiKmu$Cs7{uA=jȴX^l iQI#VJ4^g jյ'uZMQiע$ښY5$lb#t4.~XzKHF_j~Gu^ [*K-ٸ6KA$.QDJ֌췶d56V{c<2;c @Aq¡|>Bo*- Q_k+±bFld`ׯ+$W<5/jq дK+ hVHcs.YmfIDEvf 3",$ U9Qd\yTǻ•ݔ0$ yZeVت7+bXR 6w$˵v2Y@Vq:)iBfB-8`$ 1 qzdfBG9HAȧ|^mQy*&?7"YlU03r2JK0(o_/f%T7VD*u,qg+e1pD؎ѐ C۽FrV6wgr72 )\#l#iT/Jn#j?#m%R mYx~;J.@C3 {F1|?K^ |M{XtĬ]/DZhZ30_ܜzn]P# ɔ/dl, 1'9S=3|d^]q נei@K%ַ_^á18o߄RivMW>lJ5icj~uXupE$mˉ՜,n6owAkd/ocsp|׏cFO Rsn#i )jzΧ×<5Y隕M\B&5>aYK٪ nyߏ^|4ֵ?||Si# rK[gӮ /5x,".k{DRaq)JVK~Uum{[b҄e-m}#SC¡.6ClP@ Nj_?٭?1] Yf2T 7(1v~Y;ਞ-ֺjqX.˙]NK'LBY ÙkyW ]]׳x.ڌY[94kKYav"-_%Er{k.W-9WoUwuyG$VSYn$+{R[%V. l<٫h? h?x7׬/K5k? x8㍮.*wIkdB,^ϧNjz5=:^cd4役H}[Kk^+vζmk`xύtX2Xp#[^X/X^I#voѬæ5g'uq{(MƥNukZxh<|9 ^ExgHl,L2d8u#kl`#Rblfڪ8@H eQGKO']7 5߅:幹>]΃bo7VEc{5N~l!eeddi;I 0%P~9":?q|O_y$Y3>7 $!;eFHpp˽ F!'a_RL9U%?pdpG,f0ccɵm>K}ebH`v)*mI%l'~}В:,<R)bAwuVk=k"}G7AXd *)|^{cY'8G KJhU|gzp#9p:(AQU)FHbwn\2 LH>Mxf [|3*60m)#AOKn:MJ)_k{6%`3jOyIo2F/Hw&5c!o|kzw~(V{C|6[˭Z XWSI.:Kim;>뿉6zkx^Ŗ>esw_{p,4ټ#5 Iv3 1t[n/O=[ ~ <xo[mk׺hP=RYϚck\HG柋 1>B%w#zSW׬4ٴk27Zޝ2_Gs-ղ,H?6ObF_cƺEǁ ÷C\44~:u7(đI?w/X|F!G u]/U;}GB {~^,5֬uᲞĶZ|9:d1L-շ5&욋MѾ-w ?^!a?K{r4 '즃HO1_if.%6įo?kmKLw+iZ4VV^KEmi`&oL;8gIc)=U #c}F44 ۂ]bpi_\Ts'uբ4#8^2Iz85q/|c7q,_,`Ȏ68bB0 ik R022gvaI\G#"WpdT#FT}3E$!LԘ($e܁mpw^ǣ)pj2ܡ89 YkЖ83C.62gWw(PvH!mYH9ۅ?+b:fР8=Ac!+1)b'v9ld 2)YO)?f/c޼-CAH.&;y|Xn_ Z'?L|1wSV7È~\|U?5o*df|+o MtOQ5-.k?y=j5(evɧ6[IAE2FT! G߉¾9Htj߅!mBWoͧ$wvWy=U彾W49;I{{>2~^2ie.m e ~j1,f9<0M]h_mt+wJ]3RUiu!x kr$& ?loY[5hZ#x^SWl/m{-__Y[}+W[Ԯ&xҧM/;~1hV +>i2Euc=:+/%e|Qe%xX3i=c5kQPy'O@9Ws$Ѭ@.I($UV< py ds2 7>B"1T# Gn$vu[*\u;.WmNGʆѫ0M=~Rn|שּׁ46 'fU@Vߜ#aPU|_^I^I!-" V `Jkor?.MUa974O)hdˊ1\pc ?2<62WzO27L^72<SLMb)lς)'ҥ{[3XFXhۯI3yci5Z,X|K4χm_x^X4k+])5Ηk_jEg%ɛPZF|G?A.iušM .GӓP5ztk=CuOo$:, fHњQt$ys;uFgrT;YY??ϊK/(&M#–=Wwv)ooßj_h[:حwgS *5Ԯ[#/>k؇ d|7`sA6xc ~%YX\[ˤx/ U1kGy%ɂ?&XV=/ ,5 ;nJא#}xmYJYO<2j0IXWbgGSW⧈h_o:5ll#4\Zǥu|ڂĖumOV(4J"=*}:jRzi4$ ~4p A''=֙_fG+4;{85-/Úw[Wm sm׎gR O}oPt҄K}]KP;~mt;y.>(̞ Oh'o~~#Xk#WU<|2lIC}<7^|Ii%:Z;]L޿#|ooj}B4Ӛsqn}Jso*ǻʍ-('۞8ݰʹ#+NKǒm'Biӵ>m[!pWfF*Ώ_ay *Uv&VAp-60I+ފ7Snu?|љV2O׼SwS?u]7@𾁦6W-mo$(Ÿ0Toe= J.~x|Amj:]5>sjp4˖Bȱ`$-gEwϾ Z=j6kS t{'߲I絸Q1/pMO{kFs6+F8E1@a"Ʋ\/h7}~ПS5{kW%ց`K6WpQ LrMsx#ArgNӴHf?dկUweTyf\HL$]P>(ii6K$:{mm]bkHB~aoKhFte-BCt;HeQ ww?oش0~+Q,y-&)!m\v%FY~σ?in^헄<<}4nx:=Jko^T7Nh%>eL|OMK[_M+[?f#DܶX1&×ިԂqpdgݹ̊x>[J >̐H Sjpn.j4^OF{[N'^~ß x[-Y4VvMg}u]jkuukZꦡ2ۮAOBͯ? ~s~ :6A2!K{+B]&S[xGhX,+FWh=;˿s~O |,D~"P\GYhbkQ\T3RSRKT$ݯA5gnK=G!m1  k^)~v/u_xj-b0wyeB4+YLIΕIGc{}=Ķig~Zfd[3ehDHUoKOU?Ěˬjj }v OYFos1tG>/5}oI}[Et}}tJ P]b6E'eQQr-$II%vEMi='ŵ("O 7Io3Ȥ˿cF%% /)& WS:Z2RGVAYArJ.Ъ5D̟E|[5 w檑:-ɐ>ŮN8J@qPtBwz?/e:63=Ֆ.29xնۻ{rJRwaR}׻/^_~8~m⿃?|mIY:F4Ihr3ͣF=isGfO/&#_-sxe7ſ-ƒoP7y/VU =փw{2#IZoGiJ ۫iDý-8ce.$HiZ% ua`i${%ռU4a1+ĩ,-fiۙI]ck֊JQ/}1IW|$?o44IՖ }CMt۷7!]CH-lu+X&k+H3E2_˯cU_GyWA|[?kVzƞ(eQnmn4kx'ٺ(uB+R4psNNҷ,cѶEin/E(j?p7dܢ*+$X'V2n/Ckk{kbj4V'ٞlȨ&j]̂kyi]"E'mwNIw|gk6ZGy4Fl(ˁ,0(/y.&Idʋ1Pf:Fvꑋb} ;2mej+#YdCov8"@bd.PE\߶FǔUoSy^Ֆ9I>Vj]-Zx-ak =ϋ 䴓$ntk6mWMW?u`[Fq?T7DpYL!Hܹ2j.͝d| Xv7ÿOޣ}Mld*fwok4foE?:m(x?5_3ž!69Yj^vV@ZB-e+ٗgP5ޥuyd6)֫c+ Nif"IBC? -(QN~^߭\ ' b4 2Zf׊1$~Ӡa8Ip,d@fIAֵ-CDm`Y<YiZ݌1p]JpVβ9|mhw]w:jrFi5%NXfTkƞ0Ρxn5K:O$kxŸ,qebC0ۗT+lkK?;wowXby{]*kk $wmw G^C&Fȁn-9,.t{Xh/ΣrUޟxS/"-3uu;HVt3 KTx|}V/ Z\xΘwl ۷B+2ά\xY'uĪ>TF[߃ipr]ݖ!G=r (RU%֧QJCHPӲLSS1C ehv0C\5̊o#mB{;,^I-n&m "Ƥo?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~PGPy-0.5.4/tests/testdata/files/literal.dashesc.txt000066400000000000000000000001401403641706600222240ustar00rootroot00000000000000The following items are stored, literally: - This one - Also this one - And finally, this one! PGPy-0.5.4/tests/testdata/keys/000077500000000000000000000000001403641706600162745ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/keys/dsa.1.enc.asc000066400000000000000000000076411403641706600204460ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) 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 =5irF -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/dsa.1.pub.asc000066400000000000000000001376341403641706600204750ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org 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 dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAZGVzYwAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xv dXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0 IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRl c2MAAAAAAAAALFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2 Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4g SUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAAT pP4AFF8uABDPFAAD7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521l YXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1 cnYAAAAAAAAEAAAAAAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZ AF4AYwBoAG0AcgB3AHwAgQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQ ANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFg AWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAId AiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAML AxYDIQMtAzgDQwNPA1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQt BDsESARVBGMEcQR+BIwEmgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWG BZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZ BysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjn CPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3Arz CwsLIgs5C1ELaQuAC5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1A DVoNdA2ODakNww3eDfgOEw4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/P D+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKj EsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9 FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkg GUUZaxmRGbcZ3RoEGioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzM HPUdHh1HHXAdmR3DHeweFh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDE IPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJ JTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymd KdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6C Lrcu7i8kL1ovkS/HL/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4 M/E0KzRlNJ402DUTNU01hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlC OX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8h P2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVV RZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkvi TCpMcky6TQJNSk2TTdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLH UxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoH WlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2Gi YfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2ma afFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHw cktypnMBc11zuHQUdHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6Rnql ewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6 hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0x jZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cK l3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFH obaiJqKWowajdqPmpFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavp rFys0K1ErbiuLa6hrxavi7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbw t2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48Jf wtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42 zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp2 2vvbgNwF3IrdEN2W3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf 56noMui86Ubp0Opb6uXrcOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q0 9ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf///+EAgEV4 aWYAAE1NACoAAAAIAAUBEgADAAAAAQABAAABGgAFAAAAAQAAAEoBGwAFAAAAAQAA AFIBKAADAAAAAQACAACHaQAEAAAAAQAAAFoAAAAAAAAASAAAAAEAAABIAAAAAQAC oAIABAAAAAEAAAD0oAMABAAAAAEAAADlAAAAAP/bAEMAAgEBAgEBAgIBAgICAgID BQMDAwMDBgQEAwUHBgcHBwYGBgcICwkHCAoIBgYJDQkKCwsMDAwHCQ0ODQwOCwwM C//bAEMBAgICAwIDBQMDBQsIBggLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL CwsLCwsLCwsLCwsLCwsLCwsLCwsLC//AABEIAOUA9AMBIgACEQEDEQH/xAAfAAAB BQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0B AgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygp KjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImK kpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj 5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJ Cgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGh scEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZ WmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1 tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEA AhEDEQA/AP38ooooAK8w/ZO/a88F/tpfDrU/FHwNur2503R9e1Dw5di7tjbzQ3ll OYZlKHnBIDKe6upIByB6fX4pf8ElPjB+13pPwt+M11+wj8JvhN4w8F+I/jL4p1K3 1PxH4nm0+e3le6UOht0T54xsTDKwJywxxQB+kI/4Ku/AvSf2ULX42fEbxnb+Dfh3 f63eeHrXUNbiaGS6vLa9ns5EihTe75ktJ2G0E7ELkKAceo/Cr9qP4Z/HXw7Z6v8A BT4h+CPF+lajePp1reaNrlrfQXN0iF3gR4pGDSqgLFAdwUZIxX4Yf8ElrLSPj98Z v2O/ht+1/pWk6l4X0vSvig1voWpRLPpt/wCI5NYuRdWk0MoKzvHY3DOFccLKCBkn Od8Y/Bugfsuf8FxvFmufsxaVpHhT4TfDX43/AAxsdV0/R7ZLPSNJn1HSL2zu2hii CxRY81hKFA+djn0oA/oC8dfEXw/8L9EXU/iXrujeHdNeeK1W71O9jtIGmlYJHGJJ GC73YhVXOWJAGTXD/te/tg+Cv2IfhCfGnxzn1ZdNlvoNLs7XStNm1G/1K8nJEVvb 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 OpdBAvkPo6o= =+oh3 -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/dsa.1.sec.asc000066400000000000000000000074571403641706600204600ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org 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 XsQFpteizbyj5oVf8Q== =oE80 -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/ecc.1.pub.asc000066400000000000000000000014331403641706600204430ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: PGP Command Line v10.0.0 (Linux) mQBSBE1TXyYTCCqGSM49AwEHAgMEgfu8IO6p6NHDzquwqBhZJbET0axCzVx4QDvY PaGSNcZe1tsT2R2zRQfQEpv4iYGHjSmtv4/NFyCv23Z7s/yq/7QsZWNfZHNhX2Ro XzI1Nl9ub19wYXNzIDxvcGVucGdwQGJyYWluaHViLm9yZz6JAKoEEBMIAFMFAk1T XyYwFIAAAAAAIAAHcHJlZmVycmVkLWVtYWlsLWVuY29kaW5nQHBncC5jb21wZ3Bt aW1lBAsHCQgCGQEFGwMAAAACFgIFHgEAAAAEFQgJCgAKCRDQEFX7yt0mjqQxAPYo zS5vk00/v2zOg6zSX8+9h5C+IQ8M7wuCdI32fBEoAQCrCuL+VrPHKNgcyG/QqRfT W245HBWY8UaOfEhnYA4rr7kAVgRNU18nEggqhkjOPQMBBwIDBCIhHRn0uCCSB1jY leEgAq/HEqbNjmOKs4CK1sD29kgsQgmg2twUpxCLnGtrLO7QNADuYo1mo6dTZ4F8 bsTSdk8DAQgHiQBkBBgTCAAMBQJNU18nBRsMAAAAAAoJENAQVfvK3SaOfmgBAKSo PrKWfvpxtzPQLbogAP7jcpI1+VvCx/DXKzgNspHwAQCafHFCcdvzJf4SU3l/3e9V 2dmbyLwmx1NwJpdLfZQt+g== =cbCK -----END PGP PUBLIC KEY BLOCK-----PGPy-0.5.4/tests/testdata/keys/ecc.1.sec.asc000066400000000000000000000015761403641706600204370ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: PGP Command Line v10.0.0 (Linux) lQB3BE1TXyYTCCqGSM49AwEHAgMEgfu8IO6p6NHDzquwqBhZJbET0axCzVx4QDvY PaGSNcZe1tsT2R2zRQfQEpv4iYGHjSmtv4/NFyCv23Z7s/yq/wABAKNVkW+GZeuZ wa9I2VYLXGiJ5Sh7x1qmk6qum9sV6LP9EgS0LGVjX2RzYV9kaF8yNTZfbm9fcGFz cyA8b3BlbnBncEBicmFpbmh1Yi5vcmc+iQCqBBATCABTBQJNU18mMBSAAAAAACAA B3ByZWZlcnJlZC1lbWFpbC1lbmNvZGluZ0BwZ3AuY29tcGdwbWltZQQLBwkIAhkB BRsDAAAAAhYCBR4BAAAABBUICQoACgkQ0BBV+8rdJo6kMQD2KM0ub5NNP79szoOs 0l/PvYeQviEPDO8LgnSN9nwRKAEAqwri/lazxyjYHMhv0KkX01tuORwVmPFGjnxI Z2AOK6+dAHsETVNfJxIIKoZIzj0DAQcCAwQiIR0Z9LggkgdY2JXhIAKvxxKmzY5j irOAitbA9vZILEIJoNrcFKcQi5xrayzu0DQA7mKNZqOnU2eBfG7E0nZPAwEIBwAA /0CQPOwosUoHkyGtn9Qmp4/1Dg6betDZ92670XtEO+HKEbaJAGQEGBMIAAwFAk1T XycFGwwAAAAACgkQ0BBV+8rdJo5+aAEApKg+spZ++nG3M9AtuiAA/uNykjX5W8LH 8NcrOA2ykfABAJp8cUJx2/Ml/hJTeX/d71XZ2ZvIvCbHU3Aml0t9lC36 =uaXF -----END PGP PRIVATE KEY BLOCK-----PGPy-0.5.4/tests/testdata/keys/ecc.2.pub.asc000066400000000000000000000012511403641706600204420ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- mDMEXL8mcRYJKwYBBAHaRw8BAQdASFm0/fvw3kw5Vjz+vVjKq2Xhy8aX4WAcr+YF n72YSHy0PkN1cnZlMjU1MTkgdm9uIFRlc3RLZXkgKGVkMjU1MTkgY3YyNTUxOSkg PGN1cnZlMjU1MTlAdGVzdC5rZXk+iJAEExYIADgWIQR/D5etU51R90sBi9EGLmrF IF2HHgUCXL8mcQIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAGLmrFIF2H Hq3uAQCEY5BFGUt+yKQ0nzMv18EPH/AArvctRR4efdTXPAc6JgEAz/Gp4THGptmf Pn5JALETkH86zNUApJgSWeF/HifRwAi4OARcvyZxEgorBgEEAZdVAQUBAQdAMzdC zRVztPW7BXo+eZl9J06cclRV6rcw7udWUE4Rvj0DAQgHiHgEGBYIACAWIQR/D5et U51R90sBi9EGLmrFIF2HHgUCXL8mcQIbDAAKCRAGLmrFIF2HHgK/AP0XT+98jOMo 6G8qoFU7ANLfn4E3bxV0sAH9g/q/rnU7FwEAkpn5woqcil5DexELJoKruxEQ0M84 3wriYvL2DwktCAs= =OgJa -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/ecc.2.sec.asc000066400000000000000000000014201403641706600204240ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- lFgEXL8mcRYJKwYBBAHaRw8BAQdASFm0/fvw3kw5Vjz+vVjKq2Xhy8aX4WAcr+YF n72YSHwAAQCamKiDL90+GqgU5W7Y/givu0p9aUcW8XAaKh8y8f122A/YtD5DdXJ2 ZTI1NTE5IHZvbiBUZXN0S2V5IChlZDI1NTE5IGN2MjU1MTkpIDxjdXJ2ZTI1NTE5 QHRlc3Qua2V5PoiQBBMWCAA4FiEEfw+XrVOdUfdLAYvRBi5qxSBdhx4FAly/JnEC GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQBi5qxSBdhx6t7gEAhGOQRRlL fsikNJ8zL9fBDx/wAK73LUUeHn3U1zwHOiYBAM/xqeExxqbZnz5+SQCxE5B/OszV AKSYElnhfx4n0cAInF0EXL8mcRIKKwYBBAGXVQEFAQEHQDM3Qs0Vc7T1uwV6PnmZ fSdOnHJUVeq3MO7nVlBOEb49AwEIBwAA/1yFWz6KQ1cHO+dce/Moq56wvUqJxVMB EGDIFjyxs9IQDyqIeAQYFggAIBYhBH8Pl61TnVH3SwGL0QYuasUgXYceBQJcvyZx AhsMAAoJEAYuasUgXYceAr8A/RdP73yM4yjobyqgVTsA0t+fgTdvFXSwAf2D+r+u dTsXAQCSmfnCipyKXkN7EQsmgqu7ERDQzzjfCuJi8vYPCS0ICw== =siss -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/mixed.1.pub.asc000066400000000000000000000037151403641706600210240ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- mQGNBF0yIqUBDADraq8m02SBtv+4ZdsWSIQw2X1xpl3QlX9ww06lfiFWMwtSLCQe 89QIzu88QzcV/YAAEjRo9NMapyqCVwlRdaGQ5kGb1m8/tAbekIqFHsmqtTdlicsy U+XDxQHMe/lGK1wFGoHkB1dZHUBlk6hqKwuMwyp+zKsnAJPbuiwD4fjNJYjn+dwL mrvSPgGOhYjvhCSTZMWBMWdNHgwSaQQI/mhHyuz20urux03JPxJbagFjsdyDxXKX 8YGPEBvn36N/GmanV+LvmspDjrYRJNooVeZrhEyrPxm9VnXoGxaZXmjiqrguAtJL f2w6JALeDDnNPGizMoazCwkU+BHBIEAwikPHj02BbAjW9BJF8+HRSUm0lorJmRVA V5cWaPNh8LlLH662ZFBZAeZr4XEucfdqvm486nXcEFlzj+SJlvRkesAM3h8VeFn3 8OhZW1bdsD3Bsbgm8q56CDstmCWBjMv/4hEw6Mp3v2UIPneDqnk50cH+8J49Ag+h g6uWi9x0/6+BCk0AEQEAAbQxTWl4ZWQgdm9uIFRlc3RLZXkgKFJTQStjdjI1NTE5 KSA8bWl4ZWQxQHRlc3Qua2V5PokBzgQTAQoAOBYhBDaIlc8KQi6uc28xiP+7NPsV uTriBQJdMiKlAhsDBQsJCAcCBhUKCQgLAgQWAgMBAh4BAheAAAoJEP+7NPsVuTri sQIMAMHgq65TZnEibo+G6ECh70PMjgFpGRfpd95STO/UOeiP5rVmi4QpnocfUtZw q9YEO8f6KUe3ijoHkTRHM3HA4ev3HWCgIC+RpKu4y39EDf/NpZ0JwFI1Th+f1gRl UIPj3cYGrwgNqc1Xbk5pfRtjFXnGUpFJgwtt6I3ENliABQ2l4QT7J8l800AOSGoq EMsqRYCBCk2DgZGezh1mS66wSa7NR+Jcf1jaRUCc5s2IEVkFdTxxmF6y6e9erAue T3lSe6jQjk5DtbZv9rYCplJvXPjJT3V1SP7BKdneuOyydvuprA3r4Q4UVpDArTLa /MnRwV6oVkKQ+mJopZ/wgcF1TNDoKfBcUlqQr91/PqR7jxF+GwDZqwizm9/T0Qzt QmRtXzYZVsTeYirvUQkw8+mOAfGLvhUVVgV6EhUvImiMTrQLP6N9uTki7COQ25kf HEHSypiEG2Sect7D9HZ0XS2aM6MYutUyorBawH4APT5Exll68Mm57H+OBPDp8Veu Kzt6vrg4BF0yIs0SCisGAQQBl1UBBQEBB0Ah/2wCa25j9+Ptd9ofzC8d7Less3MU Dn2AFne1OD6WMwMBCAeJAbYEGAEKACAWIQQ2iJXPCkIurnNvMYj/uzT7Fbk64gUC XTIizQIbDAAKCRD/uzT7Fbk64sAzDADSYLERof681Su/8ayA4PF8pWT8vN6A3WXA G1HK8m3ue4imEVYCWng9+tCVpa5rzB3cfZnVK/xGD4Rnmut0IAwBbfNZF8JNUzZj Lp9s+ij3PloaxpgapiCdRE8C3C34FuHnAoSjE5ubt89aGcNXIjLjh+WjcTjGyTcH FiQMieUGpjGunOCcCukIWnltzhPAI4nRZH2gms4TmUi/G27eDU8KoCIaKjXMnGhI sQFMAYdMyFM4SL8gSc0jt1iUG0EYXksqw/O+uXNzbHB25mGce8GmH6VdV/4Q4MO5 FBBq0ECRHXp6zP/nh5E4/Ge9bVzOnmMBhC2i7sekrRWfeFXXxYKN4zQLynenGmAL 8O9ja0nIAZDF1eB9kDIdltg3XlBtv0NCrgJNx/vlKp/LLcnCi0Ig79NCcLjd18uo sioTrCB61kH99Gczj5wFluyodvvohZD0jymOTWzTbYnv99Ry7jnHLD8s3xBZ7GQ0 LNugOy1CqXQUniQjTIIhGUHrfqVP75w= =JuLK -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/mixed.1.sec.asc000066400000000000000000000064441403641706600210120ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- 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 LNugOy1CqXQUniQjTIIhGUHrfqVP75w= =6x9u -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/rsa.1.enc.asc000066400000000000000000000130731403641706600204600ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) lQO+BFPQJtwBCAC6zDYtoJ06t1S1NDOV3Hi+FOGDnfNIl0eTnVJyvLHKpLMkF8/i iJjJSRx+Nh4IxG/g0sp02oeAt+XX2g2VPk8qwGhmlKHPqRkX+0f+3rPia+w9G0L6 OMBXghODsxcx3jRqja6BZsLNe+Y6lOtOQ+NBhHxK/Go2FyVjJNKg36dacyRvUhld pBTA3nmPv81ohcxZALPris/MMJF8RoaUEBkKcW60iV/Us3p8qVJhzf5q5KoBARWK vH+6blwuv0RMehOqHwXhApcuSV56oAoJi8Gisijj0SJH2zfh+TbjvmZtr9TPaD7D jaXRtthOyeWFmObvmhg7AggdU1KVjgP7bkixABEBAAH+AwMCdfKUaxYPcuXOyBpS ZShH+uLmQzdSiXy5qGzkWm0+fAQEwHU7ICEw1JXXTfiDlAwXreJhwMgZwGGOMauR y5Jq81RP8zcbW+auOyyp/PrgKZkNbZXYLXzeR/6sJOuZq3z6uqDJxhnFNZU3rpOV ltVVmYo1Pt8gORxMQQsLpgQCB77c3fL5Dj4QCfexSlqpVPqGehjYIdzotKxY3LGU +qr9HWkSuP47dhsb+Qvq2VxX707fid5S7GYscibtDwukCEhvgyCkmfduzDg+o3do JY5mXvFPR1qtnUzXDoeVzokifcVFztWpH+JTfVX68xRL6MePVvS/WH0jDjgzis2z BKAIQzQh1ysqIvGaTXzUYxU3Hy7ToJFc7WOoCtfS8yhJHfyXc86m567eDPZbiWC7 03IeOOjYkHGgnOM/i+uaqzWnjHrEGgwp6/+eUJKrVOhiLU28ExskoWF6RieF3ffg 1hUNXyi01rLTosgnhEnjj+7QJX68eO59WfqGBak0t/fLIjpfeEdOVAG5CF3tbLmi pBFj1vQM6gm0R6iVi/VKIToZcpNzJ8zs3i59RL8Uh5ldhLSUeKFf/rhCuNJeXVem Qx8WTcURjrlakfdJ9c4NQELAROOQDQQKZAdsLHUzU2BEBlCZdJnYBdR7xmb2dqDP FBch51nWbu93hiebAUPG8T0kCThIfdzbnV9RDRMtaLOVd6GYr/f0djmrqYB1W4W1 v2/YsST+2pxcXc7021NMVy3nCVFOapNSUNtrVqRuh7S6Eey4vvdlh43MvPWGpgxq uS0kQxJO68MH4A/H2W10OwvOwDvMVy3CIxLDItU+AlGkc8R491hmRRadPdqaNalU 8BmNDmXQyMq3sPlEjcBlmJgdBGotpLBhDhJRw5khnegVNZbNCcpMOd7glvlg38qN RrQtUlNBIHZvbiBUZXN0S2V5ICgyMDQ4LWJpdCBSU0EpIDxyc2FAdGVzdC5rZXk+ iQE4BBMBAgAiBQJT0CbcAhsBBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA3 Rzs3WMRPNtf8CACf7xlm68wvDe/s1XovJl7Y9dssaWVVLw078AYRHu6PFzojziqb wNSRa34PHv3NgtzyzBj8VUf4dZaTL3xFzyDWOUYYT9KA8qScahGUZCZTu4F73nFG PLTHpKH7Ro+I6HthNTTqWuu4D1ZN4GgJ/VLwM0doL/pHz6YiKvc4grVNW4gcxQwM pvSx+ZszZs6wImv7ofOsdLbq861fXsmLD33ILMws2DipkmCZJi6xPWB5DFaHDGz0 l2txukauadN+UdcnPau0TqvCdS2DHSzkkayvNGNsD/EPumK1dokkl/gigI5UTlvg AggzPQERZUsEexHBpGeDY43Ngb6Qxp5F+STNnQO+BFPQJyIBCAC7O2VG9LeeoEGb lzeyDIZVUA5/TPWV5j8HAvmqjbnr5575N+9snwo3IjmY67JO3DnmzknK51+j2A3n BoCOi5Gx9LpO+fpOKD7O0+8uExWElSromqzHjLySoVVDvGypI9fHuzAF9qPyV58B quC2Tt34QVW9rLiNcyUS58RzkkqC/9Na5kmLf1RssEGyVnbhHoib3oR5eyTSJMgr geACOq66X7JGhs8qjdJfFYUTbwpFEyJDO6y5jYsffW2Q0GoaN6hPqqDkCfWUpieT YwzeVlAvFwjGGG0A0E/6xATJ9Qrzu7DP0tQ+lOFfeWyotwWCUawUKZbNeBymjMLS AHTLgf49ABEBAAH+AwMCdfKUaxYPcuXOMixFilKTrzTEQZH4ah7xrmDW0QUI2etn e9GIPHQ4DnGWuI5PsfmFB1MW/v0RsghkBi2rfFiRNxBzFpBAYzgRWlMk7qAHuofj xCvEIBsfhftNGH83sGtHsQeYfqmiFFdcc5WdMyrFUmJTjbSFUUo0lUE/XSbQLwyS JiTM1Fbo2WQU8bh4AmVYoHPBDxhprlBk0s069DfJd5i1+CpEXdkn5pxJ75DXQbs5 5Zi/g1NYqfhO4Uv53tXCu44FQ6BWmKOPP84c6lvicjCk9cKk3CRWNM5K4uXjCauu BIlWHo8rgRqgQfpW8PqY7h7kiKi2FsBZfEM5dd+xHHkoy4Lu6cib7r+mvZVos3pa H3c10dUIBnjlrKvmv//Pdze/MoyoVo4oglhOhwOei1E9+OE5TxIZhRBr3qNEyILH 8Rsnj5AeWZ6QJGpvPyPvI4ijMo5GjpY5UDyRzGkrXgVYZVGwksutfOoNRd8rmLw8 sw3M6amMs9GCahrpyEF4anf4V5HC2x0cs6Y06jDvTgRJm/Uw0PgH2ObYREFulT7S ffTCQdTTEPM4iu4x4V+TwYw6l9eH+vMRFHZZfkBmBD+VSQJ7qwe6qnw9V3OxB3HC enmUg6HH3UrKkpVLhY8vBvxtwCe2x1eIlDaIGPHnnldAQQH8A7H/7JazNmiyLtWZ WsXmIS1VdvNu3SIwKcfs+Dd5LDR9WrelrJGtqo+luQ00Mxg0CiRbEXiXrS3OnH1T JjzAbsOnX7q/KA7ATHoIJGhJlV9U1W11BwHjYfB3KufvA3mYsVRthOZFGrh+x8tc ssuYP9/fjJnO3biZie9Y5TvpugHDT7C04inongCvGQGVC2YWjzw4J/lVChUkCy0t XNBghELCELYV+W3TYsm6YZamH56ARCwZiMAXWokCPgQYAQIACQUCU9AnIgIbAgEp CRA3Rzs3WMRPNsBdIAQZAQIABgUCU9AnIgAKCRAqg02OWRjohjn8B/489EOaT9w2 tn1OcygayZnwso1dim2ecBH5ORuwQOkY6tu27EJaRut4o+KlGPVmMiInjsk5GRZM GWa5DFeiyZAEJwjTOpu9Ft6f9PmM1bK2E6bbMn9oZKvvP03V+nUUHQCGgX5Wmj0A v1jHS2GvYk5EnwtvQigNIxd5p8txm/wT9ecjS/i1pr5s/XfIec/z9429FrpZiMJw Gs7VSJ7NY3kO8/gOBjRXrn1HJK+foOSa0KvQC95QvtlSGk+xvLsrQX8vKwnLdAVt kVK5dhLiAL50vkE6+oTR2y6k8O5oksgFQ5AhkruWoUSOq5t1p2DKBXS+GGgV8bWF 9A9swG3id2qYYmQH/3ixNcdiFeebcTUei/RemGozhdadixfdlk3VSDx4BeWFBSHl iAE91GxnBk1ZX0WSJk/rZuGP6lKCWbPMHtZxX+ha6wCPAj6HOTycp1cJrbitfYh2 HTOkWFrB0JI144eeX0h+0CNCsS0SysZ+EWQ3RxUhciM6n9CIMurWv0RrjyoL1Pez wqh/Zs4jkSyozhI+UoO553r7YHdisPc884du9QiT4ESUwOYVTNkBbj5+I4llJuu3 V8BOvPa6UzndqgOWjCC2Tq99tmbCSK3Or9ELY7qab2G5L6PlC2hUJJJFIHztYN+B uct4l8OMxT4QBf1MuqLnUKfuGvoQfc0bKntc+q+dA74EU9AnTwEIAPL8q9qi7feG iMc2Nm7EGeMOVQnWnkloRlgYKyWfD5VTcj7rOJmzSN29HF1MZYHN+tWtpHRl/o4H 7SYQUrevPDJwCU/3pSv61Le/CGoyMtPN+t6+gsJns6x/nfSy64Sf7+VLCblIRMkC rxdzOTkLPNiKOU0Z72G00joK2KXh07EIkebzODlcUKNNwDYf2VdohIuhb9ha47Uw 5iMpyY/aN8PghgX+Y8k6nnC7u9fe/tej9T3PLZrBT9oWqhktq2R7ThFPAh4mfUaX uoa5bH4oc/lQ7cuav2Atew3mIXQtV/ezwWv4BMNmLn1mJaKwwlE5XwotyQROqqJX RgMYAyDEIP0AEQEAAf4DAwJ18pRrFg9y5c4leV7z7/HwFYghn4BMvTSWMxtQXjvz D9WXocBPBYBxuSV08WPZjXMOUuFERVS93LQfRxgU3VTY+wRdFr5uLn2CiOJ8jGh0 uS0+hqX8cPv/JTJ1M6KrN0PaXvuczWw/OT7Z5AQ8a052CuK5Z4f9NmLIebTPQKSB N9s9ivXv1yA0reCD3WpxJgXshOTvXFdwVgdwQ/M+fYvxEW2QBbuRJCJAtD7gM6HJ taLe/fsF2hOzUSVNSG4WLFWVriSpS7i958cW+Oqlo+UKWE6mq0USCI+u2AqGAUhl 7ZvTrAYuqVQdH8kf2Ku5yqLWTqIZT1JJl0HUXxC2d8ienBtkjFpWb9P5VDUEhK/N hfLqSkwb+pTEH8D4Oym8UUgyx4LA9MYDKqF8UObnv4M5AGqD5mWThEAgJGOojt2y 7e8SPlj80frmfFzMx4S/axs2cOpXiEaBfxw6lm7j7US5XR4f5N4wHxdKb497Jj3q 5ksjsAVczl4jfM8OAqt2IvB6vBqYwjuDAEZMEZw5rBVElMoIXgMN/DRqY9pJAIWB QW/SnZWv1QbEoYmO7GWFfpw6LY1DV/8ZRjwDwpAGCg18/fyfNAMHHomDS2EMq0fx NYcSkv8ed7OC1VKCUKHFcUl63mbZWdPNYVrYMePFn+kXdlCWkt31pboxSYl4Jm/u a1TlEOZqLr9G1OZyW1YKMAZlY9n6U2oR7+M0NyhvAFtPziiA/ePlqavhQ/9wrERF clsyOwCk3R1zPpFBtlSjHWDr6d8jGqWvAzrn4V22a24edTUeSkmr7ThHkze7b7wX EMajzfyuk1SG+RGtshJSaSBTuXqgvMjOSnBw80E2EK9fOzUTSZW9xqyY1P7OSkT7 O/utK5c5dSj/uWKKfyJbxmi2LnzCIOHWGVkNUtlSiQEfBBgBAgAJBQJT0CdPAhsM AAoJEDdHOzdYxE82gDIH/iJ2DqOtLpJVTdpOgfjRXxHQ6gsgMsBqBnsE+NYALjnt AB1wvWhdbz4tS9z6XLsWN5Bestm5Iwy4vYZlCK6rEs/YaIirxiFkzxv+UVHRxdH7 WYC4V9MIrbjct1l/UIFa+QNj6qgql7590cuEhrDm/hGX+Rhucqda8MyQZKkqDuRd 6CPUrDkEUut7IuWQWex8aTvGJpDgJZzRrlE7cE7b06U8JsXZH6pkGvml3VZlUCXd NEHzJ0iSV4Dv1uymsDwG8RHXk6laCYoicfYdEIouwqt+Fzpmb9jcwvSp6mPNvNFL mziDTCIYX1a8MsMVQnr9kfv6mATPTaEEK3oVkmKWiM0= =YA55 -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/rsa.1.pub.asc000066400000000000000000001371671403641706600205140ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org 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 ZSAtIHNSR0IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJl bmNlIFZpZXdpbmcgQ29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAA LFJlZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4AEM8UAAPtzAAE EwsAA1yeAAAAAVhZWiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAAAA AAAAAAAAAAAAAAAAAo8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAK AA8AFAAZAB4AIwAoAC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACB AIYAiwCQAJUAmgCfAKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7 AQEBBwENARMBGQEfASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGa AaEBqQGxAbkBwQHJAdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJn AnECegKEAo4CmAKiAqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNm A3IDfgOKA5YDogOuA7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASa BKgEtgTEBNME4QTwBP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYG BhYGJwY3BkgGWQZqBnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQes B78H0gflB/gICwgfCDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmP CaQJugnPCeUJ+woRCicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuw C8gL4Qv5DBIMKgxDDFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N+A4T Di4OSQ5kDn8Omw62DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBhEH4QmxC5 ENcQ9RETETERTxFtEYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOk E8UT5RQGFCcUSRRqFIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbW FvoXHRdBF2UXiReuF9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpR GncanhrFGuwbFBs7G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4W HkAeah6UHr4e6R8THz4faR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yIn IlUigiKvIt0jCiM4I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaH Jrcm6CcYJ0kneierJ9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2 K2krnSvRLAUsOSxuLKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1 MGwwpDDbMRIxSjGCMbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWH NcI1/TY3NnI2rjbpNyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zst O2s7qjvoPCc8ZTykPOM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50Ep QWpBrEHuQjBCckK1QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7 R8BIBUhLSJFI10kdSWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4l Tm5Ot08AT0lPk0/dUCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21Uo VXVVwlYPVlxWqVb3V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyG XNZdJ114XcleGl5sXr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RA ZJRk6WU9ZZJl52Y9ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xX bK9tCG1gbbluEm5rbsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTM dSh1hXXhdj52m3b4d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2h fgF+Yn7CfyN/hH/lgEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobX hzuHn4gEiGmIzokziZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBu kNaRP5GokhGSepLjk02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/Jpo mtWbQpuvnByciZz3nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTH pTilqaYapoum/adup+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq+L sACwdbDqsWCx1rJLssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1 uy67p7whvJu9Fb2Pvgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZG xsPHQce/yD3IvMk6ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/ 0sHTRNPG1EnUy9VO1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i 3ynfr+A24L3hROHM4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw 6/vshu0R7ZzuKO6070DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio +Tj5x/pX+uf7d/wH/Jj9Kf26/kv+3P9t////4QCARXhpZgAATU0AKgAAAAgABQES AAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdp AAQAAAABAAAAWgAAAAAAAABIAAAAAQAAAEgAAAABAAKgAgAEAAAAAQAAAPSgAwAE AAAAAQAAAOUAAAAA/9sAQwACAQECAQECAgECAgICAgMFAwMDAwMGBAQDBQcGBwcH BgYGBwgLCQcICggGBgkNCQoLCwwMDAcJDQ4NDA4LDAwL/9sAQwECAgIDAgMFAwMF CwgGCAsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL CwsLCwsL/8AAEQgA5QD0AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAAB AgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQci cRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElK U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeo qaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5 +v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQH BQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDTh JfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5 eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT 1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A/fyiiigArzD9 k79rzwX+2l8OtT8UfA26vbnTdH17UPDl2Lu2NvNDeWU5hmUoecEgMp7q6kgHIHp9 fil/wSU+MH7Xek/C34zXX7CPwm+E3jDwX4j+MvinUrfU/EfiebT57eV7pQ6G3RPn jGxMMrAnLDHFAH6Qj/gq78C9J/ZQtfjZ8RvGdv4N+Hd/rd54etdQ1uJoZLq8tr2e zkSKFN7vmS0nYbQTsQuQoBx6j8Kv2o/hn8dfDtnq/wAFPiH4I8X6VqN4+nWt5o2u Wt9Bc3SIXeBHikYNKqAsUB3BRkjFfhh/wSWstI+P3xm/Y7+G37X+laTqXhfS9K+K DW+halEs+m3/AIjk1i5F1aTQygrO8djcM4VxwsoIGSc53xj8G6B+y5/wXG8Wa5+z FpWkeFPhN8Nfjf8ADGx1XT9Htks9I0mfUdIvbO7aGKILFFjzWEoUD52OfSgD+gLx 18RfD/wv0RdT+Jeu6N4d0154rVbvU72O0gaaVgkcYkkYLvdiFVc5YkAZNcP+17+2 D4K/Yh+EJ8afHOfVl02W+g0uztdK02bUb/UryckRW9vbwqzySNtY44GFJJGK/Lz/ AILGf8FGvhv/AMFEv2ZNO8G/AmbVbr/hE/2l/Dnw81iK4iRF1iRXuHMloY5GMkDt BIEc7WJhJ2gEE/smyB8bwDg5GR0NAH53WH/Bx74J8ReJtc0rwH+zV+2Z4luPDFyt prB0z4YGY6TK0YlVLlDdCSFjGyuFdQSrA4wa+zf2Zf2ofDH7V3wt0fxT8O/7T08a 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 =dHD6 -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/rsa.1.sec.asc000066400000000000000000000127111403641706600204630ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org 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 mATPTaEEK3oVkmKWiM0= =k2ek -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/targette.pub.rsa.asc000066400000000000000000000011671403641706600221610ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org mI0EVBtK3gEEALmYCx/zHezwF2L5iy139sq19IHfqLXHpINFvVUAB4goJt+8H54u 5c8/iYLak4TenXWsdmGUPptBHjjnY8yk1W1fpFcdljO7mKRBtvk/XGy0OLsiLMb8 6vfWJtMzZGw7Z0BLbo+DPQ2W7YvhPFk6jHPvxUcJL7mpuRAExqS3MzyTABEBAAG0 EFRhcmdldHRlIFInRXNzYXmItwQTAQoAIQUCVBtK3gIbAwULCQgHAwUVCgkICwUW AgMBAAIeAQIXgAAKCRAOeeRxaa7DeqxpBACXW/Wud9r7PbXsQZOqqJ3LMAVBXVBe HnElZG895zJuhIeP51HiZskoamFDEPkBgoX646lxiDNb/xKO/B4aSUm6oyXew7NM nuF/Wzlskup5qd1BrMt58wuilYvAlZ1kOK8MiFFLgrsyVzdczSlNWp0tkPBblcCk cw+fCZlxdrIDBA== =33tL -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/keys/targette.sec.rsa.asc000066400000000000000000000020701403641706600221370ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org lQHYBFQbSt4BBAC5mAsf8x3s8Bdi+Ystd/bKtfSB36i1x6SDRb1VAAeIKCbfvB+e LuXPP4mC2pOE3p11rHZhlD6bQR4452PMpNVtX6RXHZYzu5ikQbb5P1xstDi7IizG /Or31ibTM2RsO2dAS26Pgz0Nlu2L4TxZOoxz78VHCS+5qbkQBMaktzM8kwARAQAB AAP8CQZcSLMpNV81KH7x/Q7kVVYAVTdHChRyoc0/gWV9QWpJR1tZYtKj2QnUMyTB RDsRUIXZ1Pqcd5zQKbMSOQMIqTH6mtSwoe9WhvTkyHN0XBu1uoPlwBnGtWFYmGuH 35GLHr3WSgYf3fcUSxj3YMZeF8pcE6qshjffHb31M/ANzCECANctIW3bxj65eXrG +A5WTxeuB7xQIBBlEaWKIpNlS96bctIuB4cEMDP2TH+EFVGZmvhQetIEn8P56BAJ DICuz4cCANzOIWh7+P0iC/oYG4VIQDd0NphhLHKEZ/+ontm4AOWlW+zMaIIywKTu KuZRWVgUF2dsgpiPDT4MX2mCpAv2tZUCAMIZnulerH0GWifwiyNXmWzSn7RarJi4 SYNPPMfoc/C85kAXkL4vvh93a54dS6xnIk5A5mPmv32SDu9Ih711oeuZd7QQVGFy Z2V0dGUgUidFc3NheYi3BBMBCgAhBQJUG0reAhsDBQsJCAcDBRUKCQgLBRYCAwEA Ah4BAheAAAoJEA555HFprsN6rGkEAJdb9a532vs9texBk6qoncswBUFdUF4ecSVk bz3nMm6Eh4/nUeJmyShqYUMQ+QGChfrjqXGIM1v/Eo78HhpJSbqjJd7Ds0ye4X9b OWyS6nmp3UGsy3nzC6KVi8CVnWQ4rwyIUUuCuzJXN1zNKU1anS2Q8FuVwKRzD58J mXF2sgME =upCF -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/message.enc.twofish.asc000066400000000000000000000003541403641706600216650ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) jA0ECgMCrAH9v6zDvVPW0lIBRim/xC8DE8xxeo9PCpRqxo6YUBWpgPxhXrv0En2C TlAMhKQA3crDpF0Qy00zUsIT6siM79QNS0I39lXkgq462i3n+0grCXDyeQEFfAqs u1mv =M7gX -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/000077500000000000000000000000001403641706600171305ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/messages/cleartext.dashesc.signed.asc000066400000000000000000000017451403641706600245030ustar00rootroot00000000000000-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1,SHA256 The following items are stored, literally: - - This one - - Also this one - - And finally, this one! -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) iJwEAQECAAYFAlQaCloACgkQBM3VPIdAqKYn8wP/Vfb4XwlBOIlARs8k+bPI06Qw nxVUXYqXREG9iWEDblS3BbO8en8TFphHxIFcrbJfzvtpEGS1ABLzq4UQQB04DaHZ EkpEst/zvwE92+h/bi8Bx3s5+qi0xnsIia44KoLLbnvs3ufR2jVM2NuCf5secoJg 9zweMrNq3ldwLEeO51CJARwEAQECAAYFAlQaCloACgkQKoNNjlkY6IYn8wf/cYT9 2jBzugUeFGnUEohmHmnn1KtBy1rdIySyiGWRyNxNVONJ8iDS1dNCKm1IbNPMATHG 4+X1dpYCa2qnP5vAF98l5cSheA+FcYNSKdaZ89LLLCRryBhzkMAk6ZUlFJanPMCY C/bD0t9r/p3mNs/tb0RV6ybXAMq4i8HgW3hfBkUNrZnGieKjZQFoSAhNeIpxFDrN e7RUoUJIHJtMqbYTpvPVBvL0RBtvfcAQZxLyarZbQEMuZT99dBRQ+0T+CKIEuvjX WJ3UY6GSmPjrq0PhWyOZBH6q0PuR6bB4PLN2GDWgJxCk3Cb3T86LuMEh2398pyaa owROXIMs+gxdyYn4B4heBAERCAAGBQJUGgpaAAoJEKXc3JZkUxQOfy8A/jgx7Ixu junmp7Mj0uMKx8XZrj38yKDwzEW8Hi1LFTZcAQCf20W3twzqq+D2wcm52/fgQ05U OrZud1Mlkg+OCSXqag== =0dL1 -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/messages/cleartext.empty.signed.asc000066400000000000000000000014111403641706600242150ustar00rootroot00000000000000-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) iQFBBAEBCAArFiEEfMRsO+Bfn5yRRM6LKoNNjlkY6IYFAllVX28NHHJzYUB0ZXN0 LmtleQAKCRAqg02OWRjohrE6B/0U3g7mXw4OFR/Oyn3eR2k7+9Fi+M+Ht0WR/hit OqcLKC4IvfgLP8EgH2TSHgakgdKK53RiaffTIDrezqNEPV49c3E3Wd+iX2zwFL+N RW33Rdm1iQczEVKZcEbMV3WDzNMFr/Se8PGTV5eCIKrQfeohQr1AcUd7AfrtTCmb Y6I/JCF9YclQzotkcxF4eMl76k6pvCUWWAtfuhdh64pr8zNVN5ivL5mzhyKiXFF+ +YMuMi76Bg73xo+gqZOcO2zDX9h09ru1yYjDxQhmwsaZBfw+Y2HXobhfkIu87+NX l0LIlbMiSD4i/7fPdDhBIJcFPFLpgPgtE0IwqX5V+WFscfY+iIMEAREIACsWIQQI TAuS3fjDNQMhy6ml3NyWZFMUDgUCWVVfbw0cZHNhQHRlc3Qua2V5AAoJEKXc3JZk UxQO0WIA/30yBYoLCmoAZvVRu/LRzlGzHdymJ9JOGNVcnVdwhMjvAP4qxc6M681N UH1kVdgbV9DCp94my1DXFcrj0wo8uc8Dew== =Mmde -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/messages/cleartext.oneline.signed.asc000066400000000000000000000014441403641706600245160ustar00rootroot00000000000000-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256 This is stored, literally\! -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) iIMEAREIACsWIQQITAuS3fjDNQMhy6ml3NyWZFMUDgUCWVKPkA0cZHNhQHRlc3Qu a2V5AAoJEKXc3JZkUxQOOqIA/Avgr3yo3KRlte+IC1UD4ahVrqYdM0X5VphVxx90 SY0TAQCRidiBvDwYKUkIMO8F1jUaydRbhwW5qdJWt+E/ZFKPvIkBQQQBAQgAKxYh BHzEbDvgX5+ckUTOiyqDTY5ZGOiGBQJZUo+QDRxyc2FAdGVzdC5rZXkACgkQKoNN jlkY6IbDAQgAhN+TinzdBeimyy8Mr6LoTulwHhjvZK+hhNGi/qjZuOcoj0PeA6zX 60Md929RN+9Wo3EIAtpqRjVkrTZw3ZtcTTnYUeHPD6HtDJJUmFkoQEZO1a8i/7Bb cTnV7Y6vO0atUERApCfzceTRuQdb9N154rPXmBYZGnLqVAqgPaRAzTbyO/CdfwTb 0UTy8zLCEX7a6v6RCgA5LuwXHwGjcjPCYcsLR8BktfcByCDvpLb/wxwEMmjBPXZf tZEnR5I2vZr+Hi11OkGbwE9yeNnvC27dTk26omyVYs+7Jh91xCCDWrwp19lmX2ZC 8PJAQRXWP2q57SaZ8LN24pD3rRZoFMPdFw== =jkrt -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/messages/cleartext.signed.asc000066400000000000000000000016341403641706600230670ustar00rootroot00000000000000-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1,SHA256 This is stored, literally\! -----BEGIN PGP SIGNATURE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) iJwEAQECAAYFAlQaCpEACgkQBM3VPIdAqKYrhwQAyQhwiqrR6oZ5fTBm4JyCOEND 72Kxbaz1i9Qh0jv7DmgRjb4udh95UQ8U0qVnmnhA8E2deKeDcWTS4fzUkU6J9OdH /GPHpL9QEtOJ7xifzJsnKaNJVynmNMtYOqHQ9gCmXx7jM2ngxbTKBT8YZlSLMUdO uoUFKrJGv0LWlSWHkeOJARwEAQECAAYFAlQaCpEACgkQKoNNjlkY6IYrhwf/ZnMN yKIVxGl+5/9oovvgz2MtGt9B09xRg4BqD+lUDshzQUvQIjBXZ7ZEGSWqerRymZDg ZzHpb1lv9oAOVU8f1qsMQJJkiz7Q+xu5FfgAp0WzMHJNy4QOmB4Kw/7UbTwdUXzw EzKwbJ8Eg97vJgYdfqUZLu949dwJvyYZzGDdkbrnsaZ8H29XkKXNMlMinDQjvFBR djgkILl3ZIdC3p+KechV3uYsqwje2qNEo69KukihPhzCe9o6/Yub5gdC+DSQDGl4 uPjk0zXjds4G5J5Jd5g4o7vhDWs8InxX4AcLfD6lH1XQ1VCZBpucun5CVsU3dUAv yvO7C7FubDu1GUxdbYheBAERCAAGBQJUGgqRAAoJEKXc3JZkUxQOZ+IA/3KI8Mnl k3jfpRQcvtSYFlU9WZk9SqZX6xirnV7Hloq6AP9ZlivPrJdWmjRyyShkMNgP/c63 cjMX82ahGPUVlyMP4A== =bcSu -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/messages/message.ecdh.cv25519.asc000066400000000000000000000005061403641706600231640ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- hF4Dr8N3ST2OiX0SAQdAjBvn1lUIHo/MoXG0iizRRIs3zmU+q/H2nk8iU+ksgXgw YxiH/gRKL/QH0ozo4mKQBy9bzY0jt0V1ldVhP4C5nh3YKLLpasHyhn/Hd+QgmKBS 0mABoKVxFzehABvQa1+QRkiegFGTjouEjRik/MCmfyT+kusqnj1dOgY/sAzFJoEy 7duCJ4YsXRrh1VAa+eJsdm7h9eeXRUvbn7QPA6VLnhYeRsQU8cCscHj+jvklSdzs rR0= =PzYF -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.ecdh.encrypted.aes.asc000066400000000000000000000006101403641706600247060ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG v2.1.0-ecc (GNU/Linux) hH4Dd863o0CJq3MSAgMEHdIYZQx+rV1cjy7qitIOEICFFzp4cjsRX4r+rDdMcQUs h7VZmbP1c9C0s9sgCKwubWfkcYUl2ZOju4gy+s4MYTBb4/j8JjnJ9Bqn6LWutTXJ zwsdP13VIJLnhiNqISdR3/6xWQ0ICRYzwb95nUZ1c1DSVgFpjPgUvi4pgYbTpcDB jzILKWBfBDT/jck169XE8vgtbcqVQYZ7lZpaY9CzEbC+4dXZmV1gm5MafpTyFWgH VnyrZB4gad9Lp9e0RKHHcOOE7s/NeLuu =odUZ -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.literal.nomdc.pass.cast5.asc000066400000000000000000000033251403641706600257640ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: BCPG C# v1.6.1.0 jA0EAwMCjUn4xB3iQ+1gycP5SZFnGPJuc+ziJVLfwYrChXjt+tIt65OO32lmoZfg 7xvLkSnKRbEMr4fsbhBKPz02FS1T3qoDx+uFSdAXyYnwIZ/WLIfVbxmcl9AkgLvE vfrq81rODrwtHJci71EYOKBme0luWkzGdIMHTx8MpvNVLJEBmVqj0f9CeUt/sZDn rMdoyG8xxkKqFn7IhM7Ef9FtQiUJlE5sRFMn50kFT9gwYE6lGum1nze1aDoX1Pol s5JRWJ2uQs8eQ4Aba9f9Jffv13qJDfkxovFyqupkCZFwm4smQkvLJUxEMxzpe5Ev OR071ESiPDfQBfDTT+Eaw4frr0lMhoAAkEEC3Ncju7EhhQeLgQndwxgiiDF+WcVl OuSl6b1XaTMn/X70SH0Lg3QUdBV0CF5lrLkWuN33u3GffaES4sBm25wC/Bbb13Q8 aJunYMJ8KhkyBkXXiNxqh2G1/L1dxe+nz9WIeL30YBjxxwi3/rifoRkbux7HftGV VBThkmB2UJZszutGEXGvpNzhrfogQi4TFIOScdgb33P6uwpx+QATxBxHFv3eSJ6n SYCS5C2b1dShlpXonISqYYXOEwkhmt3vWKEhU8pEWjB76tr7oTbCm3UqMg5QEa/e QMstP2g9ZG8U4mExfiKFzGsCznoJJSJdG/WfkUSkhUOREZc7OGEBrhgRPHELMMzy ebEy3DVXU3DLSMmYTh2xZY909ba+8mYzy1AXqEQfiCTQH2JgfSEdviD5E4QxRuOx q6AhIb1iHXw1JP3ZkO/tbXlTXgBY8AXD5dv6t1mZd+hQ2AzKcAGsK+VOJcXVLhEC dAz8N8ZYHSLc4dVxz1m3G9St81o0qpB51cfFlWYyAxhKiuKbia6cBIzHAvo2ys81 GZs2raUT6+6ehXwy6zVixi5ouO9UHl9HMA5thaOaK0hP8qZFKmRk2nyUYilKbshr 9lAhu+MxygzuBdISW/EWQjbO4GsJ+r7TG7b/b/nwOVPM02MHZOiP5wyko3hro2xa nRTLt/8OgQXW9Dn/58bx7KqNx69oTNuvAU4MVDdzTx2pQymhMpz/KrMuGHlcyv5v /ntTkmTBtfFNu+CNr8Uh3tMqmjlNwMBEY/BI0HagDxikpjO/qETluzG9cLwnBc1C 6ySkkOLisJIdLzrRuMvekHg3795GLhrAI/z8uSPIlvQDi4eLgPzzsckLu9PEsG/d 2p7tk6CCc7HwpBlBj2l5nZcoHUNEesDUJSkG2VpPR+TDdkSIWirEp/1y6QPCoa0d v8M5x0gnEpWaGvBl8x1wBxIHCxO4KcoiWS+90kNNIdpzKjkSBlnmNPrZ/37E9PQd xev7+do6CKiRO3YUzs4kT18mazd19AWGCJbxnXll294fc5xTZSJeH9HYPcvuETBG B/4DV4TKGH10WJgG/ZHqdt+4bqyVts/xvjJI5s+AvwXHTHoFZLDnFzmJdlU8LPic /sZUEBrFPS49x5f7ccEHt9zBgrvwioB6Db1Y3snGY0hXIl7/jM4hdWOHleKVKC16 GxSWICovLeDvL9j8J6b2NP20sPr32bYwVopdRdhWEeUUkHYIlAR3GuZZtLMQcXeK pMf+D8ohmWrk1jLcpnYakO1L77fJZuhG5hwF =NG/d -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.nomdc.pass000066400000000000000000000022351403641706600225450ustar00rootroot00000000000000Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris pretium libero id orci interdum pretium. Cras at arcu in leo facilisis tincidunt ac sed lorem. Quisque quis varius quam. Integer gravida quam non cursus suscipit. Vivamus placerat convallis leo, nec lobortis ipsum. Sed fermentum ipsum sed tellus consequat elementum. Fusce id congue orci, at molestie ex. Phasellus vel sagittis mauris. Ut in vehicula ipsum. Nullam facilisis molestie diam, in fermentum justo interdum id. Donec vestibulum tristique sapien nec rhoncus. Suspendisse venenatis consectetur mollis. Phasellus fringilla tortor non ligula malesuada, in vehicula mauris efficitur. Duis pulvinar eleifend est nec fringilla. Nunc elit nulla, sodales quis ullamcorper sit amet, elementum vitae justo. In pretium leo sit amet risus pharetra, ac tincidunt sem varius. Nunc fermentum id risus sed lobortis. Sed id vulputate arcu. In ac quam sed nulla semper ullamcorper. Donec eleifend quam at dolor dictum, ut efficitur tortor dapibus. Nunc maximus quam non erat aliquet, quis blandit nibh sollicitudin. Fusce aliquam est enim, nec mattis orci scelerisque nec. Nullam venenatis eget elit consectetur sagittis. PGPy-0.5.4/tests/testdata/messages/message.nomdc.pass.asc000066400000000000000000000016611403641706600233140ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: BCPG C# v1.6.1.0 jA0EAwMCCv41ziKqTRVgycGm1XyJLTiWq5AbQLN0xA8/yH/gPf/2D+L+e2yzGq7Q 1sut8FKqX2LBga8mu4gHvvotu4dvewDF5t0jT72zRqc9VsRebWihRkdNr9GU5j5K kxlA59uOPayFHjlkkqgrwR0m1RZc63G+79w/qoAv8K6OIHnpW5AXZR0WS4ZxfDoK p5vXPZ7U9SAEHCSNCbJDMKVWKn0haWE4LZ3k5sOmTR4fGCowPdi4qu1sDCcl9Kzk TTHh/9mshclKvYQKfZPQD4k14PGc/OHWHHj+THhciNUSYDy4D62cXeSbSziwD+Ga fWMhggFMRkc1kp8c6C9z7aFG7Ii6SVGBJIfY7MWvfFqte9TdDtiyKEF+3CH0jUEG m1en0tImUFVW+qRzP4T0eUtrw5svxlx/NprgT6ruOfOBGdb9oS2T0WPm3ZgY+TYN liKI/Co3zDAFF3oE5JjwmuNFLa47/HCsqNLWqzk9bskKBxHYv2g8Mu1lwK8wwBvh 0w85itQFf7N/7ilMSj0ABRaNNQHV+jGWY9NWBnoTfDgz4zYAg70uPL4DVEw1kdVU HbCRmdSop3D0YHLFuCyUBMLkKg3dq0cXhCszUhkAOYb1Xu6sMGJzJw6xi2kzJliK ZwnKJVKjE6B8NajPdtWOkganHy5jtPWgg8Et5oysW/QwviRuXh1VGwLUmX2puZ3F 2DwtEB1mJNRKS7F35sfdGfj1fOpVOMsEngiaYoZnUkBplxpb/In+Tz8QW0ocrZbh VhA26h4uWKAHiAmd4Qlk4xUFls1Hs/p8WHr0njEuB+GjUVmlEMAw6yg160+OiWZt VjUDkzDEAPA= =M8wJ -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.rsa.cast5.asc000066400000000000000000000011551403641706600230500ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org hQEMA+7gl6AXuXnKAQgAnRCazRyghxG0gMtpuCQlhljYzFCMja9Xqtd5EIF7nE2n RHXd5ctd/7M2tfOB5WYZ8+ULpowkBcAR6P5gGpeBGbvsW7HqzAVe028AS8ZFBJBw dq3f+S2XIVzGDOLOzr+BoVGN+k/+EAPE9N1ZGFaR48aY8YEdcYOtIcrpHvDeXtJ8 7cSJsQiphQoaGsFuifJ8CVMke4ika5F0Aksa7xY6YyNKUCtsrYTmZ+Rry/oFOHIE cdU+/zjrs4c3JwgMyjuXcg+NqHOz0zk3uHAdEF0JNAfYVUmJbxoBziUgxLJkyrVq KbXAl4ASdkmBV63TN6fqtmsujmOt623LX1BPcJ43j9JQARmIRP1IyziiK0zE1siD gT49DC+s4XTwFDJWoUdZIdpQYYjuV1in7XZYttS2QL/MlvwvykXd1p4Q0eb0umK+ gChyoSN7Rw2k5iWVBdmhNas= =hja9 -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.rsa.cast5.no-mdc.asc000066400000000000000000000010261403641706600242210ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG v2 hQEMA+7gl6AXuXnKAQgA0erpM6LUcAWTc/wC9MLy3MnyGQMVBXl4CNM5Lzm3ON+Y llBiqhoYMrPFH0iX5C5hnNlF1sgxyDhHefOaGz6EUIpHYHvfLwSQg/z78cHnA3RR 7D7C+tmJaGuBqs9B1VGNq++NrHRs8TKQF5PwAKaLotonJd+YbwgopHQxyO7uO65K Q/LEcmHZpIWfvZXjx8bkbT2+947F2yPw7FrhYQpODDd83aArC/SOiuaRWTk+Nh8d xsFxy6VQsi6Ro9iSwVNV8YCff9HJJSeOkM2Wq5lD2U8QdiDET4P5OEREwxu8K2Pu 6iqSCM+eXHj0PBgMVnc5+diEa86iOau17bgxibPwOck/V7hRa/icZmOSjiW9Xmf8 o/MLD4uUsUalXZBMwnLHbFD51I4BmVtgcqE3Ax4ixmjkVSJYR6TS0Q9WAQF6S0E6 =HhJw -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.rsa.dsa.3des.asc000066400000000000000000000024601403641706600234350ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org hQEMA+7gl6AXuXnKAQf/TU+HZFXQhTbqM2l7ffNbiqZ5mjTO70yU/hAqbQT38DFB 6NHtTLRLnagHi8G3spRbbaj0tFlJ10NgJe20L+CNEkDHUWT1gymdAe1lL1Mx2RM+ eZDUlEu0+vvt4VCk50qAFnT6QdNVTjL4NslOKybKXfLCqK52X0sGraofPkGB85VG 5Ms/X233xNoT/MqQy3q/CzsLcDq2mqxWUrPyDc6RdJCqrsBjAxYbNCri9XGjt2Zu 55GSW8i6C46FFnj0RiLtqOilmmMvQ+sG4yo6aaAOobR1tbEwsEIfQv2O/ND4iQS0 ZhQIhowDX17Vn2FOyqHEHqOCr82896pWQXRHiW+UXYUCDgMf1tXU2gFwxBAH/2/Z QQmf4KZIHtRNvuhWm8/88NvSnP2kvRhzt03U7Fm1EEgyExzxLD7PYqs/j6aXS9yj 3cKz9pBFUn1EMsnTmvw2RrSovQvHui8JWu1QJkfIZO1G6/G0wM/npDvLarW6I/kR JKwZfnNZdk1Xm+Y3CaT2vNmZjGLaO874uVIdwmEUtTWKzlI6HPQ+0EEhI7CjsHd1 qUKohRYW2hyrCy5UtjM/3izjmW4MlXUDWkB78M7GCxZdIZ8v85AGKJ1eFSoMzOCr ILEL30pNix7yYCiSKo9+RWIBEdfbu3fC5RGsOcLFEHp18PVuhVrMQs2TNyMa6bJ1 GX2utZrIivyvXJg73zYH/RSkjhEnYqnMcDuOB2h6wsfgA6F3C7cVngUVpJVpIBr8 98SjdK47MtatpfLbNlxlbS0jWv71vyKgYCwuIvJuL1Z2SmavTBRZUZB/M31r306v oWv3nuig04cA1ES/slnmzsZUGLI0PLlKqSm8gDwECedB9WJwCMlqoSUU2sDhXS4R uJZR5ra75dgudcQG8TcOPBsVOxnfTSyoo3OPw+uu5dJuZCicnxp/Qjp2BUoZ7XK3 IENe1TEzVPOqE9ILM46UV9Xx0dJt+VYkwub4dlYNTI76MV7cpGQ9H/KNzdbXG3OA dF4PgTxVz5BltkZsn/hw+R1xissbfQvimzmOH/0HiuXSSQFmnzrJ5ZCOYK171vvj aW0wXzSQBM4uWVlXH0xnK862ie9n+eVmYauS3PvQazJDqmuOx0KWC668cqRzcux9 Rn2HFF6QCgG8VeM= =zoHZ -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.rsa.dsa.cam128.asc000066400000000000000000000024741403641706600235770ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org hQEMA+7gl6AXuXnKAQf9FtuLQfeNZ5aFjfsJp7kckr5wAcSq3fRHyuXWvJ4QWapx kLwXLk2yO65HjBu3JcSmacewr2iBPDHUbkA27PreZ1lnKbKoXpbqzyQAWEmfBoCS eKa/2fyS8DZxii5vgCyokzZu+RV/L6OjTU0uSBQKn2cRLMeyBcbFQeD4HTTHY4kI xnzateXTp0vNxdJJWenBpIu1dJPHInTWgCUUmjovc4gD0X8rTCpwrDSA9cZAArTJ FhcDhZZ2iWWciSaBPeoIF25plxxXO6BFvhhOUSaAyOYFuOWljls91Ca/cS9BTE7u S9Jk/jreTDErEx/ofbjWmQ/5utUq2Rwjyq3owJNmmIUCDgMf1tXU2gFwxBAH/i3M sHJQnFUO0hsQ3xP+3RRcTD9/bjL/7OGqUIbZu0A87s0U9+fAILzVMAKhTJFts3r+ NGoKingiTdeHmjNMffbEO4w2z37ttVXL+ulY8AtoL0QgOmYygfKKvimWuigISmbw /va6zioTJtMo33FE6RUeLZd8ppHgiPIBC3uGJdOIyJMZqAFyLvpmabHYAxEdilH7 5w037E1+TZPY9gqWzbTVQq/9ZE3o7gI24mrK5EONmIPtglsaFwer2odcA9p2AfLu BNRiclADIsDR731KVbhVZLC4HP8/SCBZRmoWlv2HoXYX0Wzyz7oBKi9XSh7XjHCz u21seWkQCHAP1e8SBFQH/jYUnJAEFzVb+Mn0y9ZM5EWVJpz40Lg31fex2iun5Mee GJHCsMcCjEyqqXdqZ0IAK7zEVzWBF64GkU9ScIoysd/3el4nvqr43Ab3spEHmHV2 nvPhKPBnye3zZR3e0Qnq7lKm9Q8nfHciPVjXe4l6i13pW9ZjB2S7j9CXxXQwH9Ew 3KKTlgUtXnEjXC80bpskfw45q/q+kgLuLMrljaEhcO+1U2+6qO1i2IR9sFVQ/l/O 8JxUNct1j40tsoigtTfJg/btk54xqoqzPA8MsJa82xLqv0ZxHu0aVsvJe4mA2F8s gm7AQahn+B64NQgboNj76KsZzVSVS4SWEivgWf6PzivSUQEmbP2E7pOlROutc5wg FXaSQN+BNEDsZXhqT8AOhGdDaI2SY0bwQ6BPuds2OGfimWuHwvZMjyGPo701dZVN DFu3aui26/3O+Gbsp79u/OIMGg== =x0TZ -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.rsa.dsa.pass.aes000066400000000000000000000000351403641706600235430ustar00rootroot00000000000000This is stored, literally\! PGPy-0.5.4/tests/testdata/messages/message.rsa.dsa.pass.aes.asc000066400000000000000000000025741403641706600243220ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org Passphrase: QwertyUiop hQEMA+7gl6AXuXnKAQf/WZZhWu3OPWT1AS8+pAiT06spP1BSH8yv2ZM8MmXqJYaw zHetqgvgZtIWIcJ95nHKdSXABu6bjuxA6QhcSuM88+MQ95tnNH9RBbIBI7VbwcKd 8ozXEaRu3XUYgrKFFMf+jFW4a8Hlro4NqwGuVWdcvHZBBAhqPcrUImn5lXoS6OZt lT5Iklhg76BWA9woBFBQKlyG3dVIL6LeJwa/44QU1ig2+t5VSY8mOUUo4Pjis0xX NbTg26i5Bc2ISYLzgyfdO5qb9Y4CcUwnt1z/3VMh3X1g7JKRlualpwaQHCJKeug9 LDMJI5N+WpPH4/36k+gYFYuogUJT9YO1kQfAmdrLgYUCDgMf1tXU2gFwxBAH/0R/ mhw0zxZ9jAATfHMtt5OYzkVYiADsSYq95pFsbYaRsVe0Y+k//QRAU7e/xQ18zO5C 93CqZVHMts9NHEQ8o5Lka4fmBfg9Bb3zebRu16/xFmhA5koPWw7vtS15ZkIrMtt9 CRwu64+I0Okmigh8a4drHmP24sjUE8138OnBlCvR52nEt79CI3tPUF9qNNzkb2cy hENYGEyT0y2qbQHVYmb662hPgsO5uS2itIvaoTQOtNjaWBJI16y4Sn7d5EY575Uj 1Y1Pet8PcXKXTTDibPcIZh2XMv0wsOp/Sm5U8/mBmmsU4MEGfMC10B+L9kiiNzUE mDYtPBxapsh2AM55nKcH/jCrFsMkmxS7CrW1/gjUc1EMFQTjFbMG4CdaNXJNkhK7 VC/FzD6Ouq07wWQyPehTu81nbeH0Ave7GfRMUNV0R74RsTCROhDOa5EYB6C2Ye95 qeyR/NgWnepdFFFCS+EIMKioGg9b1K2stvo0ohUmSxbko/Cx9ktkaNY+/oGjCT9A Jdhe8eqfSWQsP2RKZ4MDfunnfkCkvibPajQgAly7XVMT0lzuwajUAptr1pXtKtBH YFYkx84xRbERoo5Wi8HGeEDPJfHT+n4yfMPtLeChenwELtVaRFkkiGxcSS4oXIHp Aw01J1sD2zEJUZlFEYyqkt9w/Y7AWnD7fF00CHcXIyyMHgQDAwJguS3qlrLD9s5W C3+yE8u8Xud3pVdkorpFnNJRAf+04nc5Uf8zdZrtW2uH0AT/oJGINP8bLcNLFhUj nQx4PiAyTe0VrSMZezf8uluNufb/Zsoz0w3b9XxTjC2gfFUCUzKDdfBQwxkPz8Tj gJEW =m76V -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.signed.asc000066400000000000000000000016361403641706600225220ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) owGbwMvMwCG49M6daSnBInwME4BcJkatZt++SIkXbVAuy9mrNu0OK5YxrlFLYs7J LAmR4loakpFZrABExSX5RakpOgpA4dSixJycyhhFLq6OOSwMjEwMbKxMIKUMXJwC MCMq3zD/FWB6MsO1LXv+xdx9TD39f6PdEt4LR548rBOU5nCudcnsK/Vb2W+HTjm8 12zC62vR6+78U/98/GqdYfTtAI00+cWiKcvt9Cy0Tp09W+JjdNr5yFep2QpVs595 ritmrWmouXD/0wkt32OznynIbTutZ1rR+nNFvJnRlfa55sz+X0/wCfVZsK+36WSU QXcezMOVb9h/MbsLpgkdDJsyIy7Lfc6khLzE/gOKkg+uaqnOX3X/a+KBle6ejrve 2O5P0hP/JZ3Qznf4gM0XRoWpn3IMM5SrbaaUqPXzHG0w6f1RbV6V4rhbpkaNq9l/ 9Y2zxx0uvl6pPHP5kaLtp1W03R/5Xpq9ZtFzmbavtuFCVZM+9b15Ps3s864nX6Yd c5nweIq5RtiXthUnVvTUTRGNOhR59sfdc43+n558SPh0ovjqzCbu/uW3p6nsfrvg 7sl7tWfWVei9bedkTjKeIyaQfkH5m4rUv4Xvdn8o3b8wXqzK52Nu+YEeyX9vDBfa 2mbPsuW++qz5avtNTc/8BXPnFJt77A24bRomtEbq+P5Fxh8XymTuiO6IY2EQ5EAO HVjqiElj+Cv7737cUxstLcWKK3PzL0U8kP57ovzR+x0rhdrXfQtUjGVj+CvMq8D5 rdwwXX0i+7mfDI86c+amfQ+O3PTr36/sWSYr52sDAA== =mOtP -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/messages/message.signed.ecdsa.asc000066400000000000000000000004531403641706600235740ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Version: GnuPG v2.1.0-ecc (GNU/Linux) owGbwMvMwCHMvVT3w66lc+cwrlFK4k5N1k3KT6nUK6ko8Zl8MSEkI7NYAYjy81IV cjLzUrk64lgYhDkY2FiZQNIMXJwCMO31rxgZ+tW/zesUPxWzdKWrtLGW/LkP5rXL V/Yvnr/EKjBbQuvZSYa/klsum6XFmTze+maVgclT6Rc6hzqqxNy6o6qdTTmLJuvp AQA= =GDv4 -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/need.txt000066400000000000000000000010461403641706600167760ustar00rootroot00000000000000==================== Needed Test Material ==================== Needed Subpacket Examples ------------------------- * Reserved (0x00) * Reserved (0x01) * Reserved (0x08) * Reserved (0x0D) * Reserved (0x0E) * Reserved (0x0F) * Reserved (0x11) * Reserved (0x13) * Signature Target (0x1F) Needed Packet Examples ---------------------- * Signature Packet (Tag 2): - type 0x02 - Standalone signature - type 0x40 - Timestamp signature This one looks to be difficult to obtain as - type 0x50 - Third-Party Confirmation signature PGPy-0.5.4/tests/testdata/nonsense.asc000066400000000000000000000534371403641706600176550ustar00rootroot00000000000000-----BEGIN PGP MESSAGE----- Comment: GPGTools - http://gpgtools.org y+1iAFV7aWIAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYH CAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3 ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaX mJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbH yMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3 +Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYn KCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZX WFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3 uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn 6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYX GBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3 eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaan qKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX 2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+e36+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUW FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVG R0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2 d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW 19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUG BwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2 Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWW l5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXG x8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX2 9/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUm JygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2 t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm 5+jp6uvs7e7v8PHy8/T19vf4+Qb6+/z9/v8= =EADd -----END PGP MESSAGE----- PGPy-0.5.4/tests/testdata/nonsense.txt000066400000000000000000000400001403641706600177040ustar00rootroot00000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~PGPy-0.5.4/tests/testdata/packets/000077500000000000000000000000001403641706600167535ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/packets/01.v3.pkeskp000066400000000000000000000004171403641706600207430ustar00rootroot00000000000000 yzGO9/ bB|![+=yzTq}F ͢Vnwj'l?}6||#;ՀinS7_BzҺ$hܭ򸲌3su\j|Ti=z<0srhHNhZ˾\Q0Sz/3x3 ߕi~o|Э퀺 ĿeU5W<f8̀Mz\ii7m;"bV`f돌z3Eբ.GZ_I(2qy_cJM!PGPy-0.5.4/tests/testdata/packets/02.v4.0x10.rsa.signature000066400000000000000000000006371403641706600227300ustar00rootroot00000000000000P[ Z ,7Xa?:z\djPZ"EqM!~᭡viTOS4rKSf( 4/ ,i τ ]M;n+L,r+/0IS :2ǼpUg5~t Z uSHJe<~w$qb+[#9aҩhY)Wf^\uG $ү4=^{ ptNԒ!bxnރA~ljє>8(32·9n!gir[dڨo{A+15(mq ٌ #`R}Q\NGfZch;2bPGPy-0.5.4/tests/testdata/packets/02.v4.0x11.signature000066400000000000000000000001101403641706600221270ustar00rootroot00000000000000F@ }4qTs"AiRwbN)"Ve/9I sPGPy-0.5.4/tests/testdata/packets/02.v4.0x12.signature000066400000000000000000000001101403641706600221300ustar00rootroot00000000000000F?̢  !HjrU8(bм{ j^w'ADPGPy-0.5.4/tests/testdata/packets/02.v4.0x13.signature000066400000000000000000000001401403641706600221340ustar00rootroot00000000000000^A6    , &lfVOnZ[[s MM9MPGPy-0.5.4/tests/testdata/packets/02.v4.0x18.signature000066400000000000000000000010421403641706600221430ustar00rootroot00000000000000 J [Fne(S&[:=p),j?L0={?,Ы8D]C zT f_S.GbB,]!=b^guHĤB[dN-z /㲳DOwԤA$;5FӺ~O\~[4Zi54k`,w:S;>eu/١*^Wq+l9ĸ6; )-@{*BWNjx:LG"&,xǀ` 5WJ$@&a0 E4Lxe6slI9Sn8%C>f+zSv5/nY8]?@YIb9jwRɻx}ornt=KEk):~9aqG > 9R0|):DD6Z K~ ]40y%X|Dd)!g m!?V;jg(#4HԲHPGPy-0.5.4/tests/testdata/packets/02.v4.0x19.signature000066400000000000000000000004371403641706600221530ustar00rootroot00000000000000QE VvSE(&L|y_^ԔDL؀U;S\ϩkMI|!ͲM:"V+6dZ{R"8Ž/L#?)]iz =)Gf.,vrln˹Nld^+iP1x*I|;M~1."PݴbL, _XPeT#5 P/wtd( jvl"R\`M|c4֊Mx,eoV5˛y$*%)TIr_PGPy-0.5.4/tests/testdata/packets/02.v4.0x1f.signature000066400000000000000000000001431403641706600222220ustar00rootroot00000000000000a!8 ?|1.9Ű !Ů\{g֍6SZ}x HM/m] 6PGPy-0.5.4/tests/testdata/packets/02.v4.0x20.signature000066400000000000000000000001551403641706600221400ustar00rootroot00000000000000k +A z$Please use my new key: 0x8501C7FC.  {*LAR(31JӼ HUh c]O mW ߗcPGPy-0.5.4/tests/testdata/packets/02.v4.0x28.signature000066400000000000000000000001101403641706600221370ustar00rootroot00000000000000F(H= 8zv~urD{2.+$Rauے`+ rufPGPy-0.5.4/tests/testdata/packets/02.v4.0x30.signature000066400000000000000000000010421403641706600221350ustar00rootroot000000000000000 J [Fnex씲h-h YRIx NAeDŽM.W~@#q_}QwLgBKؐI O h`;lKD,Ya}]koXoo{eB F')y7PK~k6:J@r$Bٓ$æCk!~[PGPy-0.5.4/tests/testdata/packets/04.v3.onepass_sig000066400000000000000000000000171403641706600217570ustar00rootroot00000000000000 *MYPGPy-0.5.4/tests/testdata/packets/05.v4.dsa.privkey000066400000000000000000000006761403641706600217210ustar00rootroot00000000000000S5blEpI"j6fMHQk%ŹpD<Ҏua zUe93j-^j"a(nZ̐ RXU;]w$r1mbO _ @8ӵm < tFo^8)O:oLo|Tz'G6+߬B?cMO 32i|Yŷ!VOfVT #a\'F2aQx; \1iCI"XCu$k~_6[r`Af8renA>_z9W0 lM5,t|{pTO2 P,Ke)H)"2n2tx1] itOG@͑d;o TL#*= PGPy-0.5.4/tests/testdata/packets/05.v4.ecdsa.privkey000066400000000000000000000001721403641706600222200ustar00rootroot00000000000000wMS_&*H= ΫY%ѬB\x@;=5^E) v{UoeHV \h({ZPGPy-0.5.4/tests/testdata/packets/05.v4.enc.3des.privkey000066400000000000000000000010011403641706600225330ustar00rootroot00000000000000S5Xl֋KLatl״EWEer-s=hp"xܼ{_*udSot-e^;k}Ye|^O`{~`DW{NBdž4/O}+/O %Dd+!6&4rvqB^˵%l]Gj^MZKA(Xɜ݀Cy'ۇ8TcB٩%rU*$*+bm6l<* sՐ}w s(/o=z-%I.XNOM6b¤GID|ά3 ~8Zg9T+*WMbsYkh5 s" 3B q(}X&L ^?vGD\V̹b`4wLslcmļ[4H޶aD>PGPy-0.5.4/tests/testdata/packets/05.v4.enc.aes128.privkey000066400000000000000000000010101403641706600227000ustar00rootroot00000000000000S5Ҿ= Bͦ/d҇Ԫ2}>!p]a ZNm `JԹ?rzdM >y0KBW7Y H|lRh;ɬLD􃶁 >g_( (0=##y"6T_]Q 9lDlHkHo+hїOJ$J>n@/JyUjo(Pܤ HOE`ꆍG9(f>tv+v/S9r'VTb|98I-hAI4snt,6Zhr$mɽ;߃8G{;;TTBb}&h|>Aip!h25lW#M\WwP>Bz3 Q^sKªKZM6cGF3pI~=Z 3Ҫ'7NB^|[CÁI-ޠ'b7=ZYMҒLҦQ|_Bzd?\$ރPGPy-0.5.4/tests/testdata/packets/05.v4.enc.aes256.privkey000066400000000000000000000010111403641706600227030ustar00rootroot00000000000000S5R%tNlǃvEF@\Ac:5< Kq܊蕚Lc J!v y>Quޅ-HV\̽DT;ߠOfGFrzWڰ&B:}D I9mu-+\j0[bo (z=`4E~yH7̩/2?Ta!P x=˛1X=d6#sk'䭴_ @×gP׺3ʙ< xc=LMgK~v56 ,]tT=b"ȟij8̓~=X\=Yv`~@lpK[}Q$DQAKߗ92BRԨ, PLP .׻!J2Yb}u m<ҽ7W p[s?#cb#d̈ĩ5@PGPy-0.5.4/tests/testdata/packets/05.v4.enc.blowfish.privkey000066400000000000000000000010011403641706600235120ustar00rootroot00000000000000S5%KLg@SHngB-qV'^W`# [bPL4.Waӈ_d{MN ^I'kfJP_g 6 ~.@бfF\Br_ü&2 IʢKOH@)b:[/#2-pxIj2),M'дp+w䀨h1W%2,v];t~İD|Kh *8 * BsbYEuNF3 Jz.>M M$N9)[n I :3ѣeܨ2fFW&ʼԁL!==Ia0J䘒iy KʘXSM 9@*P[ o&LXk&=b291k.5hPGPy-0.5.4/tests/testdata/packets/05.v4.enc.cast5.privkey000066400000000000000000000010011403641706600227140ustar00rootroot00000000000000S6)^QL-OhtżzGA1\Ms(Ffw \1g]\9򚺋XϼD۶vWҸopFUûxCkN ֹqCv=P…ɠӾTWR;k.>VߋdE\TrOʯgYQC~݅En_ _02;< EU:aS\B J%_qReMinbn~KQ>dC“#tzHf//kT IDnTiMeB@8MO|QHf,ʄuˆTt}m܊8;ԇ 5x3 K@=UFOCIu*^]iv%ys_z9W0 lM5,t|{pTO2 P,Ke)H)"2n2tx1] itOG@͑d;oPGPy-0.5.4/tests/testdata/packets/06.v4.ecdsa.pubkey000066400000000000000000000001251403641706600220250ustar00rootroot00000000000000RMS_&*H= ΫY%ѬB\x@;=5^E) v{PGPy-0.5.4/tests/testdata/packets/06.v4.rsa.pubkey000066400000000000000000000002171403641706600215350ustar00rootroot00000000000000S5Xl֋KLatl״EWEer-s=hp"xܼ{_*udSot-e^;k}Ye|^O`{~`DW{NBdž4/PGPy-0.5.4/tests/testdata/packets/07.v4.cv25519.privsubkey000066400000000000000000000001371403641706600226740ustar00rootroot00000000000000]\&q +U@37Bsz>y}'NrTU0VPN=\[>CW;\{(JS`<*PGPy-0.5.4/tests/testdata/packets/07.v4.ecdh.privsubkey000066400000000000000000000001761403641706600225640ustar00rootroot00000000000000{MS_'*H="! Xؕ ͎cH,B kk,4bfSg|nvO@<(J!&zn{D;PGPy-0.5.4/tests/testdata/packets/07.v4.elgamal.privsubkey000066400000000000000000000004641403641706600232630ustar00rootroot000000000000001S5LGxSz!Ȝ 1[Ø4"Z'5?)oc"˄iQa63|==K,=by ꋿ8]Cb9r4RYQeQ!Hq@!osG+' *W1<h9W'ps;8xW9#N;7kanV`ncAqWAwk>iW#Z$# CT6[o%A\z2ۄZcIϮwdS@"YL?k Z j'|{  8'+(J³Nn0슸| BdJo Hl!>Fc{stv`7`,@-lN8x*WA>-&UAlh(B% eu2PGPy-0.5.4/tests/testdata/packets/10.marker000066400000000000000000000000051403641706600203710ustar00rootroot00000000000000PGPPGPy-0.5.4/tests/testdata/packets/11.literal000066400000000000000000000000501403641706600205450ustar00rootroot00000000000000&blitSThis is stored, literally\! PGPy-0.5.4/tests/testdata/packets/11.partial.literal000066400000000000000000000400121403641706600222020ustar00rootroot00000000000000bU{ib  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~PGPy-0.5.4/tests/testdata/packets/12.trust000066400000000000000000000000041403641706600202720ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/packets/13.abcmarquee.userid000066400000000000000000000001031403641706600225110ustar00rootroot00000000000000Aa'b"cdef (a'b"cdef) def@foo.com>PGPy-0.5.4/tests/testdata/packets/13.name.comment.email.userid000066400000000000000000000000601403641706600240550ustar00rootroot00000000000000.Pachy (no password) PGPy-0.5.4/tests/testdata/packets/13.name.comment.userid000066400000000000000000000000631403641706600227720ustar00rootroot000000000000001Jens Erat (born 1988-01-19 in Stuttgart, Germany)PGPy-0.5.4/tests/testdata/packets/13.name.email.userid000066400000000000000000000000421403641706600224140ustar00rootroot00000000000000 Pachy PGPy-0.5.4/tests/testdata/packets/13.name.userid000066400000000000000000000000231403641706600213250ustar00rootroot00000000000000dunham@debian.orgPGPy-0.5.4/tests/testdata/packets/13.namewithparens.email.userid000066400000000000000000000000641403641706600245250ustar00rootroot000000000000002William A. (Bill) Scherr IV PGPy-0.5.4/tests/testdata/packets/14.v4.ecdh.pubsubkey000066400000000000000000000001311403641706600223570ustar00rootroot00000000000000VMS_'*H="! Xؕ ͎cH,B kk,4bfSg|nvOPGPy-0.5.4/tests/testdata/packets/14.v4.elgamal.pubsubkey000066400000000000000000000004201403641706600230570ustar00rootroot00000000000000 S5LGxSz!Ȝ 1[Ø4"Z'5?)oc"˄iQa63|==K,=by ꋿ8]Cb9r4RYQeQ!Hq@!osG+' *W1<h9WELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmExifMM*JR(iZHHC      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(0k_?| t}{Pػ6Cye9e(y 2H z}~)%>0~zOߌ_o0_2RGy{lL2',1~*'Pv wxzPhdD-'a z¯ڏ_>!#Vxu据ZAst]GF *,PFH~%cߵ^ ojQ,m.Eդ 3q'9~˟\okxS7_ lu]?GK=#IQ/l XXJ}(_/S^xVSV bI.bW9b@5׿b'Ɵ՗M .Jfo+[¬HXぅ$FDfM;fn9X$E$Ws%F2@ba'h&89 ~wXǾ +W[ \tφcщU.P !c+u7e|1W|-SOO6ڛ cO~f|;1RxaRA4O$+ ]~E iyF4[gky?SN?#v|2_`c#w_j~6`8ՑlHCo|GOyx/-ψ|Dįk:(1)ur {Ā6&>/h?G-ĺ-d=\\DMXِd|{sY Oxb_Qo |mh}OU'FB{U(ɟm+~ +tnx 'rD s"m͜,[1>o Azῂ>)4񯆼''tF1H7\F{A RIe]$KmdacHNAgtycp,WK;">*Ee{4|n]x#*q_*=~ПgI??ZoAu xV/oG~7RI O.֍c#nG9~h߱' h$!º\'MmL1*+PNrrmώW|cƵmpD2ngHzt2k~<~7!|׬ ?xkS}gƣ}v!Fq^xW~|t~o_ >|Q5^\]iQ>J]7|C0 !pU@>'VcxW!GIKO\L]$2&ƍXW 25΍$~w t?VVѧnu<-Rst,en?imOR9 !>2M<5DdoZ,,|"z2=/hI>|'gKHFֶVVZ ']& P=De>hڮq2][2NZn&QnmɑGo > CksNaHb2I`)( W 7V^>Ҵ?>,ͦI^M 1R `YI_< ogSq}&{j2gÁl-ī&H_v6Ɖ<>!}yuk+=9|9&-V >mھn/߰|iDjukiyj8-mʯ;Q8r~?G 3<_ xF[n4]\jBCd8(]}7 AԿR u]K^:&qeu%lגel#%c?UcK#p )Q@Q@2;H[HngvTzzS?l?أ_y Ϧê]XEy,JpmF/1*YTo?o~YO~4|'ф$>>a;#:~?_?5;F🈮u-gX]FܭڥԒA#yGq4e8rW73|9MI-3dz^MGAR'gn٤-OXn 3odĺn,qQڅmJTEM2{Y%*md^o"߈׊<]qSR>-2 &ұRE0rߔς?hCĿKh |Ajz} &6$4M l7 Usž&~1Cėz^aO[ijZTAf.??٧\~WȎ%ՋkO4jd$v i+?1(~Wv[-OĚ)DXlLsmů| nmK%_,i.D7Irc?)UeWğE>4y4mxV5/*}#Y;JĈYw ?3+BV?W O }?\->.Q "{~T1E-#teKM[Iä^VeixgֶB1+p G+䟦c)u ;>u}&Siڿ$85)Ź?ޟ|{^xWؼI !oDs|"Ϗ/E9-Súı, $v&#8a?i?_o x᷅o|;,\5QI磴*,Kwj<]`!Mߌ5Zơ;&DrHX!8 ?R'gº^{ /QI.KY7opщvc|]xgzF^iP\^y^WڤHZM;w[nN3wt_?gSNsMcH~,Yꉬ_x?~yH&}E 3;yRE<\oڿ>^ W/~&K {kˁ߹mb*@v.0}cik \|c,:Wo+}DO#e,[4!߆Vq 6gS9g K\</)nv ^&)o?_yu~jve즸0s~ q4?d~9KA;{ k)! k 5?jޫ* Oi\Gekgw:]^hW*$,.,o#}4~o/w^ +k+E>duu"#`0s??>1&OO;D[B-寔[ǸnO~?dK xKÖOlc I$ً3;ı$<kĿ'>?? QMO[S:S[i ]3~ G/Mu Oa'N2|O*|2NO{] I<>7P#xlsyE `9d[׈&|vG^*9+}B(t! -XTrBd&(?n~?k?7M oᧀUos}jVvOdf}O2;3k~6ixv[3%fpFf%Q9OV #_i:r^ӭ/R&K*d;̿#eW#hPˏ#=s Z}(=ֳ߉gch+i4l Mb>/o~>#}OHGឰOhF.r-2 10#B߱_5ݔbo/e]Kb)YnY,L`9 Q7W7 ߬ῃ|Y '9j=桦Or$KC"oܟu cq㫿ڋ_i5km7iѧrP&X(^!N%__x,v']QӬoEZYx'ѨD0pœ]jF[Dbi1BQKd$=hQ@Q@'>D[OWŒxARSޕo+5>Cyr:ny澈?$ h <5ozu7M59!0̥ZB ;A$}E||[$a-g@O߉>'՟%gj%#Ƞ`ʬ?#_EOa &X>x>'go:M%$mi>M~@|ՠgzCg[e{1]13?e߉>W jzMSK{\~m~ #d ~;k}j,{bӤe8=kn=^]A"k]zq|~$~͟=x|?/gLɞ"?Xj*>mi3_ÿ2AF-EVhDծb.]-Щm5~@8R`۟(mL4^h|Kk]IfI4vw++BQ]0XO4 _ ǿ m>#'hϮ%ƕukQAsNo-~~Q@'_Cem_ڇZ.=xrZ6a;I beآ 8!a\g^?G|X> E)4G]eּ1q$6* AB tP'/W~ O#GO^|7EwTԱ{{gUǘeq6ucVɯ)i><|FA)O-=_Ǫh1\ǫ|@4uBGF@eVmz\ʿ4P|=4˯gpF壵oRUq c,ۘ>oX2[v|b/~&4K߄(!I SM[`4ar T+}E~S~N(W 5_ x閷 !5HbTF4 lGhw%#)x~M~Q@ x [m;A?j>Sk^$iaM@Yi,֪#m5Ļ_grF |~7|?O74O>*㺹ҵ=#]k OˌI D$]Hdp>6eoڗ#㌟5Ľ;P,B׶:E/vK_Ǭxᖾfggt4Bϩ2;4Qv >` OF6t~\_+my>s٭3F 0?jC {ڷǾ!j:捦]C}U.A6lkmTțxVAtguƉ{Zw =]"As4rF&N`֟?|=7爼{uhN1Q(ַE<$3=oP^x-kþv{j0\Auw]u(uhUaxe84skG2)|7:/Yj)h6(n.Kv[.RlBW?-[/֟56'ý ¿n<:e!y.-ķ|Fu bHeE6h $`n"_ xwOii>Mʤ2xzMK(o,yjdxpђKojs?/'߈?ĝ yq}cd>%ݦYd.DGJ xKشӤ`gy%xu~zg 5{_Y MwťĶwI"9m/UXa86|.v~ o<[cQZ⻝W ]OgyFZ,.c=_M~Ͷ _XZCxble"( H~Ibj*9F-][_ta!JhB R\+neK<ֿQ~ǿ(|752jmsW8]f_Ƹ F@:֜O7A5lg8SC2*k4Kɷ8 cq;XJ.U):U7)ptJQWUQEQ@Q@Q@Q@Q@Q@-I FIHI2A?!طP7Tqo:߈5OChZ K[̰$QH)ſpb_[G+|NkxG8[إ{kZB8(]áϟ kۯS>/_?;[g>2΃&[\^5evYxu(|Q-_ e_>']$ bo>/xtٵضʖ.PǍ~%+{S&V]lxMŕv46,B#k't.'Y|me ]tzvkq=I#*Pʰ0%l񧎿j|cc>,o|;OM9u˫KH4m"͕iܖbKH5?_wZO ~~+/m;@ռ=g&.As^Y-qnq3q;#'5j :x^_"1_I=HaA*>?_ŏ_.𮁫|9-Z[%~FL<e]$ſÏߴ|6~N=(kѴLJkg[Tk۫Y ƫAt/8 gxo㯁4:hBhU@W^0Ow?'ş xkN< kSO=M<(Ւ_2LKğd>x D׃>xV#i1o$H!c4D#E'I9+'Z7ZxGԠyL9 pJ!طU oѺn𦵫t펟7^el-wB]U sɮ\n8=JI-w73J/Z5#/T_u%xigѿOŵ=x#ƨxC:E$\L)? #zUA~Qk>߱TxNvJ 5v7-qҀ=_*}c(ʵh? s@y=M>+Q?ŝr/#-s_*}c+O o>Z .iO>5LDo ЧyS&xAG^5M7Vkn@pUkF ݴg8_: SWML5ۋ_;Jxv<ϕq@Ł; 7 /G ttx6"Os@k>߱+8 Kčq$Blf_L s|cSLl\\<}`|R:݆A#ֶby-P_I1޲YaNoW= /_Y RQ_<7 /k>>KGm-Ůkk-nn{iQԤ}+O|TGo_|6's#$yEy88"؋qDŽbτ!]B|-iq6%󩹐̻r> g|y@v#?ָzNN[FW>Č}<Ӌ3|]x?u%Xbe'< kx5 qE 2 $(=+_(>'nuv7 ek Ǎ>=_Jv)k^IX  פ|QVGUA~W̷K TH|)(t .g]~z!c,9U*}c+?~kKu;Q=u iInA7տ:_zgïɭ ⱮrP\ 1XL{Dwºqڅ{#l#GHS6Kŏsx|QEG|2}=)\WDP'?c߉78Լ=$^^*;hYcC&c!NеZ7oǡxF'[\,GweU,ǠOY~ clwOoO?fiUF!}1@ʇ A4SOM??Q@E0k?noûWfO;†S7?s_ ;=N}߲&IIU @y?/_7/|A|0Qfok e{E95O ~ /Ӯ ,Sۛ> GWV5?@𾁦~uH,mZ=< 3yi>Ѽ-}In/o4Qx۲>m߈!.tyuoV/-'RIxQxP1k[tQd)(Cp >n6v~te3\$ !39| lO}ZKciyށP_?ko|OHҼUZj3~mI2Ey?? ;eC.:>3|KҼ9ZtaIXJ3<?R_V~ xGFs Y ye8Vf&H!-ԁcapiKG^ͥ/-~ Sr4gfNJ*۷:d擵Wᯈ~-c$H֚sZتyR<{CR(sKdoW|TվŊ,H| <͸&#$c'O_ǿ=#1ky8Wzd `A2B$K j_?t||# xu? { J$<3pTFe]0h㊟⺈lO/%E[ά8_ 5_e4mOQWn.V@_/H접r ߉͢Ykr߈gxt"4٥U|"NJuF^tZŴ˻C5ų` p}y/غ_^o)5åxM%Լh0C~c8~~ 87/g}dͼ6 t!uv5ejoSFo5 8+8'p@hg+:˃64>t[k{S,dDhk)@UC!%]xucź]OOBVq2ڰ I!GÂq@@i×6*K*Xmc}3PI"œiXŠ]0G|c '\?uxNũik<:|sK,taXϖHݙrXz#[[φ Rd0[sL)H,4oxAnTN3e8?e2#Ŧӎ>hm` պ3w ??uO֩p.t-5zSYU##H7H~!jY?P%jii`H?OM??Q@nWGu_lnWGu^OL ~_  ן{T~+0\)EҚgt zw;+ 8H|}jgN]0sc8AmJcx+deT*1W5[mM=6xD$?OtOi W6Sy76E"9k+ 9>Us>߈Ɖzj4쬦FvOF1~?ԭhi{w͍>pnmgm4;QP)xUk3κ>Ţ9o՟n&Yt|CGQ/fܝpo[ȫB'nڝGp~toIϱŏvS^w7P~,~۶L ~ ݁,:Oмl|r kG [>Ģ7? ~̞#x~9Vc?b=:^9?":Qzҩȃ8k&t:?a%kυWSU3ȵ^J L+ߴ Ar?xSC^?m3u}X~!\>vZȶ;d0C QmoqgMZ3MlCج P竅 ic0r4]);WjKG识=ei>O1(""@Wky==xO>O@= {|@i]1W𐻄A*k Ɨ 6J7KF&K;TrۘN_YIPqXU޲3*@sKaѭ|St>#.p5+5+B.guUgyq=I5WȾȣ)wᅫ6!`}?Z996=xL-Qs%-|$ $ypk|6kӨ/p mRr.k˧)t_"J(?44IEzǟ?ClwZd<<:ګYK", {Gݫ~L?~s^O jچu:}}&݋%JJȜ.9%ſ`o_?O-e$| vڕُ $xݷ$ w,4+٣k? V:mH߻l SX0;EE*n_ w|ڽu?lr8h:eZt;֔i~t?uJ*m=7Tix?_5ޯ]>T > "Xm$J,:,p!ҿ u߆Zto |oKWA^Kƹ*b8Sta.۟O?>>ƹt{͢-l/CYhՕ᎙zW'/ěRƽvWvQi:i-m]䬑7T~kt7c|2r&ǟt5ݾ"@-".M$@~Ϳx?~5ė,+4]Qt$]:݌zT16H3kg6ߊ4xGį h!K[؞$K5^[ZE6 F^ڝ̭wfc9=˕+jp?O)_wީE=>H'dP뫗iY>kUr;O؟Gso ?o^jڗ<&E%ƃee,V{8Kk$@Pm_N_8~֟gWNx:IAh}CIJk6wIs^[*7p1^ 5w៍5+CW}m5kt^-.a[֏c OT3࿊Oc>?"~~\S5ˬAr\l0JgVjf_ mjWů~_wJ<,.9<6Kv+ 2&9Pʮ_cs?K|#&uxڭqk }m,u&JOFI|P'"Hou?7x+dre[֏<SrL_'▹DZG?7|Qq6|e?Pkh q&WUQs2ں;m2k?=Ԥ2m#&e朆0zl/g~|5__x_L[Cv[?1Vnn8>3ߌ:xNګtZ'M.OմjX_ \VJ+^P#i"W$aU Qb$9<]Ji~1<* wOׇx%xKK Y5׮@P- WKoe$/->+jt/^ּs[no๼5> dSHlmN8d w4"O͠jO1^cohjvIȞE1^gh7UhFooWMWUeƽi.l8rnVQ4h䣐xiajK>u<_~8 4O~"i$t-;F-mvI39b(;|w}gZzCZ-{"f. `dc5~<X!?_k|-~5>-A?Gޅׇ>ŭtPI*~ 8j'G5~0T$4~YQڊ>:‹|D׼97eޛiW'J4$Q7 ®9>Dm9`x7o㟀<(ӼUǂŚ/kK}"Wmx3~+v FXt5,ΠER1SJKgMÛONft?ˤ[EFm{&{_@^q^Dgſ/iQx\t nCuX̅k`ɹC/:#_ॿK>=xg~&jaUyt˷i.+9LS?*,|~8S<_uo[߂#5~χU巶緷Me$k־<#uk^9g |pԠ~'x^KCDi"e_&+,ݴfx$'?&< g&/>MAVPA*qJUaiq5JO7BiTn>U\6}k/cS<A ($>϶Fmi~n4࡞#|o̿c[uԧҴ{IX}l}H2ܳbk-/Z|ci>?;O(5hol'U 3\ඟt-t^PstK˩%>%BUW7%x/Y/>/smpyV"khkldS-y?d_f[5 J]?Fd+pu.bȬLwyEz?f4(#⿊牼9$E[&2 .YcPk9ğ~]cBmp[u_WxK5O?0xݱ{hzW- c`d*n2c1y)a`ݥscfis7kZ7Z}e5|6a!OZUHέgRRrT˝ʯ,qr_Χ)t_"J(?44IE})~NUtZ⯍!#xR=>HE\>LXk7+P _pRL1~?Ťi-\nfWO*E)EIZJҕiКNMIlӳ_4xg>Ξ>u{ǿ|?:s_9lN1J!xc*9$9XWcGTҾ|6I5w:΋;E0Co(EgpyL=k2|Zu J#R}K}+u|l7Fw۰`j)%_ᔚg 2?iγ)7("t sOW%>i~UG`L bcʵK} 4' z}w|kmq=7-q?nHh[c6zsMex_ ׌5 q&x {;S.XZ(sA}+rshmA Y20?- 6[g8gG >.=>Ɨwj_۷0#FfaT\2OZ_'?wYW-l-oikZ[{q󑴲n#kҾ-,>*_jt__1x᷎fip[2j&ijdUex]~ɺ(O ˜9m+\I$i(UAaˮա#G"CeUg >,m~Ͽ uxVJu6Iۃ rTz$/L?a ~񿊭|%iVMٍ2O,0$|"F73!Yw? XQ俻ynեf0(@r9O:n-S𝭭jj#CuMm"$] .-_yrcY:ּQ}eKÔM  u8{8fvJ+džyk>~^7ĸ|'͗omv?ipɮ9E"Ȗrk>&i6DŽt^|R5-~QOh}!B<ڥ~ G]/ %$ԂYU2O9犥-G_g.+c??HFo{e.>|.u=CxVăk't[1>x>"~n_ɏ¾yn8.|>e^jOVzO?vFLkr y<Ƕ/#sM{00p_bzת9#aV97DQSƦ?NOLI?sR^E_n˘+WƼC'wW}!} w>*ŢH9 f[?jMݜ3\F+**%gPcGE8 JW#!}qf"I$E QU`~#`b+$ˮjrz謿Zm(o ɟ*KFlg^]To\%TQGx=MoLn1i>6?箯ܚҶA~͖x|㟞kХ>K%§aWαOUxG ++oO,ċyQ~u>c4}/HeiEvRѡ(($#s 3͵bU/)+s?;SSOODQjii`Hr ? u f&r ? u |e_P6'˘ăwSF@4謩uGZ%X/ 5VBNtn{0t/?5+Z_"i,.H; 68<@U]']ף;[Էh%YRI)wTQEQEQEQEQEQEQEQEQEQEQEQEڟE$;SSOODP(Q`k8]Wѷ^#i]>:$,bʳƌKd7+P _pSL񇍼3h渚cBfp9@xE/?i)i~4,GYF7:0]X jЎz? x3GrDдKe-o Hp -zz;ۍSzujMlm{5g1Eedq!呿:>x7Z|sxy%,#y㳶$_-^] ( ( ( ( ( ( ( ( ( ( ( (?;SSOODQjii`Hr ? u f-_S?;৅~1|rOoUWV+K77.Xd2<3 e[ƶ?jPo3h|C)Oi2,l;xPUKo+e7aCuiGJ $;N\*$_[zeįc:jir͠jNu}+)E%Z0Wq9'[5#_>.jW4k2i:KkYi|8$U|{GnxWv Hւo{[-MuIK-sfw7}E~a7 9|p?/GO𴺬vNGX鶊q&? sn_=3Ÿ?j^Sjk{=^MV+H9b?Chu~Pg![Zi  fB yוX~ko%Ŀx {مr?Y(k.O-[VSBhpޟ#`G|Ɖ\,bc! cwF,7;JoVt5'inm(NC~Q_vxNJn>;+е ZpQkxU#> ^c871ffa%Iz/+ǥi_-{kcR|{eJfRrH` Zিd|IG(Ӯ*iP]"ũT dF<E~s~Tmi}3o!j[ bC _p'/eឧ_ܛr]j ;[QtvƟ(C]Uk4L:=bDdYf TIsEP >)x/}75޿oeW *rjkĺxoOÝv:4L"6G$䯛׾ .>>h_ t}KNMGˆ$r ¨,OW_H_&~|qGWI-|9j-yn&@7FY:xPc1~οHdW%u31֓DV,[YY5) .Ք3pA6 Y>|Ǻǧ-tW[HKl$$,[nH_4|s4>`6-bI$.]SϻRi$Y."$e ' ?`hlڤ2{HmLjzRl 2H&;>2iJ޺ޡBUnj,]_ڽoy`em$HɧTt Z .iW:?gh> ;o_ m%}5"S:Ewl!1'/:>77kj|,}ݾ\CM"F&rak W?_o?VI0!͂UC35[k3co{m@𮻨" .,嶱}$W=zR?g/g_]Kټ+}SW7}[P;އkpH þ cx’j)߇j(rI$i$+w~?jo|DTW>XN`i |TB1Y~$|G<+jᮙ~? } `8hZ?8VY]T96|o`ඞ-Hg wbE|WY|Os>"AqwZdBcclqO>Ե--nK?[GP`o9bo-rJʜ2+K>I+Y^ö/_ ivI#P (bT_[7i ù<+?|9 V;KI9#$yBOoŞO־,GмCxNq}>qCu2*#pH6s'Tc/k S @~)[Yjj,ºuޠd7ZU&O ªd)rP?o_x?~;Lu S|kmO+˭`ĉpTrrO_J>%g;٣ωt_!LK7J٫j F<b i|ASR&0~9ZYiw<=vVqn7O#e4W-߳'i7_xT^b_aTPhpYJU?lOmu_ѭ/氎/q%YYy4Q쀨ɂBCs_o -G}_wVUDHAlyu dL@# WTO CG}u)<(-j$y/"i:L1$0oتMc߲΅3o>mhw7y-F8spq^&~Ҷ? eKO'uH46"Z-(Q2|xwéࡺo'ƙ/ 뗞&Qae2ܽ/Vb|-?/ zPм^𾹨O}&xn,D%`fY]fkټSs챭b, o:CEoZkshf݄$dDrK_nIt5UFotCo<2v`TG K⿏c߃znmQ<'wkb^xs=ZInU9Ã)2|"ćR]y5[eB&e'(F(?noNG>+=/7~d+35օor4߽cwK?dMڅ 7Ci~ >爡ba-巚B~ǟOكq:[yϳwŞW xwx[[h۹WoM?~xާI?eֽ-GPI6&eηIeX2`N`g)Z'~ 7ΩOeΟߤo-kicmp3T w?c |H~ x?ƞ0F?|}=;QזKym 0M,,hF'^4>_QO ?`_|FntX\^Zsiڍ6N_C`lw߱ ump?GBjxZV ӣXKYZ'iooO&%bh`ĖYAmϵ9?7z K\(s6^&YuOID hl>d O@?dٿE{Ѽx0)#ufG,ڤnBIW|"G[vsLfӯY<9i1r3 7 YECftsğҮ,UM6TbэCwElۊCZ8~TWoEQEQEQEQE| ٗv࿁ 1Zس*44;;$K31$EEQEQETsZpqж(&6_CaBh$(((((((PGPy-0.5.4/tests/testdata/packets/18.v1.symenc_mdc000066400000000000000000000001321403641706600215670ustar00rootroot00000000000000X#SVX.նtM6΂-6Ӽ(qPG̢SvEԍfcbV%o*-{m^'38>gJPGPy-0.5.4/tests/testdata/packets/19.mdc000066400000000000000000000000261403641706600176670ustar00rootroot00000000000000YgOg*#Bbi^oPGPy-0.5.4/tests/testdata/pgp.jpg000066400000000000000000001005051403641706600166120ustar00rootroot00000000000000JFIFHH XICC_PROFILE HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)KmExifMM*JR(iZHHC      C  " }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?(0k_?| t}{Pػ6Cye9e(y 2H z}~)%>0~zOߌ_o0_2RGy{lL2',1~*'Pv wxzPhdD-'a z¯ڏ_>!#Vxu据ZAst]GF *,PFH~%cߵ^ ojQ,m.Eդ 3q'9~˟\okxS7_ lu]?GK=#IQ/l XXJ}(_/S^xVSV bI.bW9b@5׿b'Ɵ՗M .Jfo+[¬HXぅ$FDfM;fn9X$E$Ws%F2@ba'h&89 ~wXǾ +W[ \tφcщU.P !c+u7e|1W|-SOO6ڛ cO~f|;1RxaRA4O$+ ]~E iyF4[gky?SN?#v|2_`c#w_j~6`8ՑlHCo|GOyx/-ψ|Dįk:(1)ur {Ā6&>/h?G-ĺ-d=\\DMXِd|{sY Oxb_Qo |mh}OU'FB{U(ɟm+~ +tnx 'rD s"m͜,[1>o Azῂ>)4񯆼''tF1H7\F{A RIe]$KmdacHNAgtycp,WK;">*Ee{4|n]x#*q_*=~ПgI??ZoAu xV/oG~7RI O.֍c#nG9~h߱' h$!º\'MmL1*+PNrrmώW|cƵmpD2ngHzt2k~<~7!|׬ ?xkS}gƣ}v!Fq^xW~|t~o_ >|Q5^\]iQ>J]7|C0 !pU@>'VcxW!GIKO\L]$2&ƍXW 25΍$~w t?VVѧnu<-Rst,en?imOR9 !>2M<5DdoZ,,|"z2=/hI>|'gKHFֶVVZ ']& P=De>hڮq2][2NZn&QnmɑGo > CksNaHb2I`)( W 7V^>Ҵ?>,ͦI^M 1R `YI_< ogSq}&{j2gÁl-ī&H_v6Ɖ<>!}yuk+=9|9&-V >mھn/߰|iDjukiyj8-mʯ;Q8r~?G 3<_ xF[n4]\jBCd8(]}7 AԿR u]K^:&qeu%lגel#%c?UcK#p )Q@Q@2;H[HngvTzzS?l?أ_y Ϧê]XEy,JpmF/1*YTo?o~YO~4|'ф$>>a;#:~?_?5;F🈮u-gX]FܭڥԒA#yGq4e8rW73|9MI-3dz^MGAR'gn٤-OXn 3odĺn,qQڅmJTEM2{Y%*md^o"߈׊<]qSR>-2 &ұRE0rߔς?hCĿKh |Ajz} &6$4M l7 Usž&~1Cėz^aO[ijZTAf.??٧\~WȎ%ՋkO4jd$v i+?1(~Wv[-OĚ)DXlLsmů| nmK%_,i.D7Irc?)UeWğE>4y4mxV5/*}#Y;JĈYw ?3+BV?W O }?\->.Q "{~T1E-#teKM[Iä^VeixgֶB1+p G+䟦c)u ;>u}&Siڿ$85)Ź?ޟ|{^xWؼI !oDs|"Ϗ/E9-Súı, $v&#8a?i?_o x᷅o|;,\5QI磴*,Kwj<]`!Mߌ5Zơ;&DrHX!8 ?R'gº^{ /QI.KY7opщvc|]xgzF^iP\^y^WڤHZM;w[nN3wt_?gSNsMcH~,Yꉬ_x?~yH&}E 3;yRE<\oڿ>^ W/~&K {kˁ߹mb*@v.0}cik \|c,:Wo+}DO#e,[4!߆Vq 6gS9g K\</)nv ^&)o?_yu~jve즸0s~ q4?d~9KA;{ k)! k 5?jޫ* Oi\Gekgw:]^hW*$,.,o#}4~o/w^ +k+E>duu"#`0s??>1&OO;D[B-寔[ǸnO~?dK xKÖOlc I$ً3;ı$<kĿ'>?? QMO[S:S[i ]3~ G/Mu Oa'N2|O*|2NO{] I<>7P#xlsyE `9d[׈&|vG^*9+}B(t! -XTrBd&(?n~?k?7M oᧀUos}jVvOdf}O2;3k~6ixv[3%fpFf%Q9OV #_i:r^ӭ/R&K*d;̿#eW#hPˏ#=s Z}(=ֳ߉gch+i4l Mb>/o~>#}OHGឰOhF.r-2 10#B߱_5ݔbo/e]Kb)YnY,L`9 Q7W7 ߬ῃ|Y '9j=桦Or$KC"oܟu cq㫿ڋ_i5km7iѧrP&X(^!N%__x,v']QӬoEZYx'ѨD0pœ]jF[Dbi1BQKd$=hQ@Q@'>D[OWŒxARSޕo+5>Cyr:ny澈?$ h <5ozu7M59!0̥ZB ;A$}E||[$a-g@O߉>'՟%gj%#Ƞ`ʬ?#_EOa &X>x>'go:M%$mi>M~@|ՠgzCg[e{1]13?e߉>W jzMSK{\~m~ #d ~;k}j,{bӤe8=kn=^]A"k]zq|~$~͟=x|?/gLɞ"?Xj*>mi3_ÿ2AF-EVhDծb.]-Щm5~@8R`۟(mL4^h|Kk]IfI4vw++BQ]0XO4 _ ǿ m>#'hϮ%ƕukQAsNo-~~Q@'_Cem_ڇZ.=xrZ6a;I beآ 8!a\g^?G|X> E)4G]eּ1q$6* AB tP'/W~ O#GO^|7EwTԱ{{gUǘeq6ucVɯ)i><|FA)O-=_Ǫh1\ǫ|@4uBGF@eVmz\ʿ4P|=4˯gpF壵oRUq c,ۘ>oX2[v|b/~&4K߄(!I SM[`4ar T+}E~S~N(W 5_ x閷 !5HbTF4 lGhw%#)x~M~Q@ x [m;A?j>Sk^$iaM@Yi,֪#m5Ļ_grF |~7|?O74O>*㺹ҵ=#]k OˌI D$]Hdp>6eoڗ#㌟5Ľ;P,B׶:E/vK_Ǭxᖾfggt4Bϩ2;4Qv >` OF6t~\_+my>s٭3F 0?jC {ڷǾ!j:捦]C}U.A6lkmTțxVAtguƉ{Zw =]"As4rF&N`֟?|=7爼{uhN1Q(ַE<$3=oP^x-kþv{j0\Auw]u(uhUaxe84skG2)|7:/Yj)h6(n.Kv[.RlBW?-[/֟56'ý ¿n<:e!y.-ķ|Fu bHeE6h $`n"_ xwOii>Mʤ2xzMK(o,yjdxpђKojs?/'߈?ĝ yq}cd>%ݦYd.DGJ xKشӤ`gy%xu~zg 5{_Y MwťĶwI"9m/UXa86|.v~ o<[cQZ⻝W ]OgyFZ,.c=_M~Ͷ _XZCxble"( H~Ibj*9F-][_ta!JhB R\+neK<ֿQ~ǿ(|752jmsW8]f_Ƹ F@:֜O7A5lg8SC2*k4Kɷ8 cq;XJ.U):U7)ptJQWUQEQ@Q@Q@Q@Q@Q@-I FIHI2A?!طP7Tqo:߈5OChZ K[̰$QH)ſpb_[G+|NkxG8[إ{kZB8(]áϟ kۯS>/_?;[g>2΃&[\^5evYxu(|Q-_ e_>']$ bo>/xtٵضʖ.PǍ~%+{S&V]lxMŕv46,B#k't.'Y|me ]tzvkq=I#*Pʰ0%l񧎿j|cc>,o|;OM9u˫KH4m"͕iܖbKH5?_wZO ~~+/m;@ռ=g&.As^Y-qnq3q;#'5j :x^_"1_I=HaA*>?_ŏ_.𮁫|9-Z[%~FL<e]$ſÏߴ|6~N=(kѴLJkg[Tk۫Y ƫAt/8 gxo㯁4:hBhU@W^0Ow?'ş xkN< kSO=M<(Ւ_2LKğd>x D׃>xV#i1o$H!c4D#E'I9+'Z7ZxGԠyL9 pJ!طU oѺn𦵫t펟7^el-wB]U sɮ\n8=JI-w73J/Z5#/T_u%xigѿOŵ=x#ƨxC:E$\L)? #zUA~Qk>߱TxNvJ 5v7-qҀ=_*}c(ʵh? s@y=M>+Q?ŝr/#-s_*}c+O o>Z .iO>5LDo ЧyS&xAG^5M7Vkn@pUkF ݴg8_: SWML5ۋ_;Jxv<ϕq@Ł; 7 /G ttx6"Os@k>߱+8 Kčq$Blf_L s|cSLl\\<}`|R:݆A#ֶby-P_I1޲YaNoW= /_Y RQ_<7 /k>>KGm-Ůkk-nn{iQԤ}+O|TGo_|6's#$yEy88"؋qDŽbτ!]B|-iq6%󩹐̻r> g|y@v#?ָzNN[FW>Č}<Ӌ3|]x?u%Xbe'< kx5 qE 2 $(=+_(>'nuv7 ek Ǎ>=_Jv)k^IX  פ|QVGUA~W̷K TH|)(t .g]~z!c,9U*}c+?~kKu;Q=u iInA7տ:_zgïɭ ⱮrP\ 1XL{Dwºqڅ{#l#GHS6Kŏsx|QEG|2}=)\WDP'?c߉78Լ=$^^*;hYcC&c!NеZ7oǡxF'[\,GweU,ǠOY~ clwOoO?fiUF!}1@ʇ A4SOM??Q@E0k?noûWfO;†S7?s_ ;=N}߲&IIU @y?/_7/|A|0Qfok e{E95O ~ /Ӯ ,Sۛ> GWV5?@𾁦~uH,mZ=< 3yi>Ѽ-}In/o4Qx۲>m߈!.tyuoV/-'RIxQxP1k[tQd)(Cp >n6v~te3\$ !39| lO}ZKciyށP_?ko|OHҼUZj3~mI2Ey?? ;eC.:>3|KҼ9ZtaIXJ3<?R_V~ xGFs Y ye8Vf&H!-ԁcapiKG^ͥ/-~ Sr4gfNJ*۷:d擵Wᯈ~-c$H֚sZتyR<{CR(sKdoW|TվŊ,H| <͸&#$c'O_ǿ=#1ky8Wzd `A2B$K j_?t||# xu? { J$<3pTFe]0h㊟⺈lO/%E[ά8_ 5_e4mOQWn.V@_/H접r ߉͢Ykr߈gxt"4٥U|"NJuF^tZŴ˻C5ų` p}y/غ_^o)5åxM%Լh0C~c8~~ 87/g}dͼ6 t!uv5ejoSFo5 8+8'p@hg+:˃64>t[k{S,dDhk)@UC!%]xucź]OOBVq2ڰ I!GÂq@@i×6*K*Xmc}3PI"œiXŠ]0G|c '\?uxNũik<:|sK,taXϖHݙrXz#[[φ Rd0[sL)H,4oxAnTN3e8?e2#Ŧӎ>hm` պ3w ??uO֩p.t-5zSYU##H7H~!jY?P%jii`H?OM??Q@nWGu_lnWGu^OL ~_  ן{T~+0\)EҚgt zw;+ 8H|}jgN]0sc8AmJcx+deT*1W5[mM=6xD$?OtOi W6Sy76E"9k+ 9>Us>߈Ɖzj4쬦FvOF1~?ԭhi{w͍>pnmgm4;QP)xUk3κ>Ţ9o՟n&Yt|CGQ/fܝpo[ȫB'nڝGp~toIϱŏvS^w7P~,~۶L ~ ݁,:Oмl|r kG [>Ģ7? ~̞#x~9Vc?b=:^9?":Qzҩȃ8k&t:?a%kυWSU3ȵ^J L+ߴ Ar?xSC^?m3u}X~!\>vZȶ;d0C QmoqgMZ3MlCج P竅 ic0r4]);WjKG识=ei>O1(""@Wky==xO>O@= {|@i]1W𐻄A*k Ɨ 6J7KF&K;TrۘN_YIPqXU޲3*@sKaѭ|St>#.p5+5+B.guUgyq=I5WȾȣ)wᅫ6!`}?Z996=xL-Qs%-|$ $ypk|6kӨ/p mRr.k˧)t_"J(?44IEzǟ?ClwZd<<:ګYK", {Gݫ~L?~s^O jچu:}}&݋%JJȜ.9%ſ`o_?O-e$| vڕُ $xݷ$ w,4+٣k? V:mH߻l SX0;EE*n_ w|ڽu?lr8h:eZt;֔i~t?uJ*m=7Tix?_5ޯ]>T > "Xm$J,:,p!ҿ u߆Zto |oKWA^Kƹ*b8Sta.۟O?>>ƹt{͢-l/CYhՕ᎙zW'/ěRƽvWvQi:i-m]䬑7T~kt7c|2r&ǟt5ݾ"@-".M$@~Ϳx?~5ė,+4]Qt$]:݌zT16H3kg6ߊ4xGį h!K[؞$K5^[ZE6 F^ڝ̭wfc9=˕+jp?O)_wީE=>H'dP뫗iY>kUr;O؟Gso ?o^jڗ<&E%ƃee,V{8Kk$@Pm_N_8~֟gWNx:IAh}CIJk6wIs^[*7p1^ 5w៍5+CW}m5kt^-.a[֏c OT3࿊Oc>?"~~\S5ˬAr\l0JgVjf_ mjWů~_wJ<,.9<6Kv+ 2&9Pʮ_cs?K|#&uxڭqk }m,u&JOFI|P'"Hou?7x+dre[֏<SrL_'▹DZG?7|Qq6|e?Pkh q&WUQs2ں;m2k?=Ԥ2m#&e朆0zl/g~|5__x_L[Cv[?1Vnn8>3ߌ:xNګtZ'M.OմjX_ \VJ+^P#i"W$aU Qb$9<]Ji~1<* wOׇx%xKK Y5׮@P- WKoe$/->+jt/^ּs[no๼5> dSHlmN8d w4"O͠jO1^cohjvIȞE1^gh7UhFooWMWUeƽi.l8rnVQ4h䣐xiajK>u<_~8 4O~"i$t-;F-mvI39b(;|w}gZzCZ-{"f. `dc5~<X!?_k|-~5>-A?Gޅׇ>ŭtPI*~ 8j'G5~0T$4~YQڊ>:‹|D׼97eޛiW'J4$Q7 ®9>Dm9`x7o㟀<(ӼUǂŚ/kK}"Wmx3~+v FXt5,ΠER1SJKgMÛONft?ˤ[EFm{&{_@^q^Dgſ/iQx\t nCuX̅k`ɹC/:#_ॿK>=xg~&jaUyt˷i.+9LS?*,|~8S<_uo[߂#5~χU巶緷Me$k־<#uk^9g |pԠ~'x^KCDi"e_&+,ݴfx$'?&< g&/>MAVPA*qJUaiq5JO7BiTn>U\6}k/cS<A ($>϶Fmi~n4࡞#|o̿c[uԧҴ{IX}l}H2ܳbk-/Z|ci>?;O(5hol'U 3\ඟt-t^PstK˩%>%BUW7%x/Y/>/smpyV"khkldS-y?d_f[5 J]?Fd+pu.bȬLwyEz?f4(#⿊牼9$E[&2 .YcPk9ğ~]cBmp[u_WxK5O?0xݱ{hzW- c`d*n2c1y)a`ݥscfis7kZ7Z}e5|6a!OZUHέgRRrT˝ʯ,qr_Χ)t_"J(?44IE})~NUtZ⯍!#xR=>HE\>LXk7+P _pRL1~?Ťi-\nfWO*E)EIZJҕiКNMIlӳ_4xg>Ξ>u{ǿ|?:s_9lN1J!xc*9$9XWcGTҾ|6I5w:΋;E0Co(EgpyL=k2|Zu J#R}K}+u|l7Fw۰`j)%_ᔚg 2?iγ)7("t sOW%>i~UG`L bcʵK} 4' z}w|kmq=7-q?nHh[c6zsMex_ ׌5 q&x {;S.XZ(sA}+rshmA Y20?- 6[g8gG >.=>Ɨwj_۷0#FfaT\2OZ_'?wYW-l-oikZ[{q󑴲n#kҾ-,>*_jt__1x᷎fip[2j&ijdUex]~ɺ(O ˜9m+\I$i(UAaˮա#G"CeUg >,m~Ͽ uxVJu6Iۃ rTz$/L?a ~񿊭|%iVMٍ2O,0$|"F73!Yw? XQ俻ynեf0(@r9O:n-S𝭭jj#CuMm"$] .-_yrcY:ּQ}eKÔM  u8{8fvJ+džyk>~^7ĸ|'͗omv?ipɮ9E"Ȗrk>&i6DŽt^|R5-~QOh}!B<ڥ~ G]/ %$ԂYU2O9犥-G_g.+c??HFo{e.>|.u=CxVăk't[1>x>"~n_ɏ¾yn8.|>e^jOVzO?vFLkr y<Ƕ/#sM{00p_bzת9#aV97DQSƦ?NOLI?sR^E_n˘+WƼC'wW}!} w>*ŢH9 f[?jMݜ3\F+**%gPcGE8 JW#!}qf"I$E QU`~#`b+$ˮjrz謿Zm(o ɟ*KFlg^]To\%TQGx=MoLn1i>6?箯ܚҶA~͖x|㟞kХ>K%§aWαOUxG ++oO,ċyQ~u>c4}/HeiEvRѡ(($#s 3͵bU/)+s?;SSOODQjii`Hr ? u f&r ? u |e_P6'˘ăwSF@4謩uGZ%X/ 5VBNtn{0t/?5+Z_"i,.H; 68<@U]']ף;[Էh%YRI)wTQEQEQEQEQEQEQEQEQEQEQEQEڟE$;SSOODP(Q`k8]Wѷ^#i]>:$,bʳƌKd7+P _pSL񇍼3h渚cBfp9@xE/?i)i~4,GYF7:0]X jЎz? x3GrDдKe-o Hp -zz;ۍSzujMlm{5g1Eedq!呿:>x7Z|sxy%,#y㳶$_-^] ( ( ( ( ( ( ( ( ( ( ( (?;SSOODQjii`Hr ? u f-_S?;৅~1|rOoUWV+K77.Xd2<3 e[ƶ?jPo3h|C)Oi2,l;xPUKo+e7aCuiGJ $;N\*$_[zeįc:jir͠jNu}+)E%Z0Wq9'[5#_>.jW4k2i:KkYi|8$U|{GnxWv Hւo{[-MuIK-sfw7}E~a7 9|p?/GO𴺬vNGX鶊q&? sn_=3Ÿ?j^Sjk{=^MV+H9b?Chu~Pg![Zi  fB yוX~ko%Ŀx {مr?Y(k.O-[VSBhpޟ#`G|Ɖ\,bc! cwF,7;JoVt5'inm(NC~Q_vxNJn>;+е ZpQkxU#> ^c871ffa%Iz/+ǥi_-{kcR|{eJfRrH` Zিd|IG(Ӯ*iP]"ũT dF<E~s~Tmi}3o!j[ bC _p'/eឧ_ܛr]j ;[QtvƟ(C]Uk4L:=bDdYf TIsEP >)x/}75޿oeW *rjkĺxoOÝv:4L"6G$䯛׾ .>>h_ t}KNMGˆ$r ¨,OW_H_&~|qGWI-|9j-yn&@7FY:xPc1~οHdW%u31֓DV,[YY5) .Ք3pA6 Y>|Ǻǧ-tW[HKl$$,[nH_4|s4>`6-bI$.]SϻRi$Y."$e ' ?`hlڤ2{HmLjzRl 2H&;>2iJ޺ޡBUnj,]_ڽoy`em$HɧTt Z .iW:?gh> ;o_ m%}5"S:Ewl!1'/:>77kj|,}ݾ\CM"F&rak W?_o?VI0!͂UC35[k3co{m@𮻨" .,嶱}$W=zR?g/g_]Kټ+}SW7}[P;އkpH þ cx’j)߇j(rI$i$+w~?jo|DTW>XN`i |TB1Y~$|G<+jᮙ~? } `8hZ?8VY]T96|o`ඞ-Hg wbE|WY|Os>"AqwZdBcclqO>Ե--nK?[GP`o9bo-rJʜ2+K>I+Y^ö/_ ivI#P (bT_[7i ù<+?|9 V;KI9#$yBOoŞO־,GмCxNq}>qCu2*#pH6s'Tc/k S @~)[Yjj,ºuޠd7ZU&O ªd)rP?o_x?~;Lu S|kmO+˭`ĉpTrrO_J>%g;٣ωt_!LK7J٫j F<b i|ASR&0~9ZYiw<=vVqn7O#e4W-߳'i7_xT^b_aTPhpYJU?lOmu_ѭ/氎/q%YYy4Q쀨ɂBCs_o -G}_wVUDHAlyu dL@# WTO CG}u)<(-j$y/"i:L1$0oتMc߲΅3o>mhw7y-F8spq^&~Ҷ? eKO'uH46"Z-(Q2|xwéࡺo'ƙ/ 뗞&Qae2ܽ/Vb|-?/ zPм^𾹨O}&xn,D%`fY]fkټSs챭b, o:CEoZkshf݄$dDrK_nIt5UFotCo<2v`TG K⿏c߃znmQ<'wkb^xs=ZInU9Ã)2|"ćR]y5[eB&e'(F(?noNG>+=/7~d+35օor4߽cwK?dMڅ 7Ci~ >爡ba-巚B~ǟOكq:[yϳwŞW xwx[[h۹WoM?~xާI?eֽ-GPI6&eηIeX2`N`g)Z'~ 7ΩOeΟߤo-kicmp3T w?c |H~ x?ƞ0F?|}=;QזKym 0M,,hF'^4>_QO ?`_|FntX\^Zsiڍ6N_C`lw߱ ump?GBjxZV ӣXKYZ'iooO&%bh`ĖYAmϵ9?7z K\(s6^&YuOID hl>d O@?dٿE{Ѽx0)#ufG,ڤnBIW|"G[vsLfӯY<9i1r3 7 YECftsğҮ,UM6TbэCwElۊCZ8~TWoEQEQEQEQE| ٗv࿁ 1Zس*44;;$K31$EEQEQETsZpqж(&6_CaBh$(((((((PGPy-0.5.4/tests/testdata/pubtest.asc000066400000000000000000002755331403641706600175160ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v2.0.17 (GNU/Linux) Comment0: Contains public keys and subkeys for: Comment1: - RSA von TestKey Comment2: - DSA von TestKey mQMuBFPQIwoRCAC/nRgeAEwiii9XGaeqi5zK7kOy6yr/q3WYT4Gy/iyV/FQRw92x j2363aMDOxvbwmSQGt5rONmeYoOiWDfmizvIk8xQrcuSBtVC+xSBFNbkRNPLemd8 PTMs4AR9VwBSL0PQMhU1q5O3c0j0ql/Lr/yUoHWRtWhOutrZiDUO6/69nUxiqkjX Fc7Rx1BxRDMJ3jIu9SRv2GClT//bTHub2hBYnQTLMgSGvz1MAsmY6D4lMbh7sSPK p/W7uCpfQ9usRfeQ/EeIJy1/nWywdVcfLXNiEmNHYqoSeoRArOwzWX9tUQEQjyF1 N4WnZOVkaV5QP8aGlMDdWErcmRifSkWRO14vAQDwDhep+b8SedCOHd6EwNYN7z/+ R1sOL7L3ykDOD4sHSQf/c87nZXW0ppg+nVcxuwseDbhYgwqOquIbRVMnctRNPhYR akrvptzxUk9ZLlT5cCxssdaOEiXNLQl6ZOYMQM+xnhuo0oMDXbBrCn+Y8LoS54WY 8acABSWDGCGfoOddhf/7Fp2rrehpxOpyIpX8c7DgpEyDmnESNNfWRimcfehIgmj8 L5+2mMhQFMwFT1XZpT0EYnV5K2ym484bYpaSVlCd/tJvP9T6l1GXQhDVuipQ0seq CO2hLIM7dRNVEYX5HuLGUjjE6qGbqRcEYRvvV6a93tKs4z94XqBoshRPhoTjyTk5 ERlqXOPlQQhFUPOFeNp09O0V4k6utp000HIQQiTR4wgAl++zc0ixOsxxtDEF3cBP AW6tZySw/znDDlG7xsEkf3BeYTDf9IDYFVxXc3eYBjMtdIead6AR8MayIsAsHMOR PJySVpdFfI5vMrooHkNHYAv/pjC2tZL1PBfLBQIqZV+fjezJUAvk2/UU565FMusE woGa1jGguqwIgkhb8v9ppcZn4KeZM/cvzkowkV+UKZIeIE3v5l7bntrwK5J915uF UDV7DS6p0XqZxWr8sOwBA6jF96q5SbnhXw0iyS0LddtlzZbnDkXLX341JSDo0t7z jy17C1f3EqKTpCKlW/hUIJuW8KLD8jZMEPcVwb2wUCHprBBWPjpiAHQIgeqBitfj eLQtRFNBIHZvbiBUZXN0S2V5ICgyMDQ4LWJpdCBEU0EpIDxkc2FAdGVzdC5rZXk+ iHIEExEIABoCGwECHgECF4AFAlPQKysECwkIBwIVCAIWAgAKCRArR0uwIITHEgyC AQCmEMlMif7UNjud4yfMFdO2M16XxW3pwrtgPe6TbAVFSAEA40PW4mGG6eWk4Fo9 iQT1sNGHCW5xA7nlQO4v3WgVoUzR/wAAgVv/AACBVgEQAAEBAAAAAAAAAAAAAAAA /9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQ AABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAA AAAAAAAAAAAAAQAA9tYAAQAAAADTLUhQICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFjcHJ0AAABUAAAADNkZXNjAAABhAAA AGx3dHB0AAAB8AAAABRia3B0AAACBAAAABRyWFlaAAACGAAAABRnWFlaAAACLAAA ABRiWFlaAAACQAAAABRkbW5kAAACVAAAAHBkbWRkAAACxAAAAIh2dWVkAAADTAAA AIZ2aWV3AAAD1AAAACRsdW1pAAAD+AAAABRtZWFzAAAEDAAAACR0ZWNoAAAEMAAA AAxyVFJDAAAEPAAACAxnVFJDAAAEPAAACAxiVFJDAAAEPAAACAx0ZXh0AAAAAENv cHlyaWdodCAoYykgMTk5OCBIZXdsZXR0LVBhY2thcmQgQ29tcGFueQAAZGVzYwAA AAAAAAASc1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAABJzUkdCIElFQzYxOTY2 LTIuMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAWFlaIAAAAAAAAPNRAAEAAAABFsxYWVogAAAAAAAAAAAAAAAAAAAAAFhZ WiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAA JKAAAA+EAAC2z2Rlc2MAAAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAA AAAAAAAAFklFQyBodHRwOi8vd3d3LmllYy5jaAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkZXNjAAAAAAAAAC5JRUMgNjE5NjYt Mi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAAAAAAAAAAAC5J RUMgNjE5NjYtMi4xIERlZmF1bHQgUkdCIGNvbG91ciBzcGFjZSAtIHNSR0IAAAAA AAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAsUmVmZXJlbmNlIFZpZXdpbmcg Q29uZGl0aW9uIGluIElFQzYxOTY2LTIuMQAAAAAAAAAAAAAALFJlZmVyZW5jZSBW aWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAHZpZXcAAAAAABOk/gAUXy4AEM8UAAPtzAAEEwsAA1yeAAAAAVhZ WiAAAAAAAEwJVgBQAAAAVx/nbWVhcwAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAA Ao8AAAACc2lnIAAAAABDUlQgY3VydgAAAAAAAAQAAAAABQAKAA8AFAAZAB4AIwAo AC0AMgA3ADsAQABFAEoATwBUAFkAXgBjAGgAbQByAHcAfACBAIYAiwCQAJUAmgCf AKQAqQCuALIAtwC8AMEAxgDLANAA1QDbAOAA5QDrAPAA9gD7AQEBBwENARMBGQEf ASUBKwEyATgBPgFFAUwBUgFZAWABZwFuAXUBfAGDAYsBkgGaAaEBqQGxAbkBwQHJ AdEB2QHhAekB8gH6AgMCDAIUAh0CJgIvAjgCQQJLAlQCXQJnAnECegKEAo4CmAKi AqwCtgLBAssC1QLgAusC9QMAAwsDFgMhAy0DOANDA08DWgNmA3IDfgOKA5YDogOu A7oDxwPTA+AD7AP5BAYEEwQgBC0EOwRIBFUEYwRxBH4EjASaBKgEtgTEBNME4QTw BP4FDQUcBSsFOgVJBVgFZwV3BYYFlgWmBbUFxQXVBeUF9gYGBhYGJwY3BkgGWQZq BnsGjAadBq8GwAbRBuMG9QcHBxkHKwc9B08HYQd0B4YHmQesB78H0gflB/gICwgf CDIIRghaCG4IggiWCKoIvgjSCOcI+wkQCSUJOglPCWQJeQmPCaQJugnPCeUJ+woR CicKPQpUCmoKgQqYCq4KxQrcCvMLCwsiCzkLUQtpC4ALmAuwC8gL4Qv5DBIMKgxD DFwMdQyODKcMwAzZDPMNDQ0mDUANWg10DY4NqQ3DDd4N+A4TDi4OSQ5kDn8Omw62 DtIO7g8JDyUPQQ9eD3oPlg+zD88P7BAJECYQQxBhEH4QmxC5ENcQ9RETETERTxFt EYwRqhHJEegSBxImEkUSZBKEEqMSwxLjEwMTIxNDE2MTgxOkE8UT5RQGFCcUSRRq FIsUrRTOFPAVEhU0FVYVeBWbFb0V4BYDFiYWSRZsFo8WshbWFvoXHRdBF2UXiReu F9IX9xgbGEAYZRiKGK8Y1Rj6GSAZRRlrGZEZtxndGgQaKhpRGncanhrFGuwbFBs7 G2MbihuyG9ocAhwqHFIcexyjHMwc9R0eHUcdcB2ZHcMd7B4WHkAeah6UHr4e6R8T Hz4faR+UH78f6iAVIEEgbCCYIMQg8CEcIUghdSGhIc4h+yInIlUigiKvIt0jCiM4 I2YjlCPCI/AkHyRNJHwkqyTaJQklOCVoJZclxyX3JicmVyaHJrcm6CcYJ0kneier J9woDSg/KHEooijUKQYpOClrKZ0p0CoCKjUqaCqbKs8rAis2K2krnSvRLAUsOSxu LKIs1y0MLUEtdi2rLeEuFi5MLoIuty7uLyQvWi+RL8cv/jA1MGwwpDDbMRIxSjGC Mbox8jIqMmMymzLUMw0zRjN/M7gz8TQrNGU0njTYNRM1TTWHNcI1/TY3NnI2rjbp NyQ3YDecN9c4FDhQOIw4yDkFOUI5fzm8Ofk6Njp0OrI67zstO2s7qjvoPCc8ZTyk POM9Ij1hPaE94D4gPmA+oD7gPyE/YT+iP+JAI0BkQKZA50EpQWpBrEHuQjBCckK1 QvdDOkN9Q8BEA0RHRIpEzkUSRVVFmkXeRiJGZ0arRvBHNUd7R8BIBUhLSJFI10kd SWNJqUnwSjdKfUrESwxLU0uaS+JMKkxyTLpNAk1KTZNN3E4lTm5Ot08AT0lPk0/d UCdQcVC7UQZRUFGbUeZSMVJ8UsdTE1NfU6pT9lRCVI9U21UoVXVVwlYPVlxWqVb3 V0RXklfgWC9YfVjLWRpZaVm4WgdaVlqmWvVbRVuVW+VcNVyGXNZdJ114XcleGl5s Xr1fD19hX7NgBWBXYKpg/GFPYaJh9WJJYpxi8GNDY5dj62RAZJRk6WU9ZZJl52Y9 ZpJm6Gc9Z5Nn6Wg/aJZo7GlDaZpp8WpIap9q92tPa6dr/2xXbK9tCG1gbbluEm5r bsRvHm94b9FwK3CGcOBxOnGVcfByS3KmcwFzXXO4dBR0cHTMdSh1hXXhdj52m3b4 d1Z3s3gReG54zHkqeYl553pGeqV7BHtje8J8IXyBfOF9QX2hfgF+Yn7CfyN/hH/l gEeAqIEKgWuBzYIwgpKC9INXg7qEHYSAhOOFR4Wrhg6GcobXhzuHn4gEiGmIzokz iZmJ/opkisqLMIuWi/yMY4zKjTGNmI3/jmaOzo82j56QBpBukNaRP5GokhGSepLj k02TtpQglIqU9JVflcmWNJaflwqXdZfgmEyYuJkkmZCZ/JpomtWbQpuvnByciZz3 nWSd0p5Anq6fHZ+Ln/qgaaDYoUehtqImopajBqN2o+akVqTHpTilqaYapoum/adu p+CoUqjEqTepqaocqo+rAqt1q+msXKzQrUStuK4trqGvFq+LsACwdbDqsWCx1rJL ssKzOLOutCW0nLUTtYq2AbZ5tvC3aLfguFm40blKucK6O7q1uy67p7whvJu9Fb2P vgq+hL7/v3q/9cBwwOzBZ8Hjwl/C28NYw9TEUcTOxUvFyMZGxsPHQce/yD3IvMk6 ybnKOMq3yzbLtsw1zLXNNc21zjbOts83z7jQOdC60TzRvtI/0sHTRNPG1EnUy9VO 1dHWVdbY11zX4Nhk2OjZbNnx2nba+9uA3AXcit0Q3ZbeHN6i3ynfr+A24L3hROHM 4lPi2+Nj4+vkc+T85YTmDeaW5x/nqegy6LzpRunQ6lvq5etw6/vshu0R7ZzuKO60 70DvzPBY8OXxcvH/8ozzGfOn9DT0wvVQ9d72bfb794r4Gfio+Tj5x/pX+uf7d/wH /Jj9Kf26/kv+3P9t////4QCARXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEa AAUAAAABAAAASgEbAAUAAAABAAAAUgEoAAMAAAABAAIAAIdpAAQAAAABAAAAWgAA AAAAAABIAAAAAQAAAEgAAAABAAKgAgAEAAAAAQAAAPSgAwAEAAAAAQAAAOUAAAAA /9sAQwACAQECAQECAgECAgICAgMFAwMDAwMGBAQDBQcGBwcHBgYGBwgLCQcICggG BgkNCQoLCwwMDAcJDQ4NDA4LDAwL/9sAQwECAgIDAgMFAwMFCwgGCAsLCwsLCwsL CwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL/8AAEQgA 5QD0AwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//E ALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEV UtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVm Z2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrC w8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEB AQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMR BAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1 Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKT lJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm 5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A/fyiiigArzD9k79rzwX+2l8OtT8U fA26vbnTdH17UPDl2Lu2NvNDeWU5hmUoecEgMp7q6kgHIHp9fil/wSU+MH7Xek/C 34zXX7CPwm+E3jDwX4j+MvinUrfU/EfiebT57eV7pQ6G3RPnjGxMMrAnLDHFAH6Q j/gq78C9J/ZQtfjZ8RvGdv4N+Hd/rd54etdQ1uJoZLq8tr2ezkSKFN7vmS0nYbQT sQuQoBx6j8Kv2o/hn8dfDtnq/wAFPiH4I8X6VqN4+nWt5o2uWt9Bc3SIXeBHikYN KqAsUB3BRkjFfhh/wSWstI+P3xm/Y7+G37X+laTqXhfS9K+KDW+halEs+m3/AIjk 1i5F1aTQygrO8djcM4VxwsoIGSc53xj8G6B+y5/wXG8Wa5+zFpWkeFPhN8Nfjf8A DGx1XT9Htks9I0mfUdIvbO7aGKILFFjzWEoUD52OfSgD+gLx18RfD/wv0RdT+Jeu 6N4d0154rVbvU72O0gaaVgkcYkkYLvdiFVc5YkAZNcP+17+2D4K/Yh+EJ8afHOfV l02W+g0uztdK02bUb/UryckRW9vbwqzySNtY44GFJJGK/Lz/AILGf8FGvhv/AMFE v2ZNO8G/AmbVbr/hE/2l/Dnw81iK4iRF1iRXuHMloY5GMkDtBIEc7WJhJ2gEE/sm yB8bwDg5GR0NAH53WH/Bx74J8ReJtc0rwH+zV+2Z4luPDFytprB0z4YGY6TK0YlV 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 w1p3ibSPDN89jqfiXSLi9EFzpsE0ckbo0/mooxImTgFgpNafiD/gl58HfD37Bvg3 4eeIvHt1pGifD7xO/jHwh44a+srXUfD1y+qS6ijWt0U8oLiZ4CSDvjOTk4I9v+Nv wZ+H3/BQr4ZeGoR4mi1rw74c8XaV4pt7rw9qMFxBdXemXcd1HbyyKHVomdFV1GGw eGU4NAH5c/Br9ga/8Uft9zJ/wSl8N6D+xzrnwi8FWWoeKX8RaDb+KNbubrW/t4it Lh5LuZF2W9jDLlJs5uG8zcVCV84/B7/gq94t/wCCjvjOWy+P1p8V9Z+L/jU2GifD vQvCvxFuPAHgnTpl0yGSee4uluYTLcS3EjzCL/SJWUrHGANm79Y/2uf+CUnjL42/ tF+N/Gn7OHx11j4Q6X8Y9BsPDnxG0+y0GHULrWLez85IZbC7kkU2Fwbe4mgMgSTA YMBuFOsP+CLXwF8LeHfiT4O8aWmm3Pw++I2k+H9NsfD1yqQyeHpNHspLKG8s7st5 v2pkeNvOGHDRkktvagCh8XP2P/jL4S/4Jx+HtN+IP7UHxJ0PxH8M/A15ceJ9Y8PJ ZJc+Jb6G3aZZZNQu7aW5RIyjR7lKPKuGc78mvzT8Cftw2H7Mn7PXxD134pfGz9pr UvitL+z7ofiPw2mp+MNc17TLnWfEGh3Mk0rW0ULQWKWs5tJIpZ3QL5oIYlQa/arx Z+zZDq/7AOsfCHxL4+1q/ttS8CXHhGfxlq8sU+oSJNYta/b53XYkkoD+YWyu4jJO STXyZ8P/ANhb4DeDvg18Xfhn44+P/grWn+N/gfw58PZcajYWk9kdJ0UaVBNbQ/aW 3O75uRF0V225YckA+NPh940/a5/bA8H22i/D/X/i78RNA+G/xD8V6JqkPg34kad4 S8TYtLTS4NOkub29YGe1iujqn3klDun73ecZ/Xj/AIJ1ftZ6Z+3H+xb4C+J/hK01 extfEVnLDJb6pLFNdxXFpcS2dwJJIgI5D59tL+8RVVhhgqg4HzZ8Lv8Ag3Z+DPgL wPb6b4k8W/FjUdb1BbyLxFquneK7nQX8Vw3Vw11PZ3kVg0ayWvnyzusRLMvmsC7c Y+s9X/ZN8IN+zba/CfwBFqPgXwZYWkOn2dt4YvG0yWzt4mUiKOWP5grBSH7uGbJJ YmoqOUYtwV30W1/mdGEhSq1oQrz5INpSklzNK+rUbq9lra6vtc9Lor481r/gkfbe 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 AIeANquo6HbWfhTXdJuonWXxHZ3unzNc2CSSiCCCBCE82WWV1w3RVVyQSMBbj/gq D4Dn0DR7nw9p3iK91HVr77L/AGW1r5N1DHlx525j5TrlVGFc43c4wRWz8Ff23Ifi t8QNP0O+8Gazp9zq1r9ohvbVhe2gQSOo8yUKu1cq5zgj6Gupm/ap8HN8ep/AkMvm 6xpNhcXt5OY9kdmY1RzECwBdjGxc7MgBeTngAHqNfNuuft66x4b+NaeFtW+F/jCS GOW5tpJLS2aaad1mZbeSAMEV43jQOSSMeZwSFy3ZfDv9u74Z/FBr9PC+uyebptjc anPHPayRFLaA/PKWK7QMchSQ2CDgVH8Pf27fAHxE1rQ9LsrnVbHVNeWFYbe706aM JNKhdYWk27N+3DZBKkOpBOaAOa+LX7Zutz6T4u0z4AeDPEl94s8KNafaIb3TGdFE 0mGASN9zHZhhjqG3chSau6v+1/4mtvgbca4fhV43sfFTvPZ22mNp73UKzoPlld12 v5GSvzFVLHIXON1d/wDtI/EjV/hZ8M/7R8BxaZNq9zqNlp1st+sjW+64uY4csIyG OA5PBzx3rxr4Lftn+M/F3xh0vQvHmn+GG0i91i60C4ubC1vbeW3u4YJJAoE/ysCU AIHI3c44yAfQ/wAN/EOo+LPAmlal4t0qbQ9SvbdZbiwlYF7Zj/C2Oh746jODyDW3 RRQAV8gfth/ta+Nfh38U59E0LUW8I6XbS+XHcG0haS7Tyon84PcRujqzySRhUA2m FixywUfX9FAHyh+yX8VPiR8VPEmn39hrWteIdCjv2t9VuL5dNGnpCISSIzbqswuA 7REAArg/NjrXuX7SPjnXfA3wydvhbBBP4n1a8t9L0sTrmGOaaQJ5kn+yi72P+7Xe gY6UUAfPXwA/a28dfE+TSNK8VfCzxBZapv8A+JxqM8L6fpttFkkyReYHeRsDAj/i P8QByPnT/goL8TvHHx7/AGWrDwT8Q9Eu/Do+M3xL0rw5olrPH5N0mmGYSbpY8blK vbIzFjz5nQLjP6IV+Rv7Un/BX/4e/Fb9sH4N33jDR/FGg6T8H/EetXPiC1kgjnll njiEVmYAr4YmSNshtu0t1IG4/O8TY6hhcI6Naaj7S0dezaUvui235H7J4H8K5rnv EVPMctw0qqwalWfLZtThTqVKKtu3OrTjFWT95pO10fpX4a+Ifi2w8eaT4c1j4eTW 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 odzNxhKrYYQG3vaaLgO+ee8sYCBvi2uxtOFTQVKI/o90ukjQyXCOGUq4qJB2qSyM qGjLO5RaBrj+I1HVl3fhisLFxxj+nIWRK9uLI0TfGqYo9mvfS1rHbLdHX6+ZHu8/ RpflpFeMNXVnjKJT5yXeTethRmjSPN+VJqNzK4EWgLaB0f8AAIFb/wAAgVYBEAAB AQAAAAAAAAAAAAAAAP/Y/+AAEEpGSUYAAQEBAEgASAAA/+IMWElDQ19QUk9GSUxF AAEBAAAMSExpbm8CEAAAbW50clJHQiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQA AAAASUVDIHNSR0IAAAAAAAAAAAAAAAEAAPbWAAEAAAAA0y1IUCAgAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAAAVAA AAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgA AAAUZ1hZWgAAAiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQA AACIdnVlZAAAA0wAAACGdmlldwAAA9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAABAwA AAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAABDwAAAgMYlRSQwAABDwA AAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJkIENv bXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAS c1JHQiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAA AAAAAAAAAAAAAABYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UA ABjaWFlaIAAAAAAAACSgAAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDovL3d3 dy5pZWMuY2gAAAAAAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAA AAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdC AAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0IFJHQiBjb2xvdXIgc3Bh Y2UgLSBzUkdCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJlZmVy ZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAA ACxSZWZlcmVuY2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB2aWV3AAAAAAATpP4AFF8uABDPFAAD7cwA BBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521lYXMAAAAAAAAAAQAAAAAA AAAAAAAAAAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAAAAUA CgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwA gQCGAIsAkACVAJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA +wEBAQcBDQETARkBHwElASsBMgE4AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIB mgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAIdAiYCLwI4AkECSwJUAl0C ZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNPA1oD ZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwE mgSoBLYExATTBOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYG BgYWBicGNwZIBlkGagZ7BowGnQavBsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kH rAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjnCPsJEAklCToJTwlkCXkJ jwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuAC5gL sAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgO Ew4uDkkOZA5/DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQ uRDXEPURExExEU8RbRGMEaoRyRHoEgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MT pBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9FeAWAxYmFkkWbBaPFrIW 1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoEGioa URp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHewe Fh5AHmoelB6+HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsi JyJVIoIiryLdIwojOCNmI5QjwiPwJB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcm hya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymdKdAqAio1KmgqmyrPKwIr NitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/HL/4w NTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01 hzXCNf02NzZyNq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87 LTtrO6o76DwnPGU8pDzjPSI9YT2hPeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdB KUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVVRZpF3kYiRmdGq0bwRzVH e0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2TTdxO JU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtV KFV1VcJWD1ZcVqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVc hlzWXSddeF3JXhpebF69Xw9fYV+zYAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tk QGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2maafFqSGqfavdrT2una/9s V2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQUdHB0 zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9 oX4BfmJ+wn8jf4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG 14c7h5+IBIhpiM6JM4mZif6KZIrKizCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQ bpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cKl3WX4JhMmLiZJJmQmfya aJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPmpFak x6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxav i7AAsHWw6rFgsdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6 tbsuu6e8IbybvRW9j74KvoS+/796v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjG RsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42zrbPN8+40DnQutE80b7S P9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W3hze ot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXr cOv77IbtEe2c7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4 qPk4+cf6V/rn+3f8B/yY/Sn9uv5L/tz/bf///+EAgEV4aWYAAE1NACoAAAAIAAUB EgADAAAAAQABAAABGgAFAAAAAQAAAEoBGwAFAAAAAQAAAFIBKAADAAAAAQACAACH aQAEAAAAAQAAAFoAAAAAAAAASAAAAAEAAABIAAAAAQACoAIABAAAAAEAAAD0oAMA BAAAAAEAAADlAAAAAP/bAEMAAgEBAgEBAgIBAgICAgIDBQMDAwMDBgQEAwUHBgcH BwYGBgcICwkHCAoIBgYJDQkKCwsMDAwHCQ0ODQwOCwwMC//bAEMBAgICAwIDBQMD BQsIBggLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL CwsLCwsLC//AABEIAOUA9AMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAA AQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEH InEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJ SlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaan qKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4 +fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAME BwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ0 4SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4 eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS 09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2gAMAwEAAhEDEQA/AP38ooooAK8w /ZO/a88F/tpfDrU/FHwNur2503R9e1Dw5di7tjbzQ3llOYZlKHnBIDKe6upIByB6 fX4pf8ElPjB+13pPwt+M11+wj8JvhN4w8F+I/jL4p1K31PxH4nm0+e3le6UOht0T 54xsTDKwJywxxQB+kI/4Ku/AvSf2ULX42fEbxnb+Dfh3f63eeHrXUNbiaGS6vLa9 ns5EihTe75ktJ2G0E7ELkKAceo/Cr9qP4Z/HXw7Z6v8ABT4h+CPF+lajePp1reaN rlrfQXN0iF3gR4pGDSqgLFAdwUZIxX4Yf8ElrLSPj98Zv2O/ht+1/pWk6l4X0vSv ig1voWpRLPpt/wCI5NYuRdWk0MoKzvHY3DOFccLKCBknOd8Y/Bugfsuf8FxvFmuf sxaVpHhT4TfDX43/AAxsdV0/R7ZLPSNJn1HSL2zu2hiiCxRY81hKFA+djn0oA/oC 8dfEXw/8L9EXU/iXrujeHdNeeK1W71O9jtIGmlYJHGJJGC73YhVXOWJAGTXD/te/ tg+Cv2IfhCfGnxzn1ZdNlvoNLs7XStNm1G/1K8nJEVvb28Ks8kjbWOOBhSSRivy8 /wCCxn/BRr4b/wDBRL9mTTvBvwJm1W6/4RP9pfw58PNYiuIkRdYkV7hzJaGORjJA 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 =bnpu -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/revocations/000077500000000000000000000000001403641706600176555ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/revocations/dsa.1.revoc.asc000066400000000000000000000004401403641706600223660ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: This is a revocation certificate iHgEIBEIACAWIQTryIqUrLEQ8b4/48ErR0uwIITHEgUCWYCvMwIdAgAKCRArR0uw IITHEiFDAPkB/6ZeGwyzoZRJC6fRtI/OmihNvrdu+Ny3dncMisrT5gD/XQ186uTF aCPZxg0Jy5ctcFcYie9km5QgNWm3q3uipH4= =4Fzd -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/revocations/ecc.1.revoc.asc000066400000000000000000000004401403641706600223510ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: This is a revocation certificate iHgEIBMIACAWIQScv1nOQFYyAvCFs5nQEFX7yt0mjgUCWYCwOQIdAgAKCRDQEFX7 yt0mji9tAQDyXokguheA8E8UZVOY5Bq2W0WrSYUUBSKREWq/5nnqyAEAzlRXHO7m 7NlCBkP9A7ANP8ykIejE6zSroBnmrrTZUvA= =i9u2 -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/revocations/rsa.1.revoc.asc000066400000000000000000000010441403641706600224050ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: This is a revocation certificate iQE2BCABCAAgFiEE9ClLyAlKfgWFyF6GN0c7N1jETzYFAlmAsHECHQIACgkQN0c7 N1jETzbblAf+LXAAKIMGDAJA8UBmo098uDTlVieFTJeiYzyZZAYpee+yqtm8EtZY orqzsPueztm37bKvg4n9NeGEREVlra3W3clXwtmzeufK/J7HXR627e593Ct2ai8W v4V/eu/UIGS+3FfroMD2sUoQwJWm27RO4M01uuuP69c331UH3y6X6T6M1Fvx/iB4 6/WPMWvZU3K+Cbp5O1TXtwThW/K2a3gBt0N4XGBgEvuTsPxrUP320kiBRfbtJGNe d4nVOJk5fCpKWKcQ2HrZEgXUYRdBOWNfiQATqwBoTwGQawT+Jw1gl3GB2JVuzQWC TqoogtWLq51TsYHPZWNH7O7EaZHSttEjHQ== =hyrP -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/revocations/targette.revoc.asc000066400000000000000000000005651403641706600233070ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Comment: This is a revocation certificate iLYEIAEIACAWIQTTlv4xBcdnbHTehHYOeeRxaa7DegUCWYCwlwIdAgAKCRAOeeRx aa7DejgJBAC4vaBWIUtKv8t90N1+pXlsOhd71VxwYFBFY+T34VAoH1CYfemdr4Ed lxZvWoJunbbA+hVFw7ML9JsIxKbWUtqSSf7rAzwwwfL84iYjYMiILMd0lJAeRtq4 f4byrRpP4Q1M1hIPpnnM7o+j+AX1VLnxdkX6VPi1g1hxQn555cunFg== =cEcC -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/sectest.asc000066400000000000000000000222201403641706600174610ustar00rootroot00000000000000-----BEGIN PGP PRIVATE KEY BLOCK----- Version: GnuPG v2.0.17 (GNU/Linux) Comment0: Contains private keys and subkeys for: Comment1: - RSA von TestKey Comment2: - DSA von TestKey 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 GF9WvDLDFUJ6/ZH7+pgEz02hBCt6FZJilojN =08M9 -----END PGP PRIVATE KEY BLOCK----- PGPy-0.5.4/tests/testdata/signatures/000077500000000000000000000000001403641706600175055ustar00rootroot00000000000000PGPy-0.5.4/tests/testdata/signatures/aptapproval-test.key.asc000066400000000000000000000032471403641706600243000ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.4.11 (GNU/Linux) mQINBFD16Q4BEAC1rKU/BuA8mp2vReaJ5VlXGnO3E1mdOYbaIUH1FLhzaK284GRA VuasB1QJ75Uf+Ic5GV2H3Er3327qWIaWsZ5V0MPuoNbQmHuYfnZKzLP7qMzgCumR ZyRZGlHImLtuh5C8Mwcv1ycqYVfY7/cKrBlWBH9/nzcaFpIlyGM2DsOFSyEsKS8D z+BeWYbKUi44d1WhXdgHZOtfMMGORnCKH2oToJLDKNnkMUaBHxM2W08/YQauXsPq fXaiXLoC6x4hGHA8WjLO9vGxC0JsxNoyIa6Tobf7z5cOFOJZUiwcBtqRZFPNG/g+ bq2EK18V+Yy62kXgLWLqRCw/l5k9D1z6B+zMIFWaC1Xo9GGS9jryrYtUSv+QFm8W nu18FemOfJLV9o3yxgWhczjg1WI7jJLk69xkYF0KzgFmmK+AkLhGoVSyOJP1aIJT usTIcUyfru5+13o0TbjWC+uP47sE90rcJMGuUaPZyrL4vxZ8GRVGreOcc3MDtjkA kmsnUsUhnOQQr77Glfo0RhOS8tlt90ZBFz4Zx/6WRA61eRBP/ixacTcXzJci6+Y8 815xSMUP/+6+su/BF2/oY0FdxYzsf0Bgts7JI1NV3CHLZ9bPRe9t4xgss1IeCMgm sf5030g1DnXtRB23aALd1w0hD3sUHjRwc0LgSYfuhOef02d3wnFfgJ7YswARAQAB tEJUZXN0IFJlcG9zaXRvcnkgU2lnbmluZyBLZXkgKEtVUykgPHVzYy1rdXNAc2Vj dXJpdHlpbm5vdmF0aW9uLmNvbT6JAj4EEwECACgFAlD2Ju4CGy8FCRLMQDYGCwkI BwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEM5XB3TQ/cog+dcP/1LcxDYoosqef0cr CvL5uzCOLZkL2xR72WnG0FwJYxXEJISl2Iw43+JXDER8sthgwyRB4LZDn/s+VvNn 9cyoQZy8pOziG+7vGICLAGGdJ0nZeSpKb6ycvWRrjiqx1g51WdIEPOKQZzEQwukl MQNr8+jsF5X1wkcM9JuqZRNzemOgl1gISYAI+s12nYdcWWZ8gqIdyv+m0zKNVX+V trdBcFp7c9xHtjn89o5EHJvqODObNldMay+6ruv/fesdQsGE2GUpopa3rN7XT0i7 2f/FP9GmR7XhZE2T6KcBSONM9iMFfsPnH/gclUHucFUi9OyBwyrWKg30iQm1kooX 4jn2D/vsdSD2YDMDBM9RWna7V27YuIm2ypH7LATcFlOQ/5Eth0SdveUHwzjp2LJH kqIVUXKu0BggDaS8VUYMKaIy07uGhZrJhKgBKtJwRAcLhSmJkRc8W3xmqhl+26Gs IRrmV1axzYQ44reW6cB3jSJywN6F2Gl5zfl3EnaAiGO7jGV1obkLStaeG797Dkmd SRZtfK/r2olOpCNoXxwPEnPBCoxrbPwjtGIQd/cMdTLbLWyW+4qfPARrc6E1GE5W DfNkkKXF+6RkEK0Ly7eaESrtI9QTgSCpsD3MsmX0Gy1GbtPGcJrVGdf0L4PtBhws OIBR/v+FFd/U0ieW/CY+sHNGawR6 =GlOh -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/signatures/aptapproval-test.sig.asc000066400000000000000000000015041403641706600242640ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJSjoDnAAoJEM5XB3TQ/cogbSsQAKG0o4YjKW7q0ENUgAwzD7P9 /AkqWjqv0hXgJuFj6T0aQ3xuUr63qi5tu9Y1QsVty06Ku1JdujL1s4G5RfCsM5d1 rXLeuA1PH+oGl2hXHrnfq39rJNAzb21yqH0C73p7IKLQgdfIcuGmDyzzMkGExLX+ 1+ENMMgWskzceH/NSy/Yk4SXKPQijX89gq9WxpEQGGKY7sSkHQsYxVTe05Jrxy8I w7lFQBAokDd2TwHTVnTwDTi7Nu0iAkjMxhT9mnat096w5qKhEMLYr/9f2yHutA4U sgw2tPldZVUow2AfqKAID0s66VGFsPFh8IlUQBOpE7UbVOlN4ICHTFqvVXWH4sWM HM+ISCDQaBlmIb1SFTbf1QB9vQ+tf14XPQD92okQi/jE1JWd2tUO5AQneckSn5ed Usx1NbPoYdOuGahZImFiiTa32MeWz7bgg8kuoMw0jx+6y2Qnc6erG3nUJ/8tS1PJ dkaZbcyVJCRet2De+vTFYGecTjsnwguPIVSNera9DW2dlZtRLFj1ICVp34RwHqHi vhHYeG72sgg6piVFiXQOSgDD8M2C0rv1dBLZMtvmAyAnZwwuJciUPGungO9F9/NL EcpMIQHPHVLZjrxXvV0QH+GxHVc8qDRqcsc50IeU5Knq13oMS8NYMaj8xLbnvYpW z4ZuxJxGyyaeH/2RXy2Z =fL78 -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/signatures/aptapproval-test.subj000066400000000000000000000133701403641706600237040ustar00rootroot00000000000000Origin: Ubuntu Label: Ubuntu Repository Suite: precise Codename: precise Architectures: i386 Components: main multiverse restricted universe Description: Ubuntu Repository (precise) Date: Thu, 21 Nov 2013 21:53:43 UTC MD5Sum: fabf9a777017e93b4053f5cb47b78f13 1276805 main/binary-i386/Packages b67db03940f371d28be692171bda196c 199253 main/binary-i386/Packages.bz2 fde9d2ce1f6605132d298bf749b336d7 257210 main/binary-i386/Packages.gz 688272b125f7ac7112a7da79ce2635d3 5226 multiverse/binary-i386/Packages 9ea8297ede221cc2f99b7814de57229b 2125 multiverse/binary-i386/Packages.bz2 4d9e1849c52bdc2edcff06c0563a270c 1956 multiverse/binary-i386/Packages.gz 65fc97f86c432985c26d7a65688763ca 21749 restricted/binary-i386/Packages 7b476c0ebb26456305ca7c65a8d417f3 3793 restricted/binary-i386/Packages.bz2 40643b2e7c0ce29926c9a9a78a5317d8 3482 restricted/binary-i386/Packages.gz 4a77173861addf45f1b9e1a8769158cb 384498 universe/binary-i386/Packages ae6fcef0142ff5bd951b092f3652f1bb 68734 universe/binary-i386/Packages.bz2 65ab477573f7eead3cd6eb7d86ec4ede 86722 universe/binary-i386/Packages.gz SHA1: 40ff285fa016be39a674b774ca9c369efcf7c6f8 1276805 main/binary-i386/Packages 5a5d8e31e06f73fe524eeb6c2a5ea67c45abe3f5 199253 main/binary-i386/Packages.bz2 b842fde116612cae4d02d40ef8e9f0656ab90e73 257210 main/binary-i386/Packages.gz d5dacc424fb19689898250f4e7ebc2d3665161a7 5226 multiverse/binary-i386/Packages ba81e19d6c08e02caa27ad3a221812ad089d5ce1 2125 multiverse/binary-i386/Packages.bz2 6ab184c35d82635ada3a09299b9cac31adb78e4c 1956 multiverse/binary-i386/Packages.gz c16144c61fcee4243fcd0eafeab6fc0d030517f7 21749 restricted/binary-i386/Packages 4d796e52679ce0adbe9d2bcdc6a9545e1bd31c27 3793 restricted/binary-i386/Packages.bz2 f397def5d878b3af4c6e3682f9a3989479980ac1 3482 restricted/binary-i386/Packages.gz 06a7abc091ca3956ded56bc735b2d909b674d4db 384498 universe/binary-i386/Packages dbe8054ab19cba6cbe4b5ba117ebd5483efc7671 68734 universe/binary-i386/Packages.bz2 0d400a09c209b1ddcf1c720ec9516ab7c18a153c 86722 universe/binary-i386/Packages.gz SHA256: bb8e8648d5d51fa7eef9aa63fa55ddcf57792d3b87d2b9f62de944ec4fd47ea7 1276805 main/binary-i386/Packages 4258c08697a226a23ceb83adc1bc4465bd908e2e8eff67cb23c5902f8514e7df 199253 main/binary-i386/Packages.bz2 fa206038925dcd7f3c231b2314579549a29ece6e19dc7888467c07545c344602 257210 main/binary-i386/Packages.gz 779e6d6a8fbd4beee4ff34ca40eb445c79747a5e5d85c8664dc0df03aebeb774 5226 multiverse/binary-i386/Packages 3660636e8d43da231989f047fef63065053aacdb31f1720ae280e06c15776203 2125 multiverse/binary-i386/Packages.bz2 b83e86df352c2eef0df2204c57fe1eee7738c5c7a03159cbbaa96055773ef69e 1956 multiverse/binary-i386/Packages.gz 9f3d212f4c4ff545a84409983efd50c648c17348fc6b11ad13336f12842e9d3a 21749 restricted/binary-i386/Packages 3500e4ac6bd16c973f305e59f73b73658fb29b10313ead9710ad4c7f336f3ecd 3793 restricted/binary-i386/Packages.bz2 658516d3228258e6a8d67b90a0fb6e77775b91ed3cb3de2281b1135e12062406 3482 restricted/binary-i386/Packages.gz ddbdf17bcaced399af346d5992fe1474c57d9f0e31b997cff5b01d84cc18b5a7 384498 universe/binary-i386/Packages 5229ea954074611a174215c9e7c01e78c677d5e47c391219f76babddcd6d2e76 68734 universe/binary-i386/Packages.bz2 c7e8cbe58fc07e652e2140bb650b8232312cd3b2b96fe299086c2c92a886fd04 86722 universe/binary-i386/Packages.gz SHA512: f870f30b58ed3ee3854df0adf09623f7d65faafe62b70b05760a8fcd2add8d49a0a81f52702350b4e4ce52263a9ab4b9906fe1ddd2034de942ddbf4026cbfc2a 1276805 main/binary-i386/Packages 82c4090ce5fc175de7e491dab07d080d05295ca45625b7398ecf0668eba45d802ae7041be60829a391ce285bbab4f598b13f20f5a8f9c44f87db71607fb60c46 199253 main/binary-i386/Packages.bz2 4be892651cbb698a6385b41adb082a1cb88448842d8f87d912abd7970f739ad66c7a8461cc4533daec629dd11e62f9c1f359cab4b71f09d244b8737828bb97c9 257210 main/binary-i386/Packages.gz b30fddf5e001d6bb7051dfe79666dc43eee17bde055c928b036bd524e57b31aaf336f3355b31d93aed775ef5975dc903260f1d91c70f52348d13d786b650bbb5 5226 multiverse/binary-i386/Packages d4b26f000466f6455feca5754e4ac17f94988b239b6954c3f4bc864d68754e3c197c5679836e9d78ff8ac840070074e1bda9235ba8e0a4d23c4187d79e78ee50 2125 multiverse/binary-i386/Packages.bz2 8e7cdc56e8a5ead1e4da36587551b93e84cefc6d69797848187ec718e94386b295f5ca5bfb59ba172694c696c6c0429eaa5a903ea9ecaddb9dd2a96081a23b05 1956 multiverse/binary-i386/Packages.gz 02bbc01adbe48439f8823c54b3a7494180fb369fee457ca7f9bea771372473fae7b206de942c8837f2e9bf7c2722330ebe765fbb30f3ad3338cdcbc884ae2067 21749 restricted/binary-i386/Packages 619405fef99874d85009053cce9470f8b1270f120748b8de8cdc1723fe68955cdb209d0417311495ab638dad757f30a2287e0cff01bbb95f63c6343cd953fd2c 3793 restricted/binary-i386/Packages.bz2 c74348808899ab049aa84f36dde541b016eb3264dfdd66ee22ad1c6ae7cec8fe57fef9a226d6cc904d6892f8d649f880714f50ce73848b980d1401b0b99e7958 3482 restricted/binary-i386/Packages.gz 4f0e773e60f3ba1b56d7eb41d076a838694afca1511473c680e0716bf268c3dbcc0df6fbdfce9f71e3302d58af03246b0959701cdf6c8e0453243c965fca3f45 384498 universe/binary-i386/Packages 6a4dad6c4c01c20bcac4ddb4babb638254946decda6283e8eedefb7a1d5ef0141a7e0b0fd502d887851ec625124b5be9a73810b5d36a6f2525dc92ab4ee98383 68734 universe/binary-i386/Packages.bz2 583e7615dd24324502592a6c6d913220b315aafd0984310f92b749252347e470f045e581886977075ba41a40588f7ba83f9fb4da4c2b7a5b3a56094262822b71 86722 universe/binary-i386/Packages.gz PGPy-0.5.4/tests/testdata/signatures/debian-sid.key.asc000066400000000000000000000121721403641706600227660ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org 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 DHcut3Yey8o= =id4q -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/signatures/debian-sid.sig.asc000066400000000000000000000015041403641706600227550ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.12 (GNU/Linux) iQIcBAABCAAGBQJTYBKUAAoJEItIrWJGklVTFukQAM3zOcAjAiMFKBAtBmuJy6w1 VTKctRgQMYOJuLQxCM4y1RGlfoGyD9HiPRQXiHvkF4MHxi9+KtQCu247TXTlyl+N 8cHW2woZcsSrhMDJ1A7IeF7fDgRt3Tu2HnXd/qFxH3TJPtXZbaUnqKrRDFPwfBIO JAHVmdQz4m7TVOvuikthbbqnvXYL1/7KK4otCsteYkO2lQTEFARxb0YMHPo3bBep 3csmRrN94gTBIWLahOQncD+o9UFD1vrxuXTjqXgziNmYhsOiVHWlXAxydQ4vYznt O8yF2lnvVOQCeUOiTiavY1hoVL0gk42pMeNjMWLgH2016yKWVF4YlbWf2BP6oJJD zCNodUFWeY5iZKyK0J6fKQyB+S9tPAmNzaUXLzyRgHKjSAuXlGqAZg/jT9tbHBHa FwZ60+sbBsXLjF0PSKwVf+hnG8KPWr6vPWh255lXk+nrU+YxN9OD7dhI8abMsa++ lEPalDDc/jrzLkydaDF7mTAxy5DQciECHI8h9UeiTueaDtbxJERFPdx/xpQpFDty I620ImiEHoVycjLsA2cpu6GOwPj98zZPG249wmvUdt/2ISdbKx7fi6L4isv2F7f5 0mHKocGfBMLgQDP8V2r5aLoGkqduYo8jb1Ey96jmEEdb4TLfhGZgxwZTPxP/sFje 8CkMfPpGPDKhJNlHTGND =FO1m -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/signatures/debian-sid.subj000066400000000000000000006201151403641706600223760ustar00rootroot00000000000000Origin: Debian Label: Debian Suite: unstable Codename: sid Date: Tue, 29 Apr 2014 20:58:15 UTC Valid-Until: Tue, 06 May 2014 20:58:15 UTC Architectures: amd64 armel armhf hurd-i386 i386 kfreebsd-amd64 kfreebsd-i386 mips mipsel powerpc s390x sparc Components: main contrib non-free Description: Debian x.y Unstable - Not Released MD5Sum: 74f2f2544ee141b71adb4cf8db4949e7 29126161 Contents-amd64.gz 11d034bb9578d45897109d8031f30571 28753408 Contents-armel.gz 47ef807e6655550b970248098eb9c132 28485312 Contents-armhf.gz 95888b2b1e7d2ace6a733586eec9cd43 26796983 Contents-hurd-i386.gz 6197a52e0eee7d731c7999ed784a67cb 29331795 Contents-i386.gz ec42cf71d203858bf1f95db907c00830 27824917 Contents-kfreebsd-amd64.gz cad60860960bbc37fcac156f6a5c6831 27850902 Contents-kfreebsd-i386.gz 77547d8c0f3bd9bd2ae5628b8018ed5f 28457146 Contents-mips.gz cc8d4aff1bc6ce5fa30d89ea3a4986a1 28487260 Contents-mipsel.gz 4fb74cdc9b264aa2bc4edac4ad2cffd6 28813161 Contents-powerpc.gz a3f825d2a5fae576a00f53be90f42fe3 28252350 Contents-s390x.gz c74e43f2988a3a019f0a2bbfb9c5a824 28214513 Contents-sparc.gz 99a6714557d1b2c3d4a60d185aeecf00 7819 contrib/Contents-amd64.diff/Index c5602f36c81cca52df72dbe44aae5fa8 101661 contrib/Contents-amd64.gz 4c6b33102507808e6ec78eb28bf5fe9b 7819 contrib/Contents-armel.diff/Index a548ee7e842393b8a44a58920cd06261 84379 contrib/Contents-armel.gz 5bff91ad8b0bd21ddac52838837ac745 7819 contrib/Contents-armhf.diff/Index 4f08d2cf26fd73f5090872eee16f78c9 84201 contrib/Contents-armhf.gz a35ce922335bb46b6915d377d1a4c376 7819 contrib/Contents-hurd-i386.diff/Index ba652abfb6c46725e5048bdd654ed655 81453 contrib/Contents-hurd-i386.gz 6a1d6600e8a63aacf5ee18b770a34a76 7819 contrib/Contents-i386.diff/Index d730f1371634994fdb9689aee67bdcfa 100858 contrib/Contents-i386.gz 58a30bf2dcf0575228e64b9da7afbf6a 7819 contrib/Contents-kfreebsd-amd64.diff/Index 03b309b4278a694379fba333f51f0f02 84100 contrib/Contents-kfreebsd-amd64.gz 58a30bf2dcf0575228e64b9da7afbf6a 7819 contrib/Contents-kfreebsd-i386.diff/Index fe21fac8129e155221602e257d7311ab 84073 contrib/Contents-kfreebsd-i386.gz fe4906d09d50fc01dbe5ec5644efc383 7819 contrib/Contents-mips.diff/Index 6a5c1066a0277ea985a961630802bfc7 84846 contrib/Contents-mips.gz 5e3d01f006611feab4de4a1f5274c95d 7819 contrib/Contents-mipsel.diff/Index e4adaad3ef018e4889bb9b49ca85288e 84844 contrib/Contents-mipsel.gz bedeed3e7999706257d950a8348fa6b5 7819 contrib/Contents-powerpc.diff/Index b1ab4ea8b5f23dabdc90e862ebe007fd 84620 contrib/Contents-powerpc.gz 6745cf141a73c8d6b4cf498c1863581e 7819 contrib/Contents-s390x.diff/Index da5b795a60a9d40e2c11c9a78ebdfeca 84290 contrib/Contents-s390x.gz 089f5bd27d55954ce6857152398de865 320817 contrib/Contents-source.gz da14235b0273694ed68708171c6a73e9 7819 contrib/Contents-sparc.diff/Index f04536eaf732deabc9bcbee1ee295f47 84617 contrib/Contents-sparc.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-amd64.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-armel.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-armhf.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-hurd-i386.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-i386.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-kfreebsd-amd64.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-kfreebsd-i386.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-mips.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-mipsel.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-powerpc.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-s390x.gz c0e7f37cdcb2125588ecfbe574a47206 714 contrib/Contents-udeb-sparc.gz 46cee68fa52d0639d8c0b5e55aa58eb8 93025 contrib/binary-all/Packages 196d8761c4bc46ea52035dfab40a0246 29432 contrib/binary-all/Packages.gz efde36583b6bc5ccbe131ec5adeadc32 25984 contrib/binary-all/Packages.xz 291cb816ec29f1afe0b07c0fcb6bbd89 84 contrib/binary-all/Release 14eaf9f436073e84ac0801bdf64445cf 217977 contrib/binary-amd64/Packages 8925bcc780e820b5906ac7b5fceb1192 7819 contrib/binary-amd64/Packages.diff/Index 014506d593130093d63d6d633b9e42f0 64629 contrib/binary-amd64/Packages.gz 448183342a7a2d567c1f1e3043378a37 54404 contrib/binary-amd64/Packages.xz a5b906a87a8e63e489f021d349a93cf1 86 contrib/binary-amd64/Release 2ae72b2756a8212bb857220228e5314f 157509 contrib/binary-armel/Packages 9441ed53f34c7f6c539e39ff9a2af32b 7819 contrib/binary-armel/Packages.diff/Index 9a96482634e186f662ed74d43baca2b5 48157 contrib/binary-armel/Packages.gz a3850ce1c3309810776c2e58d8268921 41292 contrib/binary-armel/Packages.xz e8cf3b323444ab6cfd831071847804fc 86 contrib/binary-armel/Release 716a58faaf242fbe7805d32572ab7993 160324 contrib/binary-armhf/Packages c834b09f7ede7b732e3fb06ba786e314 7819 contrib/binary-armhf/Packages.diff/Index 323f38c0c11ec576d1211cd4b4dd27b3 48893 contrib/binary-armhf/Packages.gz 635e6cb82c19c457023b3fbc57e1f392 41736 contrib/binary-armhf/Packages.xz 96bef4b38c209bd0fb1f187315f65291 86 contrib/binary-armhf/Release 869ce56546d575dc4f8c28e0fa8096a4 142314 contrib/binary-hurd-i386/Packages 2c8ec0bdc6948d9a4b09c573ce00c7ba 7819 contrib/binary-hurd-i386/Packages.diff/Index 6bb8adc59eedc5de37b1fb94bb2dc0d2 44061 contrib/binary-hurd-i386/Packages.gz 4f698a4800f45ffadfd6631f01c4a1d4 37744 contrib/binary-hurd-i386/Packages.xz 8fd8b95dec7040f67cde27bf8ef293e2 90 contrib/binary-hurd-i386/Release 0acb338c8afaf800aa105fa51b9f7393 215343 contrib/binary-i386/Packages 89ec27ee417caa87b8bb1eaf58b3d676 7819 contrib/binary-i386/Packages.diff/Index b1701a72a58a225af3f5c7b932ca60b0 64028 contrib/binary-i386/Packages.gz 9c1503162316a1a56a2016435a3d6bf0 53760 contrib/binary-i386/Packages.xz 1e59b8e041d7a6de56d74eba0393dc45 85 contrib/binary-i386/Release a523f8992c968da82e4bb3fe2aad47e7 159685 contrib/binary-kfreebsd-amd64/Packages becd420198f00c7fab7fa4737e0fd012 7819 contrib/binary-kfreebsd-amd64/Packages.diff/Index c028d9b7a5c10c656e266a8052ca2345 47934 contrib/binary-kfreebsd-amd64/Packages.gz 9e4418a08ab98ddfdd3ccce556591ae6 41212 contrib/binary-kfreebsd-amd64/Packages.xz ebfba99ae6f0e51ff57fd5842b230c97 95 contrib/binary-kfreebsd-amd64/Release f64f581c4a5145447ca3dc3e4c1e0b40 159525 contrib/binary-kfreebsd-i386/Packages f31ecb80ef9a8272bd50b55c0c3966dd 7819 contrib/binary-kfreebsd-i386/Packages.diff/Index e66b689d6b2ffc6447ad54f13c211c05 48140 contrib/binary-kfreebsd-i386/Packages.gz 82b43df622a9ac2c050b7b6a465833ee 41220 contrib/binary-kfreebsd-i386/Packages.xz 5e58ccd691631209da5853bc83d468a9 94 contrib/binary-kfreebsd-i386/Release db17250fae45cf28ea41e5e1588bce23 159132 contrib/binary-mips/Packages bec1c1c95ecc822d5141f345b87d1f10 7819 contrib/binary-mips/Packages.diff/Index ec862c641314218d4e48ce0860234ac1 48921 contrib/binary-mips/Packages.gz 92778e15b3e6aac7d144f4171c43cd61 41708 contrib/binary-mips/Packages.xz f3181e8319b52c16bbf941cf5124e476 85 contrib/binary-mips/Release e480d9b0cc0826d06be94fe03bf77795 159444 contrib/binary-mipsel/Packages fc1d0ca13767fda87941b8c4e2daa98c 7819 contrib/binary-mipsel/Packages.diff/Index 3b4a236166ebc742af4610d4f040295c 48759 contrib/binary-mipsel/Packages.gz 371265756ca67b2373de0436ca5a33bb 41760 contrib/binary-mipsel/Packages.xz f8725a668668d6f7b7031da9d912f969 87 contrib/binary-mipsel/Release 64d3c423eb6de88c3831e6c026ffc159 157611 contrib/binary-powerpc/Packages 5a7a4c2a8aaf792d9bd89acb74561de9 7819 contrib/binary-powerpc/Packages.diff/Index 5ecc292e18cd61b0a496a3d8d895ab99 48455 contrib/binary-powerpc/Packages.gz fc1dddf03f921ec0a1975b3d3e437be3 41396 contrib/binary-powerpc/Packages.xz 146c44380d5a06bb31557814a9c68bcd 88 contrib/binary-powerpc/Release fbc7798bd5550c410f4e8dec280358ab 156138 contrib/binary-s390x/Packages c834b09f7ede7b732e3fb06ba786e314 7819 contrib/binary-s390x/Packages.diff/Index 1f2cc4145674e1668583036e66496f5c 47760 contrib/binary-s390x/Packages.gz fef85b69909febc289ce1d9436e6e030 40900 contrib/binary-s390x/Packages.xz 86bb42ad1cb29064781e6e730ba5aa56 86 contrib/binary-s390x/Release 3fb74f0e0d54dca8cc5bc58acbf2b8d5 157282 contrib/binary-sparc/Packages 06b63fb0941d1db9540563357642db35 7819 contrib/binary-sparc/Packages.diff/Index bf22b79eef716bd26cd03fd8105b80b0 48168 contrib/binary-sparc/Packages.gz 34d7cfce3fb6ade3ba6ea7ba459126bd 41228 contrib/binary-sparc/Packages.xz 24dd07b487e6c38799e5b1ecb8923faf 86 contrib/binary-sparc/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-all/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-all/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-all/Packages.xz 291cb816ec29f1afe0b07c0fcb6bbd89 84 contrib/debian-installer/binary-all/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-amd64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-amd64/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-amd64/Packages.xz a5b906a87a8e63e489f021d349a93cf1 86 contrib/debian-installer/binary-amd64/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-armel/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-armel/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-armel/Packages.xz e8cf3b323444ab6cfd831071847804fc 86 contrib/debian-installer/binary-armel/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-armhf/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-armhf/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-armhf/Packages.xz 96bef4b38c209bd0fb1f187315f65291 86 contrib/debian-installer/binary-armhf/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-hurd-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-hurd-i386/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-hurd-i386/Packages.xz 8fd8b95dec7040f67cde27bf8ef293e2 90 contrib/debian-installer/binary-hurd-i386/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-i386/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-i386/Packages.xz 1e59b8e041d7a6de56d74eba0393dc45 85 contrib/debian-installer/binary-i386/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-kfreebsd-amd64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-kfreebsd-amd64/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-kfreebsd-amd64/Packages.xz ebfba99ae6f0e51ff57fd5842b230c97 95 contrib/debian-installer/binary-kfreebsd-amd64/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-kfreebsd-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-kfreebsd-i386/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-kfreebsd-i386/Packages.xz 5e58ccd691631209da5853bc83d468a9 94 contrib/debian-installer/binary-kfreebsd-i386/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-mips/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-mips/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-mips/Packages.xz f3181e8319b52c16bbf941cf5124e476 85 contrib/debian-installer/binary-mips/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-mipsel/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-mipsel/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-mipsel/Packages.xz f8725a668668d6f7b7031da9d912f969 87 contrib/debian-installer/binary-mipsel/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-powerpc/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-powerpc/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-powerpc/Packages.xz 146c44380d5a06bb31557814a9c68bcd 88 contrib/debian-installer/binary-powerpc/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-s390x/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-s390x/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-s390x/Packages.xz 86bb42ad1cb29064781e6e730ba5aa56 86 contrib/debian-installer/binary-s390x/Release d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-sparc/Packages 4a4dd3598707603b3f76a2378a4504aa 20 contrib/debian-installer/binary-sparc/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 contrib/debian-installer/binary-sparc/Packages.xz 24dd07b487e6c38799e5b1ecb8923faf 86 contrib/debian-installer/binary-sparc/Release ede95049aa2835f145e25376db670df9 163386 contrib/i18n/Translation-en fffce457870e6886b6ff87c9286ffadc 42412 contrib/i18n/Translation-en.bz2 62af9e6054f09ac4fb36d73f4ba34590 7819 contrib/i18n/Translation-en.diff/Index 82fb19d5abc58994d389b90bc39f449d 87 contrib/source/Release c29b89da6b6accb4a758f51519aeaf60 214833 contrib/source/Sources 54818ec74faa4c463df0f8e0a5a600e8 7819 contrib/source/Sources.diff/Index 2a80effa7b08a28d4325415c1c198c05 65954 contrib/source/Sources.gz 6be16e064eaa338080093bef52849429 56404 contrib/source/Sources.xz 726c64ebc780ba37ee132a0bbdff11e5 7933 main/Contents-amd64.diff/Index 74f2f2544ee141b71adb4cf8db4949e7 29126161 main/Contents-amd64.gz 138e428bad3899c9d585aafb64ada29d 7933 main/Contents-armel.diff/Index 11d034bb9578d45897109d8031f30571 28753408 main/Contents-armel.gz 6e196768d87d8cdf2f2a3dd145713bb7 7933 main/Contents-armhf.diff/Index 47ef807e6655550b970248098eb9c132 28485312 main/Contents-armhf.gz 77b22591308182db41094592f66cd138 7933 main/Contents-hurd-i386.diff/Index 95888b2b1e7d2ace6a733586eec9cd43 26796983 main/Contents-hurd-i386.gz d631907fcf1d34d766ca08d51cb61b0f 7933 main/Contents-i386.diff/Index 6197a52e0eee7d731c7999ed784a67cb 29331795 main/Contents-i386.gz 23d91f8e78275fc7ba9f314346c20276 7933 main/Contents-kfreebsd-amd64.diff/Index ec42cf71d203858bf1f95db907c00830 27824917 main/Contents-kfreebsd-amd64.gz 079bf934adefbddd8b3ff34de5917adc 7933 main/Contents-kfreebsd-i386.diff/Index cad60860960bbc37fcac156f6a5c6831 27850902 main/Contents-kfreebsd-i386.gz 19624470d48bd7ebe8fc89e03e566826 7933 main/Contents-mips.diff/Index 77547d8c0f3bd9bd2ae5628b8018ed5f 28457146 main/Contents-mips.gz f9da20eb84f548948b8ebce675b51b4f 7933 main/Contents-mipsel.diff/Index cc8d4aff1bc6ce5fa30d89ea3a4986a1 28487260 main/Contents-mipsel.gz 8bdbe19df903d944140c1ef60d3a64c7 7933 main/Contents-powerpc.diff/Index 4fb74cdc9b264aa2bc4edac4ad2cffd6 28813161 main/Contents-powerpc.gz 6e196768d87d8cdf2f2a3dd145713bb7 7933 main/Contents-s390x.diff/Index a3f825d2a5fae576a00f53be90f42fe3 28252350 main/Contents-s390x.gz 09fe88aeb68c95b5191d43fd71b5d613 42201895 main/Contents-source.gz 252a53b7973ac03e056876efd0912458 7933 main/Contents-sparc.diff/Index c74e43f2988a3a019f0a2bbfb9c5a824 28214513 main/Contents-sparc.gz 647d3d3ed7fdb44f3d92131138a104b2 34470 main/Contents-udeb-amd64.gz 4437aa84b3d80deeae5969d070a21638 30168 main/Contents-udeb-armel.gz d230c30dbf808891cf8aa31c0dcd2ff9 26977 main/Contents-udeb-armhf.gz 6f7816134b70c6e0b66b051a208456e9 20196 main/Contents-udeb-hurd-i386.gz ab22aaadb6a640f431f4830add06a65b 47415 main/Contents-udeb-i386.gz b9d3dcea8461a534294c64117bc208d7 22694 main/Contents-udeb-kfreebsd-amd64.gz 4a6dfc198a29ac6aad076f1f7c92e3a4 22764 main/Contents-udeb-kfreebsd-i386.gz 0dc90e4a294bf86f8246fbdd2af9eefc 26868 main/Contents-udeb-mips.gz b9f893352c925ea4b14c76654002e8bd 27496 main/Contents-udeb-mipsel.gz 0e6ff224edec118d5aa95b51f402bebb 40941 main/Contents-udeb-powerpc.gz 9646278c443e4b38c4a4ddfee472b68f 23637 main/Contents-udeb-s390x.gz 9e2003fb4ea534453588f0bccc545f85 25142 main/Contents-udeb-sparc.gz 45a1480a589e84fef46c83bb7da25658 14618792 main/binary-all/Packages d85a9613ef1812df8d3e3356c506049e 3969765 main/binary-all/Packages.gz 2db7d8d939db4edb364e00634987eb08 3028620 main/binary-all/Packages.xz 2f1779097b77b7c96c836ecf12889a54 81 main/binary-all/Release 3d50db777cc1dd61b1f83f76e43c6d94 33618877 main/binary-amd64/Packages 29f5275565296c3080fbdedf7b603f39 7876 main/binary-amd64/Packages.diff/Index 207e6553646731d4c3edd27ecb1fa39e 8985791 main/binary-amd64/Packages.gz 6915d27a65e1a39d445f92172138298f 6724080 main/binary-amd64/Packages.xz 6bc541e5c4ffa6ac8b2ade2acd75d41b 83 main/binary-amd64/Release 2a9c1ba815db45d271ecd925955959c5 32806207 main/binary-armel/Packages c90f534995cf71c4130eb4f3fa7fb91b 7876 main/binary-armel/Packages.diff/Index 3020435b32bdf55b1e399f27f954d13d 8780431 main/binary-armel/Packages.gz f78dcea0d7f03bea44217f42d40ad774 6573736 main/binary-armel/Packages.xz 68a847c354775ffdde15f4f9399397d4 83 main/binary-armel/Release 6d87df84c6ebb39dcec78465d500ae84 32702650 main/binary-armhf/Packages 638d5c6079c9a0282aa168074bbd337b 7876 main/binary-armhf/Packages.diff/Index 319fedd9fc7a778828954d37986a8d85 8752490 main/binary-armhf/Packages.gz 01b68fe720196e15f607e3c8f079f6cf 6553496 main/binary-armhf/Packages.xz b4cfe692f36d87052a6a66579b5e252c 83 main/binary-armhf/Release d9ddbff6b5770f05a06200b58f729ca1 29457485 main/binary-hurd-i386/Packages 2ab8d7217bfdbe0750423dd6b0652f81 7876 main/binary-hurd-i386/Packages.diff/Index 6af1d400fcd768627fc2690b926fe29b 7820791 main/binary-hurd-i386/Packages.gz 20c9bc4fe32109ec6e76065c65ca7e5e 5871368 main/binary-hurd-i386/Packages.xz ede8470befdc90ec9ad86b4b264109fd 87 main/binary-hurd-i386/Release 5362e0d1ed2062256c09883b4a51fd9e 33606129 main/binary-i386/Packages e613419be40324b4a372c85c68469c24 7876 main/binary-i386/Packages.diff/Index 338ded2ec818099a05eefb02bb7b7099 8997921 main/binary-i386/Packages.gz 0b13c77cc2d28439b7aab69779137205 6732360 main/binary-i386/Packages.xz 91b92c901d0ab259eb0b9b7d8812351d 82 main/binary-i386/Release 2989a4e9ff396d78815e4d2729b08694 31615279 main/binary-kfreebsd-amd64/Packages 70139b2c9abb75aa490295a43bd1ad96 7876 main/binary-kfreebsd-amd64/Packages.diff/Index dbeeaa48d49b2b649cfbe9ce00ad8daa 8337837 main/binary-kfreebsd-amd64/Packages.gz 537759a23d9df892ecd52af21b7a62a6 6249852 main/binary-kfreebsd-amd64/Packages.xz 8b47e4a3fde41e5dd87d641fc07e47d1 92 main/binary-kfreebsd-amd64/Release 165a579360820026f88cd7b84763ecf1 31551588 main/binary-kfreebsd-i386/Packages 80143b16f5363d0b41e36e07434ceed3 7876 main/binary-kfreebsd-i386/Packages.diff/Index 12d25d7dbfeefad65400379088e389fe 8332623 main/binary-kfreebsd-i386/Packages.gz d84065b8e75336b01f3c38237cd47970 6247780 main/binary-kfreebsd-i386/Packages.xz ee7346b51445b11247574b193f6b5095 91 main/binary-kfreebsd-i386/Release deef276f682fadaa8b698b6797ebad16 32480079 main/binary-mips/Packages 88b6e5dc8c322f7cbc78a3fdc2f87923 7876 main/binary-mips/Packages.diff/Index 9894ccf0baae85525bca101c43b69d30 8716064 main/binary-mips/Packages.gz fb728ffc6e96a4ec9296fbf24020ad46 6524920 main/binary-mips/Packages.xz dc87b78e01ac83f1381f8480d5683c7b 82 main/binary-mips/Release b57367e5b46cafa92f6259da58af08d3 32596356 main/binary-mipsel/Packages 73515e4d9aa103161f99d52e6847fff5 7876 main/binary-mipsel/Packages.diff/Index 3dd2e68b4a6065dc067739f7e99b47ab 8728556 main/binary-mipsel/Packages.gz a18e3a3c3bb3dd801613534a9de3b60c 6535216 main/binary-mipsel/Packages.xz 247dde42ef2ac217ef4943d59d36cb54 84 main/binary-mipsel/Release f6b7af82e0040a667fe35e05e4a12a68 33154230 main/binary-powerpc/Packages 7ca9a0d6235c7dcef4d3c42db19b3ce1 7876 main/binary-powerpc/Packages.diff/Index 5800451c572ce61e8ae391201a15d03f 8848733 main/binary-powerpc/Packages.gz 6bac44457f8dbbd351c5660e5c5f3591 6623544 main/binary-powerpc/Packages.xz 2d04da76b15dd2caa4e2915dd483650b 85 main/binary-powerpc/Release f2605a537907da33b287d4573acd9d84 32297598 main/binary-s390x/Packages 638d5c6079c9a0282aa168074bbd337b 7876 main/binary-s390x/Packages.diff/Index b97bb2ebdff8c35646a53c73aa047d6a 8657047 main/binary-s390x/Packages.gz c6e9e998a6269dd43d2f275c2d1a132f 6481076 main/binary-s390x/Packages.xz fad0e44465977dc69a375c8d813ee076 83 main/binary-s390x/Release 268fc73ad72910ff75dfc5d8e8302c56 32390467 main/binary-sparc/Packages e6cf8db141aa70797416c78a525afe26 7876 main/binary-sparc/Packages.diff/Index 6742c71cd313659f6632b367d1edc612 8675573 main/binary-sparc/Packages.gz d0458c4dfb0f38dd493a313904fdf742 6495944 main/binary-sparc/Packages.xz 97bf8eee640651cab4effdf2b71b36fe 83 main/binary-sparc/Release 9adbf089cf5221b0725cd301be105c0d 71965 main/debian-installer/binary-all/Packages c028234ddce95cbf827bab96996c19bc 20810 main/debian-installer/binary-all/Packages.gz e19bf647b5ac2b281ea80a6a28591f3d 18100 main/debian-installer/binary-all/Packages.xz 2f1779097b77b7c96c836ecf12889a54 81 main/debian-installer/binary-all/Release 2215f5a6ca885d90f1556163590f2cb5 271101 main/debian-installer/binary-amd64/Packages 8c4dbf1845d68a36c74b3c27d69dbd57 73559 main/debian-installer/binary-amd64/Packages.gz f2a8d4b0103b1f5f6f723b723e803272 62096 main/debian-installer/binary-amd64/Packages.xz 6bc541e5c4ffa6ac8b2ade2acd75d41b 83 main/debian-installer/binary-amd64/Release ad1dab43c4b5d2947f921b2e44466aa2 327884 main/debian-installer/binary-armel/Packages d5adea6f4d656f859f30bd9b6968cf12 82972 main/debian-installer/binary-armel/Packages.gz 55114ebe6e56ad0c85040411ff58c683 69496 main/debian-installer/binary-armel/Packages.xz 68a847c354775ffdde15f4f9399397d4 83 main/debian-installer/binary-armel/Release 5a631c4b5df82891f9743898ff516c60 215371 main/debian-installer/binary-armhf/Packages 884f557cb4c40fc403ef12cdf695d1be 62714 main/debian-installer/binary-armhf/Packages.gz 048f581e7b6a3474a302d34756b5528c 52924 main/debian-installer/binary-armhf/Packages.xz b4cfe692f36d87052a6a66579b5e252c 83 main/debian-installer/binary-armhf/Release 298bbd7dc5e7b9e06003b9f5db6f68cd 164280 main/debian-installer/binary-hurd-i386/Packages 3c4cafdec1caea8716baaffa812ee8b5 48130 main/debian-installer/binary-hurd-i386/Packages.gz 6b81fbf68cfedde4340a2852ffdd60fc 40652 main/debian-installer/binary-hurd-i386/Packages.xz ede8470befdc90ec9ad86b4b264109fd 87 main/debian-installer/binary-hurd-i386/Release 5d3531895f094a849cbb629681c1542f 345491 main/debian-installer/binary-i386/Packages 769ba85829787781e02b084d1e14c133 86948 main/debian-installer/binary-i386/Packages.gz dd282c1712ecb0cd7a125aa921a0ed79 73012 main/debian-installer/binary-i386/Packages.xz 91b92c901d0ab259eb0b9b7d8812351d 82 main/debian-installer/binary-i386/Release 7053698a9bb6c36d098c27ed21a012e4 225819 main/debian-installer/binary-kfreebsd-amd64/Packages 9ee43a0455ad27b62b6c080f14f69f85 61365 main/debian-installer/binary-kfreebsd-amd64/Packages.gz 9e915d1660d7d1f3eb58ebe43b0be140 51708 main/debian-installer/binary-kfreebsd-amd64/Packages.xz 8b47e4a3fde41e5dd87d641fc07e47d1 92 main/debian-installer/binary-kfreebsd-amd64/Release 929d3fe35cf0d3eef7b7cf7dfd2aa678 224725 main/debian-installer/binary-kfreebsd-i386/Packages f0667a45effabc351a5365dc042fb793 61102 main/debian-installer/binary-kfreebsd-i386/Packages.gz 0d12bdaa80edb68b8b99d6335a57506e 51660 main/debian-installer/binary-kfreebsd-i386/Packages.xz ee7346b51445b11247574b193f6b5095 91 main/debian-installer/binary-kfreebsd-i386/Release 5d4841c8196161828370a12a1d4f85c8 271887 main/debian-installer/binary-mips/Packages f859e86bd017b3af9d51afff457145fa 72939 main/debian-installer/binary-mips/Packages.gz a040d0b7ee73febbec5811d67cd3aad5 61176 main/debian-installer/binary-mips/Packages.xz dc87b78e01ac83f1381f8480d5683c7b 82 main/debian-installer/binary-mips/Release 6372c35218bd4f87e368a7c5f9dff228 268044 main/debian-installer/binary-mipsel/Packages 6b01cfefc39eefc73223891cc4b5b3d4 72122 main/debian-installer/binary-mipsel/Packages.gz 2698c077af076b24fc9f04188e5922a0 60384 main/debian-installer/binary-mipsel/Packages.xz 247dde42ef2ac217ef4943d59d36cb54 84 main/debian-installer/binary-mipsel/Release 20930ce99d809fa3efefd174d351d602 326190 main/debian-installer/binary-powerpc/Packages 2c236e5e10fae7b6431e32f940db97a0 83151 main/debian-installer/binary-powerpc/Packages.gz 4177bc9c07704b3d4401681359ff40b4 69520 main/debian-installer/binary-powerpc/Packages.xz 2d04da76b15dd2caa4e2915dd483650b 85 main/debian-installer/binary-powerpc/Release b6b4c90e717428752dc7369d1569232c 211381 main/debian-installer/binary-s390x/Packages 36c9976c82ea3d007bcc33b3073d8664 61216 main/debian-installer/binary-s390x/Packages.gz 51efb96c8523db349c79b19c80fbe989 51472 main/debian-installer/binary-s390x/Packages.xz fad0e44465977dc69a375c8d813ee076 83 main/debian-installer/binary-s390x/Release f29096e201f8cad00a352d2a21a4647f 211987 main/debian-installer/binary-sparc/Packages 9d49e4debdf3f0c583f3d13c3fd53ec5 61792 main/debian-installer/binary-sparc/Packages.gz 4ef0585a25108cf523225d303fe377dd 52084 main/debian-installer/binary-sparc/Packages.xz 97bf8eee640651cab4effdf2b71b36fe 83 main/debian-installer/binary-sparc/Release e4c61ab05a71b235512c8534e1058b3a 10212 main/i18n/Translation-ca cb4d80ba741853ac67452065ba2776d4 3986 main/i18n/Translation-ca.bz2 ec7d74d4eaf529204968a00a42719e42 3265 main/i18n/Translation-ca.diff/Index efbf65468d2bad24880d136fe916a606 2083334 main/i18n/Translation-cs da877e1feed6f3306098262246f44a49 541607 main/i18n/Translation-cs.bz2 1c15aa20512b579fed58c2d40b8e2d70 7819 main/i18n/Translation-cs.diff/Index 92ea305b66d92514a90f379e0791f11f 10917248 main/i18n/Translation-da 4580fc2ec572819c60d25bec4ad873d3 2381081 main/i18n/Translation-da.bz2 34b96b8486daf62d722161c3e60038f1 7876 main/i18n/Translation-da.diff/Index 17bd93fd9c79625dac6a6a76c8ced340 7811636 main/i18n/Translation-de e6c4c504fed24d630f6e73541c8b1ba8 1783651 main/i18n/Translation-de.bz2 70a6e0df09e47d05a67a20a146f0771f 7819 main/i18n/Translation-de.diff/Index a344219bf0eec9139d5270017ecfceee 1347 main/i18n/Translation-de_DE 0fe0725f74bb5249f15f30ce965142d5 830 main/i18n/Translation-de_DE.bz2 c26d1f5d454d59a734435115a463bc5e 8287 main/i18n/Translation-el a2e3d718b49885932660c9c5dbdc0570 1896 main/i18n/Translation-el.bz2 38addf3fd4cc2396148d88157910d478 643 main/i18n/Translation-el.diff/Index 3c0860e0b23bb82f08d89d24f394a04e 22533282 main/i18n/Translation-en 53af49257c5aa5757c89cce99a3146dc 4576178 main/i18n/Translation-en.bz2 646db4187c8920581f55e0e88a39c406 7876 main/i18n/Translation-en.diff/Index 4c0b9e67121c4d5dddc059b2ef62070e 1504 main/i18n/Translation-eo 71f9620424a58e78b636066add295008 811 main/i18n/Translation-eo.bz2 d7a7fe0990c60411dc7c544f281d7287 781 main/i18n/Translation-eo.diff/Index 60da7562555161246b3c840e3698b837 1356430 main/i18n/Translation-es 73692e1e79f6c5351975005d5d8be776 327604 main/i18n/Translation-es.bz2 e675a3957626228f2f21ee659b47c5c8 7819 main/i18n/Translation-es.diff/Index 07e260527919f0c1e5f18508246e099c 17600 main/i18n/Translation-eu 43774685c2cd68f6fe1a3ba20e34f84c 6545 main/i18n/Translation-eu.bz2 7155b5f4da0039d5f338277b3a9cbace 6163 main/i18n/Translation-eu.diff/Index 649766df7c6afc5e94f88e13c3e014b6 420323 main/i18n/Translation-fi 0e6085d2175d6e5a4c2dc500eb0a5539 115357 main/i18n/Translation-fi.bz2 e0ea99df9bf133b975bdcfbce9b65fbf 7819 main/i18n/Translation-fi.diff/Index b304d4dee8db6a185a766ea47e661c63 3325423 main/i18n/Translation-fr a676219c0120381009e893a71040fee3 742555 main/i18n/Translation-fr.bz2 c6999e87d079a93d06d71f06b1347704 7819 main/i18n/Translation-fr.diff/Index 197b1862f7be2fb6dcbf6e715b173cd8 16814 main/i18n/Translation-hr ce6ca7ce76f0b9327ff243bf2b94c438 6426 main/i18n/Translation-hr.bz2 eee47e7f129cda3a3c2bb4f98b37886b 4645 main/i18n/Translation-hr.diff/Index f344311f4a300a87d6b09db12094d596 110436 main/i18n/Translation-hu e418e52393b361b3f397e339a8127d8d 35714 main/i18n/Translation-hu.bz2 69170fe7c7d7a2a434da6cd8e5953009 7819 main/i18n/Translation-hu.diff/Index 34ec59df8bca0339a18f33e475ec9965 7753 main/i18n/Translation-id c1adb75e39ecbdc6eadd353d22b47f7d 3093 main/i18n/Translation-id.bz2 529b06b92bfcd84fc9316899cbf8f934 3127 main/i18n/Translation-id.diff/Index 2e3ebfbdc1564ad67f50ff7c529876ff 15963337 main/i18n/Translation-it 3a418006b066762fbf11912ba2894be9 3236630 main/i18n/Translation-it.bz2 d517191316d1c2cdb65d636be5b0f633 7876 main/i18n/Translation-it.diff/Index 1cf467bf13c7511aeb24d67eedeb9820 4326439 main/i18n/Translation-ja f6b67743e1cc67ffe533a67357d12f59 795115 main/i18n/Translation-ja.bz2 13fe035bf0f2278e440388b0db2d28e1 7819 main/i18n/Translation-ja.diff/Index f85e8e6ca13ec6a1c206c1906bae3e73 19391 main/i18n/Translation-km 6612d0ae8b0c0770c1901e60dfced286 3611 main/i18n/Translation-km.bz2 a04eb9c06c94deaebd72213c63f73300 3541 main/i18n/Translation-km.diff/Index 9483c88f38ec8eba890c754a94f976b6 466233 main/i18n/Translation-ko 10ee0c04a4e0926852ff7759889972c1 108418 main/i18n/Translation-ko.bz2 a76531f4d7d17d8e592118b1d2d41ad1 7819 main/i18n/Translation-ko.diff/Index d41d8cd98f00b204e9800998ecf8427e 0 main/i18n/Translation-ml 4059d198768f9f8dc9372dc1c54bc3c3 14 main/i18n/Translation-ml.bz2 5676b1dbf1afed1dfd2ed8c4d87d6f8e 2325 main/i18n/Translation-nb be1e645de35839db0778d87b8e903e43 1302 main/i18n/Translation-nb.bz2 5c0a16a28b4dea0130acd4c1c1804fd7 367 main/i18n/Translation-nb.diff/Index 500fbed9f4b657c75d3b0cae17ed2d17 303930 main/i18n/Translation-nl 8b5a2e13ee0d6309d917016edb1fb175 82529 main/i18n/Translation-nl.bz2 728b39a4ab6df53a71cafdded0201a8f 7819 main/i18n/Translation-nl.diff/Index 05e509bc4411a6163b904a35d372a11a 2529869 main/i18n/Translation-pl 2a7a484093fe7735a8dfe8c1d3fe9be8 572467 main/i18n/Translation-pl.bz2 4a36b3f00191a180fd8f2af5cd8c241c 7819 main/i18n/Translation-pl.diff/Index 12fb4dee35e1565c3e851d1dc35ee24b 1862609 main/i18n/Translation-pt e39f75649d070a8de4531f049e33add7 453214 main/i18n/Translation-pt.bz2 ac3a5550eb8ddeb9185b169f61f1c44a 7819 main/i18n/Translation-pt.diff/Index c3db4ac286a6c4765a970628a14c0afa 3043569 main/i18n/Translation-pt_BR 6147b5df0cbe549bdd48ce362db33e53 734688 main/i18n/Translation-pt_BR.bz2 9e4b76bbba3127fcd9ec8b8c891e9454 7819 main/i18n/Translation-pt_BR.diff/Index 9574eddfdb6ee4fa59d2cf7e74a63aa3 2949 main/i18n/Translation-ro 82c63f5ea9cfd275bea9b476f34b6653 1463 main/i18n/Translation-ro.bz2 3f6b680a0b24b193a3f1f67bbab8db77 1195 main/i18n/Translation-ro.diff/Index 79372fbd39705a3af9670fd33e9b905a 2563200 main/i18n/Translation-ru 34fa5478e86212edb4fb7fc406a89ae2 420970 main/i18n/Translation-ru.bz2 c022c6f5c2893d6595927d2be073ce71 7819 main/i18n/Translation-ru.diff/Index 0308b61d28d33b62ce395bb2a2c92eb0 1804527 main/i18n/Translation-sk 5ff66385370fcdc7c26a75c5b32f0a2b 427527 main/i18n/Translation-sk.bz2 57b4ab4969fb0d6ea1493fd833e6ad47 7819 main/i18n/Translation-sk.diff/Index 205286da06ac664b2d3800228458125d 403940 main/i18n/Translation-sr 631eb6b872a55bf9c1c2cb9c476732f2 71417 main/i18n/Translation-sr.bz2 f72113ebef0c93f9291956cb1149a948 7819 main/i18n/Translation-sr.diff/Index c10923e93b58a51c6619fd52879b4ca7 139255 main/i18n/Translation-sv 42e6c29d71cbab5ec96e42b778c3a84f 41556 main/i18n/Translation-sv.bz2 502db0411e891e3ff6c418db0f75aed3 7819 main/i18n/Translation-sv.diff/Index 617fcb26803e9b2a60c2716ea4744451 902 main/i18n/Translation-tr 96c9deb10e4bb691e778589dec582fd7 530 main/i18n/Translation-tr.bz2 cb4c4914ebe769388e0de8c670225d37 4999044 main/i18n/Translation-uk 59e4e6ee5a78116b4ef2adaba3d69fa1 784640 main/i18n/Translation-uk.bz2 bd48325a3bd0dbec6c8e3d6a1166c6d6 7819 main/i18n/Translation-uk.diff/Index 68909da4ab0f9f8756c146d97f6cbfc7 38901 main/i18n/Translation-vi f742742b9fa95ba9813afdd8e6db3db0 11052 main/i18n/Translation-vi.bz2 c798577eaf0fa2845e1fe1167852aac1 7819 main/i18n/Translation-vi.diff/Index 7717fa25bd691ec385bddacf42419c9f 2799 main/i18n/Translation-zh b5a4e7e47da47ac7596ed5d72fdeef93 1526 main/i18n/Translation-zh.bz2 a012271716cf9d256dd9be9b9a4d6531 1609 main/i18n/Translation-zh.diff/Index 6cec35a2af1d84fa5bf47ffdff828458 417827 main/i18n/Translation-zh_CN 63b7491bc4af416a39ba19d590db8b46 113341 main/i18n/Translation-zh_CN.bz2 2a24796a7884950ac4a439a7de37cdae 7819 main/i18n/Translation-zh_CN.diff/Index 10db9f51168ebf0ea76cf062b7546aa9 65883 main/i18n/Translation-zh_TW cbe47f409a77be84c8ef5d46a3962cac 23191 main/i18n/Translation-zh_TW.bz2 3fa089e363a42d9d70613847cc5a18a6 7819 main/i18n/Translation-zh_TW.diff/Index 5157f07fc4659fd0695fc6c75c04a1b8 10309 main/installer-amd64/20130430/images/MD5SUMS df4c099d2c2e8e40ff1d75b73dee438c 14289 main/installer-amd64/20130430/images/SHA256SUMS 301979199205db4125d33750af7a4d88 10309 main/installer-amd64/20131014/images/MD5SUMS 8d26bcba148e44a226b1f4d6d2ddd844 14289 main/installer-amd64/20131014/images/SHA256SUMS da45f8131ef93f224f324723e686ba95 10309 main/installer-amd64/20131211/images/MD5SUMS 7ca6dbd2ad599733dd81da9d0a2dab48 14289 main/installer-amd64/20131211/images/SHA256SUMS 7ed1fbf562b4b5b9ec8237fefed7c651 10309 main/installer-amd64/20140208/images/MD5SUMS 4d6002cf22da6492712df5911153590b 14289 main/installer-amd64/20140208/images/SHA256SUMS f4eaab3e731a08ddee258e8f0ecb1da3 10323 main/installer-amd64/20140316/images/MD5SUMS ffe44dbf59759fbb55b3f1a6e2587e94 14303 main/installer-amd64/20140316/images/SHA256SUMS f4eaab3e731a08ddee258e8f0ecb1da3 10323 main/installer-amd64/current/images/MD5SUMS ffe44dbf59759fbb55b3f1a6e2587e94 14303 main/installer-amd64/current/images/SHA256SUMS 7de8623c019d830d601ee2a7a87dc4e8 4807 main/installer-armel/20130430/images/MD5SUMS c2887f8bb9f23682c45747b21a0e59c5 6835 main/installer-armel/20130430/images/SHA256SUMS fd7584af5d5cd9b57addd84b7cd2590f 4751 main/installer-armel/20131014/images/MD5SUMS 246c47f9e41acae4f6db18aaf2fc715d 6747 main/installer-armel/20131014/images/SHA256SUMS 0c09c0a9fbb28f3e4828c5ea9313a06e 4751 main/installer-armel/20131211/images/MD5SUMS 7cea5b316712a95841fbb55b033a3b14 6747 main/installer-armel/20131211/images/SHA256SUMS ee73b81c97735428110d6f01c0385aa2 4751 main/installer-armel/20140208/images/MD5SUMS 41a8129497fe8e919ad1317df8a61245 6747 main/installer-armel/20140208/images/SHA256SUMS 80b44c51928c82961e44527290ab4e97 3612 main/installer-armel/20140316/images/MD5SUMS 42ddf7632ae183c465fcd7dcc3e88c36 5128 main/installer-armel/20140316/images/SHA256SUMS 80b44c51928c82961e44527290ab4e97 3612 main/installer-armel/current/images/MD5SUMS 42ddf7632ae183c465fcd7dcc3e88c36 5128 main/installer-armel/current/images/SHA256SUMS 71a278a0ee180ccc1a661950fe9bc496 1108 main/installer-armhf/20130430/images/MD5SUMS 5655e437de9d926ea6550cff0a9d03bd 1728 main/installer-armhf/20130430/images/SHA256SUMS 9834a210064b4cbdc80180d9c9935b00 2373 main/installer-armhf/20131014/images/MD5SUMS 5372c3a3382f0c986848adbcaab46491 3569 main/installer-armhf/20131014/images/SHA256SUMS 6387b823bceed9955aaf6549744fde7e 1408 main/installer-armhf/20131211/images/MD5SUMS ec36e0b8d3c5256618948a7be4170f35 2156 main/installer-armhf/20131211/images/SHA256SUMS 9e3c867fd0af8d19ff8e005a5112088e 1408 main/installer-armhf/20140208/images/MD5SUMS 183c7864c39ce524dd36afcb41f20dc7 2156 main/installer-armhf/20140208/images/SHA256SUMS be93f8587486e7da34c2b1778d550dae 1408 main/installer-armhf/20140316/images/MD5SUMS 0eb1c3941eea96e062b93823152229ff 2156 main/installer-armhf/20140316/images/SHA256SUMS be93f8587486e7da34c2b1778d550dae 1408 main/installer-armhf/current/images/MD5SUMS 0eb1c3941eea96e062b93823152229ff 2156 main/installer-armhf/current/images/SHA256SUMS e8f06c1e9f9939ddc8e02b815ac196f0 10215 main/installer-i386/20130430/images/MD5SUMS 22a406bc62028ec5a18072a5e9d28d76 14195 main/installer-i386/20130430/images/SHA256SUMS 028ca26c83500c6a0899d807c7067c19 10215 main/installer-i386/20131014/images/MD5SUMS 24cf5bee322327f9e8ea53068d3c0a4e 14195 main/installer-i386/20131014/images/SHA256SUMS 3cdb21ee28ac95f93f6e16eea027131b 10215 main/installer-i386/20131211/images/MD5SUMS ee910b607d20ab0d866bc5060a8d4e0a 14195 main/installer-i386/20131211/images/SHA256SUMS b99cf54d61cdd4b6f462fa452ea6aa96 10215 main/installer-i386/20140208/images/MD5SUMS a41fd77526c8c169591e473480b7258f 14195 main/installer-i386/20140208/images/SHA256SUMS 26bef3c9d83bde3b84ca7dc62d270fc0 10229 main/installer-i386/20140316/images/MD5SUMS 0342e2b7186841b9f8de01a96cc8fb20 14209 main/installer-i386/20140316/images/SHA256SUMS 26bef3c9d83bde3b84ca7dc62d270fc0 10229 main/installer-i386/current/images/MD5SUMS 0342e2b7186841b9f8de01a96cc8fb20 14209 main/installer-i386/current/images/SHA256SUMS c224c83552c638c5ca8b98cdda824737 3446 main/installer-kfreebsd-amd64/20130430/images/MD5SUMS e08c7ccc16ffa44591ea8fa495cb1fa1 5026 main/installer-kfreebsd-amd64/20130430/images/SHA256SUMS 4a79ecae1b0bf0cda2c8c6622814c72f 1936 main/installer-kfreebsd-amd64/20131211/images/MD5SUMS ca154d69a5a157b5a7e9b5adcd2f5032 2876 main/installer-kfreebsd-amd64/20131211/images/SHA256SUMS 5fcb790b610983bdf49751a17970d7d5 1936 main/installer-kfreebsd-amd64/20140208/images/MD5SUMS 7419c804b7aa251f9d7e0ce29378d40a 2876 main/installer-kfreebsd-amd64/20140208/images/SHA256SUMS 8e9e579dc857632f20e38682e7202959 3768 main/installer-kfreebsd-amd64/20140316/images/MD5SUMS 51dc540d8c2e11212b2633fbfbc13091 5476 main/installer-kfreebsd-amd64/20140316/images/SHA256SUMS 8e9e579dc857632f20e38682e7202959 3768 main/installer-kfreebsd-amd64/current/images/MD5SUMS 51dc540d8c2e11212b2633fbfbc13091 5476 main/installer-kfreebsd-amd64/current/images/SHA256SUMS e25ecf1b319f5b5f4878b8c45b71dabf 1738 main/installer-kfreebsd-i386/20130430/images/MD5SUMS cfb0d05d87c0574b4ef27c24a8bda694 2614 main/installer-kfreebsd-i386/20130430/images/SHA256SUMS 181d0af0ad767db108d4c796bb1fcaed 1009 main/installer-kfreebsd-i386/20131211/images/MD5SUMS 4c7ba4c668b086bf31d2b03a3d61c212 1565 main/installer-kfreebsd-i386/20131211/images/SHA256SUMS ba1e32201db4e3c3aa37d47d0412487f 1009 main/installer-kfreebsd-i386/20140208/images/MD5SUMS a94dc3481804f29df88084c5aee6d585 1565 main/installer-kfreebsd-i386/20140208/images/SHA256SUMS 14bfd930f1d8aa10b62e72b8b9b8c527 2088 main/installer-kfreebsd-i386/20140316/images/MD5SUMS 735c6975a7b736171c8874abd87959f4 3124 main/installer-kfreebsd-i386/20140316/images/SHA256SUMS 14bfd930f1d8aa10b62e72b8b9b8c527 2088 main/installer-kfreebsd-i386/current/images/MD5SUMS 735c6975a7b736171c8874abd87959f4 3124 main/installer-kfreebsd-i386/current/images/SHA256SUMS f086770a9dc33f07be725507956548cd 802 main/installer-mips/20130430/images/MD5SUMS 54942fb0134772061606c20c2595a85d 1294 main/installer-mips/20130430/images/SHA256SUMS 24081c6f0b7c19c2ad8b5ab4dbd9f970 800 main/installer-mips/20131014/images/MD5SUMS 5f12e84dc29cabce7d8a8115875c5cdc 1292 main/installer-mips/20131014/images/SHA256SUMS 654e4298ca9c32ff88c7fb2a5ec32a47 800 main/installer-mips/20131211/images/MD5SUMS 83da891d3a2ef6a99ac84b1f062a0447 1292 main/installer-mips/20131211/images/SHA256SUMS 98fde225034cf664c2ac28a194e9dc71 934 main/installer-mips/20140208/images/MD5SUMS c893abefae76b0e008d5ec5a8014a54b 1490 main/installer-mips/20140208/images/SHA256SUMS c54606b8a49b2e7d817031a2c0447386 934 main/installer-mips/20140316/images/MD5SUMS 18244c4df596ce1f562b3209bbf4facb 1490 main/installer-mips/20140316/images/SHA256SUMS c54606b8a49b2e7d817031a2c0447386 934 main/installer-mips/current/images/MD5SUMS 18244c4df596ce1f562b3209bbf4facb 1490 main/installer-mips/current/images/SHA256SUMS 688dd3d2984ef08783259805f3fdfc71 1342 main/installer-mipsel/20130430/images/MD5SUMS e10769317f4f5925aa5bfb5505b748d7 2058 main/installer-mipsel/20130430/images/SHA256SUMS 1544093f4552f68a4aa3df94465ee1e0 1338 main/installer-mipsel/20131014/images/MD5SUMS 8620af5c92c885ed05fcfe0fbbe98a32 2054 main/installer-mipsel/20131014/images/SHA256SUMS cfce7c80f11d1fd5c784e49390b54913 1338 main/installer-mipsel/20131211/images/MD5SUMS 093cd338b128b3dc665cb654b0bf2c5c 2054 main/installer-mipsel/20131211/images/SHA256SUMS f616ae8aa45ccd5fe3511518ed3a7417 993 main/installer-mipsel/20140208/images/MD5SUMS 50242cbf0ec26020bd45291cc7286aad 1549 main/installer-mipsel/20140208/images/SHA256SUMS a8cf21f7766b39144a04b44daf37acec 993 main/installer-mipsel/20140316/images/MD5SUMS 5abf589867be0b0862ee4b6c4722c311 1549 main/installer-mipsel/20140316/images/SHA256SUMS a8cf21f7766b39144a04b44daf37acec 993 main/installer-mipsel/current/images/MD5SUMS 5abf589867be0b0862ee4b6c4722c311 1549 main/installer-mipsel/current/images/SHA256SUMS a23b0abc569fa35e33d19fbd3b7b1ba5 2128 main/installer-powerpc/20130430/images/MD5SUMS db1fea8e29058bd92b92ab4e00e04f81 3292 main/installer-powerpc/20130430/images/SHA256SUMS 813bed7c83e8c278080cb655c0ec4a00 2128 main/installer-powerpc/20131014/images/MD5SUMS 0a00ae033839876b98a12a707997a2af 3292 main/installer-powerpc/20131014/images/SHA256SUMS 5f166fd1ce537aa4f9df928449912d44 2128 main/installer-powerpc/20131211/images/MD5SUMS 0b8f9002f47941aa35fbea260ff440c4 3292 main/installer-powerpc/20131211/images/SHA256SUMS d32f841db5b1538592370c4d489ec645 2128 main/installer-powerpc/20140208/images/MD5SUMS fd020de38a5833d5f8d721396684a3b2 3292 main/installer-powerpc/20140208/images/SHA256SUMS 196a98c7e0cc520ab30b3af63e12997e 2128 main/installer-powerpc/20140316/images/MD5SUMS 6cb1636aaf3ea2981b4e84eec965e212 3292 main/installer-powerpc/20140316/images/SHA256SUMS 196a98c7e0cc520ab30b3af63e12997e 2128 main/installer-powerpc/current/images/MD5SUMS 6cb1636aaf3ea2981b4e84eec965e212 3292 main/installer-powerpc/current/images/SHA256SUMS 58a4905fbce785248af65bcafaa50bec 604 main/installer-s390x/20130430/images/MD5SUMS 25492a720b14bece99e85c4e47c330ec 1032 main/installer-s390x/20130430/images/SHA256SUMS 2f23d000575488cca828a5f55bc246d7 374 main/installer-s390x/20131014/images/MD5SUMS 62b8311d547185eb84f3a6a201674c73 674 main/installer-s390x/20131014/images/SHA256SUMS 7dac42788263c2846bdff5565156bf08 374 main/installer-s390x/20131211/images/MD5SUMS 3b37340c5e27fad47736e39b90143a43 674 main/installer-s390x/20131211/images/SHA256SUMS 2e330c208f4c37647f1d796e85023839 374 main/installer-s390x/20140208/images/MD5SUMS f4f726fedb72f515f89d828f89b8ead3 674 main/installer-s390x/20140208/images/SHA256SUMS dc909df04287595f9976d35c06efa349 374 main/installer-s390x/20140316/images/MD5SUMS 7b9b300111a207face404311e2a4f5ce 674 main/installer-s390x/20140316/images/SHA256SUMS dc909df04287595f9976d35c06efa349 374 main/installer-s390x/current/images/MD5SUMS 7b9b300111a207face404311e2a4f5ce 674 main/installer-s390x/current/images/SHA256SUMS c5804a6d2711504ef4293271ea405013 358 main/installer-sparc/20130430/images/MD5SUMS e94e7cbb0509df67ddc86eaeb21a3bed 658 main/installer-sparc/20130430/images/SHA256SUMS d09e23b9328826d80a167ec8b52436cc 357 main/installer-sparc/20131211/images/MD5SUMS 2eca96fe86e68e92eaf4a7f1b68b17cb 657 main/installer-sparc/20131211/images/SHA256SUMS d09e23b9328826d80a167ec8b52436cc 357 main/installer-sparc/current/images/MD5SUMS 2eca96fe86e68e92eaf4a7f1b68b17cb 657 main/installer-sparc/current/images/SHA256SUMS 523304484e38cb817355601d6d99f8e0 84 main/source/Release f0dd59427cfcaeca2c4bb6df8a160902 33695427 main/source/Sources b85be17367c2e7147a05c5321e7601e6 7876 main/source/Sources.diff/Index 40643cc886f19d1bfc9cdd7667423857 9414551 main/source/Sources.gz ff64ec431203da7ba4a200c87e14dcc3 7263348 main/source/Sources.xz ee2afd68966d4750df7f46bee07d249e 7876 non-free/Contents-amd64.diff/Index 466a58e7f6ac69852a1646e2c5602126 747296 non-free/Contents-amd64.gz e550899b04092baa04d03c46bc2bb2e2 7876 non-free/Contents-armel.diff/Index 0ccad62719ca6e464ab193f12442ddd1 692360 non-free/Contents-armel.gz 422278a42b864f85c738419673ad9367 7876 non-free/Contents-armhf.diff/Index 57c2767d379004a761732944a45747a0 690391 non-free/Contents-armhf.gz 6317d776d1bbda953b777b50a7dcd396 7876 non-free/Contents-hurd-i386.diff/Index f26162b0a7108fc7b506fb4b2e370e17 689428 non-free/Contents-hurd-i386.gz 16aba2334b200d7e4332b15dfaf4631c 7876 non-free/Contents-i386.diff/Index c7a40726618d59bc1f79f01906c3933b 740969 non-free/Contents-i386.gz a2e1064fe050d3ddafb0f0277f2c0325 7876 non-free/Contents-kfreebsd-amd64.diff/Index 0e62d95210a688a925dd13ed9c296251 690234 non-free/Contents-kfreebsd-amd64.gz d81d830b66d23671706493e3da49d404 7876 non-free/Contents-kfreebsd-i386.diff/Index e4bff034a99aaa236c5e12bfd27ad3d5 691340 non-free/Contents-kfreebsd-i386.gz ef283870651643613c6db7fb3d27ed1c 7876 non-free/Contents-mips.diff/Index a83720350ab8526681da800de0767d73 692859 non-free/Contents-mips.gz c97023873f05807b3cb749e6b36bfa09 7876 non-free/Contents-mipsel.diff/Index 624fc612bb71ee16c139b3a2f5716050 693226 non-free/Contents-mipsel.gz cbaf26e97ee17052659b95e1aab49f73 7876 non-free/Contents-powerpc.diff/Index c9c6cae4abf3113c7661a682c3b7bcf9 692776 non-free/Contents-powerpc.gz 422278a42b864f85c738419673ad9367 7876 non-free/Contents-s390x.diff/Index d21b3bc90e9ad7b8f6bbca00cc795542 689635 non-free/Contents-s390x.gz d1fe7273b8dee3090c1f49ee41415bd5 878304 non-free/Contents-source.gz 532f262febe49a4cc81b3d1bb64bb1fc 7876 non-free/Contents-sparc.diff/Index abbc93fd2821d9bcdeb15b977c659e00 693322 non-free/Contents-sparc.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-alpha.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-amd64.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-armel.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-armhf.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-hppa.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-hurd-i386.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-i386.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-kfreebsd-amd64.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-kfreebsd-i386.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-mips.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-mipsel.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-powerpc.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-s390x.gz c0e7f37cdcb2125588ecfbe574a47206 714 non-free/Contents-udeb-sparc.gz d86b9ade7a5c88b1a49979e52c4b7350 205641 non-free/binary-all/Packages 33da6000a574960c415a27dc8ba84b4b 60301 non-free/binary-all/Packages.gz 7294185731764ad2e9075abd49e91ad6 51104 non-free/binary-all/Packages.xz 2bef39b9cc7403ece40bbadf2ceaa995 85 non-free/binary-all/Release a292d23f07b062311ce365111aec997b 399086 non-free/binary-amd64/Packages ffdcb556ee2c2730f41270ba44bc96ea 7819 non-free/binary-amd64/Packages.diff/Index 26adac6cf84a324162e22bfda4a997d1 110104 non-free/binary-amd64/Packages.gz bee3b7a3a34f1b28a4e28d55bb7fe5fd 91232 non-free/binary-amd64/Packages.xz 10cfcc7cdb85c38c7de03cb2bc074e0a 87 non-free/binary-amd64/Release 9591b27b2b48a5f339b2ae85828912e3 256534 non-free/binary-armel/Packages aebbc4aaecae91a6619b902089779661 7819 non-free/binary-armel/Packages.diff/Index 81a2247374e09d7d10705568a5c3370c 75455 non-free/binary-armel/Packages.gz 272c8eacf0a5a30a025131e2b572912a 63408 non-free/binary-armel/Packages.xz 236b24d5ff7e9330a395cf8e4b2a9c71 87 non-free/binary-armel/Release fe08ecdec9069c75d4f1622933d2b373 262280 non-free/binary-armhf/Packages 32880abf00af4657589040da501ed51a 7819 non-free/binary-armhf/Packages.diff/Index d7976ed6ddeb940821dfa50968d00b08 76497 non-free/binary-armhf/Packages.gz 61182b6908d6e95db4bbe7454a83c7e4 64148 non-free/binary-armhf/Packages.xz 66b699951ef3b94a4d23d5cecbd5f900 87 non-free/binary-armhf/Release 935da443e2338079713dae53f64a5268 257246 non-free/binary-hurd-i386/Packages 1850006c87543af041d307fc0aa095e5 7819 non-free/binary-hurd-i386/Packages.diff/Index 70f88d7140f0e7b76f085ba24681cf5b 74841 non-free/binary-hurd-i386/Packages.gz c2584a765a91e39918b6bc7783be28a1 63080 non-free/binary-hurd-i386/Packages.xz 014e80a8920ee365791fc6ef53950167 91 non-free/binary-hurd-i386/Release 9be3ade99d4bfdd841e500ea4873861a 387138 non-free/binary-i386/Packages 51ade8c8630ef962b75f01ed0c81e708 7819 non-free/binary-i386/Packages.diff/Index 32695d6fa5aa336ab367311314c98442 105652 non-free/binary-i386/Packages.gz b9fafc8085825e2adeb9b5fa98a48052 87824 non-free/binary-i386/Packages.xz 3ccb6268d6ee322edba6a517607b0507 86 non-free/binary-i386/Release cc93165e5e84ca8bee812cc67e91fdaf 253378 non-free/binary-kfreebsd-amd64/Packages 05fdf7b2ff5f9de6300f48172cad5782 7819 non-free/binary-kfreebsd-amd64/Packages.diff/Index 014cf65e05a7804653ba503e6c269332 73809 non-free/binary-kfreebsd-amd64/Packages.gz e6e524ba7958a68a01bb4ce7d81f6ded 62124 non-free/binary-kfreebsd-amd64/Packages.xz c5220fb19192687c1443e0cb24d0884c 96 non-free/binary-kfreebsd-amd64/Release 122b3b5ea9465ca2260ee51ac8cf2094 257662 non-free/binary-kfreebsd-i386/Packages 05fdf7b2ff5f9de6300f48172cad5782 7819 non-free/binary-kfreebsd-i386/Packages.diff/Index b0945d5187aeef765db2a768a0194e75 75004 non-free/binary-kfreebsd-i386/Packages.gz fe95f293d9a5cfb833ff661fbbcdb967 63052 non-free/binary-kfreebsd-i386/Packages.xz 6ae37525aebaeb3e79965d8482c9ab34 95 non-free/binary-kfreebsd-i386/Release b13482c02f1b52fccce43335b1929014 253858 non-free/binary-mips/Packages 93dd99e220b0d87c1301c91b17d6cb99 7819 non-free/binary-mips/Packages.diff/Index 857f40454068ed476025908471353e37 74686 non-free/binary-mips/Packages.gz 834687aabb0aa7691f96ea75703c12a6 62728 non-free/binary-mips/Packages.xz 0a9196fc2bdba277335f7a9159a81853 86 non-free/binary-mips/Release 00a7606a8b13b2f93fe82bbdf9ea69b8 257104 non-free/binary-mipsel/Packages 0bf6599c4092fd96cdb4ab7144ea83e3 7819 non-free/binary-mipsel/Packages.diff/Index 9c8405e04cb7a3c4aa3d4b2e3cb98dac 75418 non-free/binary-mipsel/Packages.gz 3ef2cb67b4fa9da7f30d1be065155c13 63308 non-free/binary-mipsel/Packages.xz 8249ff0fb5f8a091737111c1fdb241c7 88 non-free/binary-mipsel/Release 39ea0db4de206f83ff328b0bb0e16ef8 255252 non-free/binary-powerpc/Packages 20a89ccb912e559af4010901d35b976e 7819 non-free/binary-powerpc/Packages.diff/Index 179f0ca907891c624d3b1677d05afb7a 74812 non-free/binary-powerpc/Packages.gz b5968fd59f4c83b6073c3e28eeeba67d 62968 non-free/binary-powerpc/Packages.xz 2c71ffa8f13500b24d9ebca19437484f 89 non-free/binary-powerpc/Release 6178e7e601fe18bfa22e4a0762038d74 251692 non-free/binary-s390x/Packages 32880abf00af4657589040da501ed51a 7819 non-free/binary-s390x/Packages.diff/Index f399947c8607c45a79680ee6a99371bd 73841 non-free/binary-s390x/Packages.gz d760160dd954325d5ffc6dc7edf97fd4 62104 non-free/binary-s390x/Packages.xz 4050f20acb5ac6bae5a1cf8f0a98ccc7 87 non-free/binary-s390x/Release f271a7eae3d9438eebed4fa3044f8d4c 255662 non-free/binary-sparc/Packages 7dee36fbab3a2e5be5fb005cc7b103c8 7819 non-free/binary-sparc/Packages.diff/Index 7e254349508e3a872dcac7a07edaea2f 75128 non-free/binary-sparc/Packages.gz 26767d67982ae2b65bc885763cae272b 63144 non-free/binary-sparc/Packages.xz 3291f8caef741ffdcdfab29fa4dfecd3 87 non-free/binary-sparc/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-all/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-all/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-all/Packages.xz 2bef39b9cc7403ece40bbadf2ceaa995 85 non-free/debian-installer/binary-all/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-amd64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-amd64/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-amd64/Packages.xz 10cfcc7cdb85c38c7de03cb2bc074e0a 87 non-free/debian-installer/binary-amd64/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-armel/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-armel/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-armel/Packages.xz 236b24d5ff7e9330a395cf8e4b2a9c71 87 non-free/debian-installer/binary-armel/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-armhf/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-armhf/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-armhf/Packages.xz 66b699951ef3b94a4d23d5cecbd5f900 87 non-free/debian-installer/binary-armhf/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-hurd-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-hurd-i386/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-hurd-i386/Packages.xz 014e80a8920ee365791fc6ef53950167 91 non-free/debian-installer/binary-hurd-i386/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-i386/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-i386/Packages.xz 3ccb6268d6ee322edba6a517607b0507 86 non-free/debian-installer/binary-i386/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-kfreebsd-amd64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-kfreebsd-amd64/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-kfreebsd-amd64/Packages.xz c5220fb19192687c1443e0cb24d0884c 96 non-free/debian-installer/binary-kfreebsd-amd64/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-kfreebsd-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-kfreebsd-i386/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-kfreebsd-i386/Packages.xz 6ae37525aebaeb3e79965d8482c9ab34 95 non-free/debian-installer/binary-kfreebsd-i386/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-mips/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-mips/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-mips/Packages.xz 0a9196fc2bdba277335f7a9159a81853 86 non-free/debian-installer/binary-mips/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-mipsel/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-mipsel/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-mipsel/Packages.xz 8249ff0fb5f8a091737111c1fdb241c7 88 non-free/debian-installer/binary-mipsel/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-powerpc/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-powerpc/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-powerpc/Packages.xz 2c71ffa8f13500b24d9ebca19437484f 89 non-free/debian-installer/binary-powerpc/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-s390x/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-s390x/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-s390x/Packages.xz 4050f20acb5ac6bae5a1cf8f0a98ccc7 87 non-free/debian-installer/binary-s390x/Release d41d8cd98f00b204e9800998ecf8427e 0 non-free/debian-installer/binary-sparc/Packages 4a4dd3598707603b3f76a2378a4504aa 20 non-free/debian-installer/binary-sparc/Packages.gz 8dc5aea5b03dff8595f096f9e368e888 32 non-free/debian-installer/binary-sparc/Packages.xz 3291f8caef741ffdcdfab29fa4dfecd3 87 non-free/debian-installer/binary-sparc/Release 7c3f32e9e68926bf2e1c058e6362e649 345632 non-free/i18n/Translation-en 249e473ff6359aebfc021f6d4e62082e 76649 non-free/i18n/Translation-en.bz2 2dfc538010c9901f98da4f7362572ccc 7819 non-free/i18n/Translation-en.diff/Index 37414e5ea3a3b38d8cda0b8f9d7ccdfa 88 non-free/source/Release 75c03145b9cb0eaa247ad2264ad40d66 432632 non-free/source/Sources abd5b5853618a37d46066f6d3f2d153e 7819 non-free/source/Sources.diff/Index a16572fcd231361055662cdcea315489 127628 non-free/source/Sources.gz 8043a1ef89ac42a6fd824653d03da3db 106852 non-free/source/Sources.xz SHA1: 0f7a3f8eeed325c4a7ab042ee0c092bb0630340a 29126161 Contents-amd64.gz 4396882f447b9a438c137ac53bac589e64e433f4 28753408 Contents-armel.gz ca08536f57e16da2349279f0f0182d9329810f08 28485312 Contents-armhf.gz edb1ed9b84ae288b28675347adb7bdd37452c984 26796983 Contents-hurd-i386.gz 1f5cedc1d6d2927d63c894f630eb769316fed384 29331795 Contents-i386.gz b9d6ccdd8575331dcf9996fec5bf7ed8c8c3b779 27824917 Contents-kfreebsd-amd64.gz b7e37761da6c8066568684f9fd4c5956524d883a 27850902 Contents-kfreebsd-i386.gz f23039a77417fc80e1f0d1d3f8c0338e1b6a132d 28457146 Contents-mips.gz 5e63672e45a4fba6fecb657d8ff92d7bd2e4b66d 28487260 Contents-mipsel.gz f0dac7422e1b29890a53a1f0a5314d583f613cb8 28813161 Contents-powerpc.gz 49392f8dfbd63994b016f9ec041e7bd830d3c73a 28252350 Contents-s390x.gz 44526259016b7702b5cbb69c792f2f795f079098 28214513 Contents-sparc.gz f1c4035f5dd9ffc2813c1581d35a175dd5cc9ddc 7819 contrib/Contents-amd64.diff/Index 6fcd6228ebb129875d16753e30d88271ccc0dcf3 101661 contrib/Contents-amd64.gz f997d05fba5ac91e9ed08535d3bd8347dc96844e 7819 contrib/Contents-armel.diff/Index 7e0d3705bf9d89ded71d844071a28e9da31eb1ff 84379 contrib/Contents-armel.gz a710e9c04387e579cb6726c310e7af72472caa87 7819 contrib/Contents-armhf.diff/Index fb26dc4a5efc8c88e1e184549c0d0b956c91d68c 84201 contrib/Contents-armhf.gz d2fed1d55502850d26428300c0ebd1d860851435 7819 contrib/Contents-hurd-i386.diff/Index 79d53eee12c02db9af600b114fbdc8d10f870bcd 81453 contrib/Contents-hurd-i386.gz 055b1a353988ed91e8c9721f2a41173aac14ffd2 7819 contrib/Contents-i386.diff/Index d4b466157bd185004153a6fc6f8550ae68d118a7 100858 contrib/Contents-i386.gz 7d43b7235f43ed8654135a96f1b184200c16402d 7819 contrib/Contents-kfreebsd-amd64.diff/Index 2d741be98b29868ffb587e0321d68c990d2dc131 84100 contrib/Contents-kfreebsd-amd64.gz 7d43b7235f43ed8654135a96f1b184200c16402d 7819 contrib/Contents-kfreebsd-i386.diff/Index def1fabcb9c2ce2b4e02e340f339d7f4410e4404 84073 contrib/Contents-kfreebsd-i386.gz 022b652b75c38c0bdba446d97f89b0ac2168490a 7819 contrib/Contents-mips.diff/Index 4038987b47b3c2e30b9d3a4663bd78db843787c7 84846 contrib/Contents-mips.gz 226b2daeca69fbc81d2bd021636c4c029254f759 7819 contrib/Contents-mipsel.diff/Index ce12f8d9c145302f7145d6f8ae3d511229c8fc4b 84844 contrib/Contents-mipsel.gz 08978fc15467d8f0e0014f948aab3868f2273926 7819 contrib/Contents-powerpc.diff/Index aeb3b4c4ab2a3e4abf8fcfc981ae0f16cef31676 84620 contrib/Contents-powerpc.gz 572580a3b34e293fa9cc722d8b0a1233571fe8fc 7819 contrib/Contents-s390x.diff/Index d3fd6a2084b8c9dbc88dcc30d79576c4d0732eb4 84290 contrib/Contents-s390x.gz f44b0fa00cef5ca9f2aa7ae608cb3e87779cbcca 320817 contrib/Contents-source.gz 799f1a461a9db6e5b95705fb6f12758418e69520 7819 contrib/Contents-sparc.diff/Index a22f56a1f95a31774fd36796be7baaaa21f3ff50 84617 contrib/Contents-sparc.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-amd64.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-armel.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-armhf.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-hurd-i386.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-i386.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-kfreebsd-amd64.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-kfreebsd-i386.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-mips.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-mipsel.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-powerpc.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-s390x.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 contrib/Contents-udeb-sparc.gz a1d78f4a20d3e940855070477540f347c4ae1848 93025 contrib/binary-all/Packages 90cac9b4fb564c2d6aae723a2f6fd21e3de6c9e8 29432 contrib/binary-all/Packages.gz 49eb524bb47252290b3909a3a9311f52541e87f2 25984 contrib/binary-all/Packages.xz 2531fb2c0c855eb1acf68edf4408271f87fc8d95 84 contrib/binary-all/Release 2970bf7ff707537a5dc3a9eda74e7e4bb0a00a41 217977 contrib/binary-amd64/Packages d899d98950635e05668fbe22b3c9659d536eaf6e 7819 contrib/binary-amd64/Packages.diff/Index 3e5c3e13a192f1662b2dce024744a69c56737a1d 64629 contrib/binary-amd64/Packages.gz 192736991d8cd994a6b48eb268f549f855d20698 54404 contrib/binary-amd64/Packages.xz 3fd5b4687a0b455fcb249275ca8fef5d662ff8f8 86 contrib/binary-amd64/Release cc912a61f92996fbc16c1279f411b9a859c0dfce 157509 contrib/binary-armel/Packages 5f2fc37bff6261afacb76f97258bccb7284b073b 7819 contrib/binary-armel/Packages.diff/Index bd576b9874099b7ff104e8a04027e5b97b8dc781 48157 contrib/binary-armel/Packages.gz 7c61ed87846f3ca58e32c20adc80e8a354f249e2 41292 contrib/binary-armel/Packages.xz 278b47ac71481360485446de8ac8f22e3e8ff88b 86 contrib/binary-armel/Release 9ea3e7243497a641bd8af098441268a950ed1cd8 160324 contrib/binary-armhf/Packages 2d12288b804e38cb7f165f0399c3760db116e792 7819 contrib/binary-armhf/Packages.diff/Index 800d96700cece8ed8b21f0bfd96abf6d67047a81 48893 contrib/binary-armhf/Packages.gz 62b2b5ba4abe5b35413f3150e03e3eb02e15fc4e 41736 contrib/binary-armhf/Packages.xz d72e6ed0e8d6014f29df3f30c67ca7013bb92bbe 86 contrib/binary-armhf/Release d6aafb5af838cd8b5db203abc60bc2fd346b66a7 142314 contrib/binary-hurd-i386/Packages 46da61b6d2c2cc8e6a89cda1c4cfda08fe5730c4 7819 contrib/binary-hurd-i386/Packages.diff/Index 244553c8caf7e07eae5d8b3b3c17b9c17fe68500 44061 contrib/binary-hurd-i386/Packages.gz 4c9c061272d8b2888419aa495eb970193556df43 37744 contrib/binary-hurd-i386/Packages.xz c72b3950fe79c8185a2ef3bc1ce46db42935a911 90 contrib/binary-hurd-i386/Release aea7c13888690692930ccb1f76820e75dd5b5204 215343 contrib/binary-i386/Packages b910de11c1964e1317b97f063f0387e91ecbe868 7819 contrib/binary-i386/Packages.diff/Index 7b427f708e6f75ae99837ab2cb65b44af0384550 64028 contrib/binary-i386/Packages.gz 762f7499edbbde121e5f2a923e32a6d766d4e3eb 53760 contrib/binary-i386/Packages.xz ed357d4957545b23d3cb0f7fb9ed2f6d5d3c0bde 85 contrib/binary-i386/Release b035619a6aceae708c55007e4a6249b33cc5bbe1 159685 contrib/binary-kfreebsd-amd64/Packages aa60d5f27eaf2febdcc8dbd74587703294b1d4c6 7819 contrib/binary-kfreebsd-amd64/Packages.diff/Index 80e10696e1c5fc60573412607d2b14dd31f03774 47934 contrib/binary-kfreebsd-amd64/Packages.gz 3593820ee377660d7bb04950e3911eb45798edc4 41212 contrib/binary-kfreebsd-amd64/Packages.xz cddea49e554e6ba448c40154e61fa263a8a7e726 95 contrib/binary-kfreebsd-amd64/Release 6a72fc99201159d792da268c3043730422294e0c 159525 contrib/binary-kfreebsd-i386/Packages 93c533e51134f1ce0bc78302b5926aa51822d5db 7819 contrib/binary-kfreebsd-i386/Packages.diff/Index ddc7553cb146b7a58f8a3936eede30443942491f 48140 contrib/binary-kfreebsd-i386/Packages.gz df49b562af7887d76a6c6f01d7b018e6b0392114 41220 contrib/binary-kfreebsd-i386/Packages.xz 57759d839e668500cd78da4bd9244f6716607bde 94 contrib/binary-kfreebsd-i386/Release 6beebb9ea82b90aa47e97aad545937cef32c61e2 159132 contrib/binary-mips/Packages 1f35c584c70ff1abbfa71fd6f68f6719c7c1ab03 7819 contrib/binary-mips/Packages.diff/Index f50f839dea89f4deca58398366006f8d129cb51c 48921 contrib/binary-mips/Packages.gz 678c1f230dc8b5ea2868739e2e8c0ac4da40132d 41708 contrib/binary-mips/Packages.xz 5b1d2a55a3a2e6f2bdd8b77c5b7a0877bf101d02 85 contrib/binary-mips/Release b862ec10a7d92e1edb7c6fd28f0c8c4ebc95090d 159444 contrib/binary-mipsel/Packages 8bbb351e3b397f553be89bc4a7db5c048da9f95a 7819 contrib/binary-mipsel/Packages.diff/Index cb4cfe3a7bda97ebbd9ac9aa89d9b57f049c3728 48759 contrib/binary-mipsel/Packages.gz 0d86ed3bba8a9d1d4b7c490513a75329776ebdd5 41760 contrib/binary-mipsel/Packages.xz af9fc1822af2a1e4d3e6df2f61c7df41d7ee92e9 87 contrib/binary-mipsel/Release 54a9bf4462ac8234601ecdce90a18a851c6a2c5d 157611 contrib/binary-powerpc/Packages c0c840237642dafc8602371238482dca0264b1b5 7819 contrib/binary-powerpc/Packages.diff/Index e6955f4d2cce25fdb65d6b0d0b1c2f848e39fd44 48455 contrib/binary-powerpc/Packages.gz 40a0fbcf6432920ca39e8e72bb13449ab740a698 41396 contrib/binary-powerpc/Packages.xz 748dca58de29701ab67b8b0a76939dc99aeedc14 88 contrib/binary-powerpc/Release 8ea64ece9de9a37c609cf5c601bd58b8efc1e7bd 156138 contrib/binary-s390x/Packages 2d12288b804e38cb7f165f0399c3760db116e792 7819 contrib/binary-s390x/Packages.diff/Index 72376b6d16f08d781ca0a7b3a90e85653edefe8a 47760 contrib/binary-s390x/Packages.gz fd849c7971a5a9a37fbbfb989a62430ddcb38fcc 40900 contrib/binary-s390x/Packages.xz 8d5ca1d8c56f9162c5a9d13dbc2895cab7d8f8ca 86 contrib/binary-s390x/Release 0e997c85096e30fa6d81a9d159292f38f8779cd0 157282 contrib/binary-sparc/Packages 7880d2c06e8ae170d6ddf38baf6d7f875732deec 7819 contrib/binary-sparc/Packages.diff/Index a54d1c81813c5365eb5e9e6019cdea464be36303 48168 contrib/binary-sparc/Packages.gz f2e54bf047da8960b6b31e5019f2a5fe2d08646e 41228 contrib/binary-sparc/Packages.xz bba7138f002bbdbe3a8e2755257d324e201e556b 86 contrib/binary-sparc/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-all/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-all/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-all/Packages.xz 2531fb2c0c855eb1acf68edf4408271f87fc8d95 84 contrib/debian-installer/binary-all/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-amd64/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-amd64/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-amd64/Packages.xz 3fd5b4687a0b455fcb249275ca8fef5d662ff8f8 86 contrib/debian-installer/binary-amd64/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-armel/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-armel/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-armel/Packages.xz 278b47ac71481360485446de8ac8f22e3e8ff88b 86 contrib/debian-installer/binary-armel/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-armhf/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-armhf/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-armhf/Packages.xz d72e6ed0e8d6014f29df3f30c67ca7013bb92bbe 86 contrib/debian-installer/binary-armhf/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-hurd-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-hurd-i386/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-hurd-i386/Packages.xz c72b3950fe79c8185a2ef3bc1ce46db42935a911 90 contrib/debian-installer/binary-hurd-i386/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-i386/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-i386/Packages.xz ed357d4957545b23d3cb0f7fb9ed2f6d5d3c0bde 85 contrib/debian-installer/binary-i386/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-kfreebsd-amd64/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-kfreebsd-amd64/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-kfreebsd-amd64/Packages.xz cddea49e554e6ba448c40154e61fa263a8a7e726 95 contrib/debian-installer/binary-kfreebsd-amd64/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-kfreebsd-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-kfreebsd-i386/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-kfreebsd-i386/Packages.xz 57759d839e668500cd78da4bd9244f6716607bde 94 contrib/debian-installer/binary-kfreebsd-i386/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-mips/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-mips/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-mips/Packages.xz 5b1d2a55a3a2e6f2bdd8b77c5b7a0877bf101d02 85 contrib/debian-installer/binary-mips/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-mipsel/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-mipsel/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-mipsel/Packages.xz af9fc1822af2a1e4d3e6df2f61c7df41d7ee92e9 87 contrib/debian-installer/binary-mipsel/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-powerpc/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-powerpc/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-powerpc/Packages.xz 748dca58de29701ab67b8b0a76939dc99aeedc14 88 contrib/debian-installer/binary-powerpc/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-s390x/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-s390x/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-s390x/Packages.xz 8d5ca1d8c56f9162c5a9d13dbc2895cab7d8f8ca 86 contrib/debian-installer/binary-s390x/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 contrib/debian-installer/binary-sparc/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 contrib/debian-installer/binary-sparc/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 contrib/debian-installer/binary-sparc/Packages.xz bba7138f002bbdbe3a8e2755257d324e201e556b 86 contrib/debian-installer/binary-sparc/Release 98df89a3829750c2fc5464a1c05b0c7016763912 163386 contrib/i18n/Translation-en fb295ee7747043c7f6234c254d7c09dc38971249 42412 contrib/i18n/Translation-en.bz2 04e143f30477c355be72a9d8bdcd687fcb6ad551 7819 contrib/i18n/Translation-en.diff/Index ffbc1e34cfd84724dd7b58c954e39b4402f0f81d 87 contrib/source/Release 1dabe3641c5a059ac6b35b8b399ed3c4ebf8cc08 214833 contrib/source/Sources 960541c5f6bb065464f3b5f206823a433a0d933d 7819 contrib/source/Sources.diff/Index 87ae4d0d12c02a2622dd399548f6140279eb6d79 65954 contrib/source/Sources.gz b887215823e5e77cc595efa977af1fd7d2cf02eb 56404 contrib/source/Sources.xz 82cecbc70ca41f479b606ee96e5229c46525a18f 7933 main/Contents-amd64.diff/Index 0f7a3f8eeed325c4a7ab042ee0c092bb0630340a 29126161 main/Contents-amd64.gz aa50440bae671e405af640b7d0ff3271dea8924a 7933 main/Contents-armel.diff/Index 4396882f447b9a438c137ac53bac589e64e433f4 28753408 main/Contents-armel.gz df8c8e1156d02b29d584b7a1dee2c4c609b85dc7 7933 main/Contents-armhf.diff/Index ca08536f57e16da2349279f0f0182d9329810f08 28485312 main/Contents-armhf.gz ac9199ff40f06d287057273fa7651ebcf2eff058 7933 main/Contents-hurd-i386.diff/Index edb1ed9b84ae288b28675347adb7bdd37452c984 26796983 main/Contents-hurd-i386.gz b6559335ec1fb16333eb344e879d62842e0b6933 7933 main/Contents-i386.diff/Index 1f5cedc1d6d2927d63c894f630eb769316fed384 29331795 main/Contents-i386.gz 6ecd9cdad274f032c8fc0b1cd0c1549648fc86bd 7933 main/Contents-kfreebsd-amd64.diff/Index b9d6ccdd8575331dcf9996fec5bf7ed8c8c3b779 27824917 main/Contents-kfreebsd-amd64.gz 6ebaf9206ccda7c21abc1de56c8624738928b1d7 7933 main/Contents-kfreebsd-i386.diff/Index b7e37761da6c8066568684f9fd4c5956524d883a 27850902 main/Contents-kfreebsd-i386.gz b9903c557b6ac7820cf3cc7e86691b65c0fc68b1 7933 main/Contents-mips.diff/Index f23039a77417fc80e1f0d1d3f8c0338e1b6a132d 28457146 main/Contents-mips.gz 5d64a4ce5cf2db93e850efeca32b71e66f52d04c 7933 main/Contents-mipsel.diff/Index 5e63672e45a4fba6fecb657d8ff92d7bd2e4b66d 28487260 main/Contents-mipsel.gz 77a7ed7b70b40d313952fe352ab73b551bed9b1b 7933 main/Contents-powerpc.diff/Index f0dac7422e1b29890a53a1f0a5314d583f613cb8 28813161 main/Contents-powerpc.gz df8c8e1156d02b29d584b7a1dee2c4c609b85dc7 7933 main/Contents-s390x.diff/Index 49392f8dfbd63994b016f9ec041e7bd830d3c73a 28252350 main/Contents-s390x.gz 629bde522497b33c74e508189f56f703c9ecf7ad 42201895 main/Contents-source.gz 52bc023323fbbbe754565cd1c3679fd6bac71cb9 7933 main/Contents-sparc.diff/Index 44526259016b7702b5cbb69c792f2f795f079098 28214513 main/Contents-sparc.gz a4f3696dfe28018e281722a0b0bd3af2f0f97851 34470 main/Contents-udeb-amd64.gz 44af7d914a28c1447b3ea02d813ccf7af444bd18 30168 main/Contents-udeb-armel.gz 258ccaf2f672f14c809e28b5400270351ace4104 26977 main/Contents-udeb-armhf.gz a2621b0b6581f3d0267be7d936e3ba24be3968fa 20196 main/Contents-udeb-hurd-i386.gz faabeb4ed47e69ffef0596e94badea6e68f9417c 47415 main/Contents-udeb-i386.gz 1feefa5e3de58af78276634c3faf60f990c73d4a 22694 main/Contents-udeb-kfreebsd-amd64.gz 33332604175185218b17bab4402ff88bacacf538 22764 main/Contents-udeb-kfreebsd-i386.gz c57e11fdfac26948dec6f72a6272e8e69d7efd0e 26868 main/Contents-udeb-mips.gz 8140d3d09b7e574588e144f3f4e0f9671f5802f5 27496 main/Contents-udeb-mipsel.gz d5704ee18b4d105a1c547ff05c62ad7193dda25b 40941 main/Contents-udeb-powerpc.gz e28566e33756ed2f6e946d969053dffcb6c60f34 23637 main/Contents-udeb-s390x.gz 2907d80c86c35f6bb010eb84c5da74d8b6ffe910 25142 main/Contents-udeb-sparc.gz 9cc7b1a1fd4bc115ab405200fcfa88b8ed5c39b8 14618792 main/binary-all/Packages d8f2041e5047ddec0e741e7dcafa30f71a9526a9 3969765 main/binary-all/Packages.gz a02cf4931ae9edc7b8e82856ca5ed86d8546d6a3 3028620 main/binary-all/Packages.xz 5db37fb1d8a09567d5215170cd04a0a6fa959b91 81 main/binary-all/Release b5a815d3114b218e138f45f5e616111fc2c86de6 33618877 main/binary-amd64/Packages 2fbc7a525a1f4836f8379a3abdd876bd781edefa 7876 main/binary-amd64/Packages.diff/Index 0d47982d5757e8a7402785fd95cd7a3e02820d08 8985791 main/binary-amd64/Packages.gz 18b77bbc372078aacde8ba0604c5310860f3e348 6724080 main/binary-amd64/Packages.xz 0ddf4927eb3db059ab4583e346c7e489dd11b373 83 main/binary-amd64/Release c332ca8595f7779a3dc22973af66ee17829880bd 32806207 main/binary-armel/Packages 9e3df502ef76b3acdcbb929cb9a798f3387f9cfd 7876 main/binary-armel/Packages.diff/Index 850614836c6215a19687f7d96bf392750974c420 8780431 main/binary-armel/Packages.gz c8658e38a8f8cbae6a0ee359a274e7114a6234b1 6573736 main/binary-armel/Packages.xz 5fe3326149ae392bc6badb1c48f50775215c7432 83 main/binary-armel/Release f27ccda21f7d4ad672604f0468429e078ef84a71 32702650 main/binary-armhf/Packages 31eb996dfd1d5776f2eef79a265b3bc897fe8c36 7876 main/binary-armhf/Packages.diff/Index ccf4c1b0c55a9999f0be5907dc6a493f1b832d96 8752490 main/binary-armhf/Packages.gz 99e4669feeb747d2f8e1f035de8935c711b37036 6553496 main/binary-armhf/Packages.xz 98ff75cef0e03c386e133b4e1be7b2c8c43c2526 83 main/binary-armhf/Release cec480b952578bf20fc0bffdc59859e2b7f629f9 29457485 main/binary-hurd-i386/Packages 79634755deccd4d7ca37be6bfe6b7a5b4b1ae271 7876 main/binary-hurd-i386/Packages.diff/Index dc0d7e7a7425c6ef11a2bef16f929bda0fc6f51c 7820791 main/binary-hurd-i386/Packages.gz 36b65ebb30659f946d70748a552afd39d750f021 5871368 main/binary-hurd-i386/Packages.xz c149ce687b03adf36b4d3920457be9d3f20cc163 87 main/binary-hurd-i386/Release 9210ef101dae06c0c137f63dd78d84f2cb1d6b45 33606129 main/binary-i386/Packages f8742d3c01ac976ccfc96e5736ac09e8d7cf63ab 7876 main/binary-i386/Packages.diff/Index c0f4d7095570200798a86f4eada7a3c58214da42 8997921 main/binary-i386/Packages.gz d3edad31c5f90517577e8e9952ab34b61ba943c6 6732360 main/binary-i386/Packages.xz dea61efa7fed463c032671482596761b7af2415a 82 main/binary-i386/Release 62e514b35a27fd0f8640f888a40d2ddd807554b7 31615279 main/binary-kfreebsd-amd64/Packages 18ee6a6518f93f2a2b1bb0001b0087db83376c67 7876 main/binary-kfreebsd-amd64/Packages.diff/Index 162aedff4417558f0baf8134e6b8f9092c8877db 8337837 main/binary-kfreebsd-amd64/Packages.gz f7b2afe46ba7e8e56b4ef0f7fdb861b4952d5954 6249852 main/binary-kfreebsd-amd64/Packages.xz 6e85c89395958d096e06767671f43e646fb92a12 92 main/binary-kfreebsd-amd64/Release 329c12d81383dcb9fbae69f1b3132d2910ed98c7 31551588 main/binary-kfreebsd-i386/Packages e39f598958f2774e98cd5db00e051019db3c3e40 7876 main/binary-kfreebsd-i386/Packages.diff/Index 645328c1751e347dfe849dab972eec2ca7aa9471 8332623 main/binary-kfreebsd-i386/Packages.gz 71c98cd5498687a9fd33a625d2166e61ea3c0ea4 6247780 main/binary-kfreebsd-i386/Packages.xz df74b1257bd084c54b3399ff9c22a7029b6ae230 91 main/binary-kfreebsd-i386/Release 6dbdd45dd850ac0e827e68b7d86d61ea7faf274e 32480079 main/binary-mips/Packages ba73d2485e1561430cc2274e31e9ba308033a7fb 7876 main/binary-mips/Packages.diff/Index f65081e2ba6e2dbc4a01430947696098f01159da 8716064 main/binary-mips/Packages.gz fea8a576dba323486c4effd7999c55ed23f3c238 6524920 main/binary-mips/Packages.xz cc333596aa0741e32ddcb44609770b45ff0c52a0 82 main/binary-mips/Release 8fd23b51d84139efb1a1d027aca517fedb3237c6 32596356 main/binary-mipsel/Packages bbf21dc60627bcdb5b5924730413fafb5e440425 7876 main/binary-mipsel/Packages.diff/Index 5bfcfa8ee9965cd4e3e1705d6cc90502274dbd7c 8728556 main/binary-mipsel/Packages.gz 7c7170726cce4f5d7e1a0d93afe9221f62d7a5cf 6535216 main/binary-mipsel/Packages.xz 9894f04b1af775286cd7c93daefa823dc1882e63 84 main/binary-mipsel/Release e62fdd43dc61c6c1d1c5e0f56a2232d98d023a4e 33154230 main/binary-powerpc/Packages a6fc61fd944ced94536d9744e5fe0ae2d663c034 7876 main/binary-powerpc/Packages.diff/Index 46a046deb07b708c0e3dcee98058ef06f620f12b 8848733 main/binary-powerpc/Packages.gz 13834d35131bfdf70f95722ee6c36241da75eeb9 6623544 main/binary-powerpc/Packages.xz 190bbd38800b218f71aed72ab71cb5748866f14c 85 main/binary-powerpc/Release 84debdb7715f6b769f5f5bcc02e68d4a970f1278 32297598 main/binary-s390x/Packages 31eb996dfd1d5776f2eef79a265b3bc897fe8c36 7876 main/binary-s390x/Packages.diff/Index d30d7b98fb850331e60d3f1c7f9fad274e01c08b 8657047 main/binary-s390x/Packages.gz f6e81f34ae01c59a375eab252db20a199a6a655d 6481076 main/binary-s390x/Packages.xz fd74b9ec778d495c0aa2477da8afb393c3761381 83 main/binary-s390x/Release 7dd211be3fa631c03febc58c71d8b9d0e8c219ee 32390467 main/binary-sparc/Packages 6e2a42ab1fb5bb70fe1804bc5a8acc347abb085e 7876 main/binary-sparc/Packages.diff/Index 5c829f06228bb581a7cd0280515946162331c336 8675573 main/binary-sparc/Packages.gz 4f779d9f31df273cb633e73cc56cfabf4cb0af91 6495944 main/binary-sparc/Packages.xz c0610e86a744e9f5bda1aee1b098e9fc98dde1cc 83 main/binary-sparc/Release 95e907ab56bd161535c687136b102bb3d9efbab2 71965 main/debian-installer/binary-all/Packages 4f1ebe15bda85d7b9abebc6905aadf6a53e11bfc 20810 main/debian-installer/binary-all/Packages.gz bd313b4f51b97238057fd09a6866c7c623b348d7 18100 main/debian-installer/binary-all/Packages.xz 5db37fb1d8a09567d5215170cd04a0a6fa959b91 81 main/debian-installer/binary-all/Release 0bbd278ca6060a60530f6a1ef4a150363db19013 271101 main/debian-installer/binary-amd64/Packages d89343d07d353194781a67b1aaf931091424a210 73559 main/debian-installer/binary-amd64/Packages.gz eab0e9a753b73c685dab891c857d34307857ced0 62096 main/debian-installer/binary-amd64/Packages.xz 0ddf4927eb3db059ab4583e346c7e489dd11b373 83 main/debian-installer/binary-amd64/Release efe1a63d8a852a2b1cc57ff88252f35ccf094f5c 327884 main/debian-installer/binary-armel/Packages 5f3b295124a1d25844264253eb77453f293279b2 82972 main/debian-installer/binary-armel/Packages.gz c7774350db5e2f49b90b41319df9e5a76e6a74b2 69496 main/debian-installer/binary-armel/Packages.xz 5fe3326149ae392bc6badb1c48f50775215c7432 83 main/debian-installer/binary-armel/Release 7413a5116f72984e492d21b386cb443d0b71cbb3 215371 main/debian-installer/binary-armhf/Packages 0ae830da4fa2a9e7d6050565a76301813ffa31f3 62714 main/debian-installer/binary-armhf/Packages.gz a1902cff42e121b9785fd8dcec41664ac668f6b8 52924 main/debian-installer/binary-armhf/Packages.xz 98ff75cef0e03c386e133b4e1be7b2c8c43c2526 83 main/debian-installer/binary-armhf/Release 9d98dc835ed078f656c8b430ef2b0bb455713342 164280 main/debian-installer/binary-hurd-i386/Packages 5393ff7cdf348f4140a5336293406a90af149b46 48130 main/debian-installer/binary-hurd-i386/Packages.gz 674d1979b45541c6c47acb8bd8a3ba5aad7114aa 40652 main/debian-installer/binary-hurd-i386/Packages.xz c149ce687b03adf36b4d3920457be9d3f20cc163 87 main/debian-installer/binary-hurd-i386/Release 91a6bfd59766716b9493ec8874f4cbcbcf7e8583 345491 main/debian-installer/binary-i386/Packages f3a4ed61691fbc6a177a5764b4f452204caa315b 86948 main/debian-installer/binary-i386/Packages.gz d7921006fc04a8cc16b1f627e00d80a692a60b53 73012 main/debian-installer/binary-i386/Packages.xz dea61efa7fed463c032671482596761b7af2415a 82 main/debian-installer/binary-i386/Release e3397463fcc8387a77969a2f4d205b76f7c68831 225819 main/debian-installer/binary-kfreebsd-amd64/Packages 08d35e604313facedb002aab9c39b1a0473f6935 61365 main/debian-installer/binary-kfreebsd-amd64/Packages.gz 047a694caa207f76622a2ab5dc157646a3da3ccc 51708 main/debian-installer/binary-kfreebsd-amd64/Packages.xz 6e85c89395958d096e06767671f43e646fb92a12 92 main/debian-installer/binary-kfreebsd-amd64/Release 568dac87d844880df13d05b8f072eea670440ee2 224725 main/debian-installer/binary-kfreebsd-i386/Packages 384a00a6482adc16f2534901b4dc2cf2f1a2b8ba 61102 main/debian-installer/binary-kfreebsd-i386/Packages.gz 5508d2584499f1d757c3033c5348da8da984e10e 51660 main/debian-installer/binary-kfreebsd-i386/Packages.xz df74b1257bd084c54b3399ff9c22a7029b6ae230 91 main/debian-installer/binary-kfreebsd-i386/Release 11ab7d0c02b67932c2eb2188bf9f9ea88e4da5cf 271887 main/debian-installer/binary-mips/Packages 76397aad4bd0f87b8c2b4363383b760e1f518c94 72939 main/debian-installer/binary-mips/Packages.gz 90a18b274cc05783769b73d21a17b043afa4aeaf 61176 main/debian-installer/binary-mips/Packages.xz cc333596aa0741e32ddcb44609770b45ff0c52a0 82 main/debian-installer/binary-mips/Release 4db98b101d0fe7bfd359f15fc0aad9d572566e6a 268044 main/debian-installer/binary-mipsel/Packages 758268d1881ee16cb5166c5502a6537b07447068 72122 main/debian-installer/binary-mipsel/Packages.gz 42cc82f316e261f2784c7298107a0de99baad39d 60384 main/debian-installer/binary-mipsel/Packages.xz 9894f04b1af775286cd7c93daefa823dc1882e63 84 main/debian-installer/binary-mipsel/Release 31abaddfd8d8c5c901588cf8b1fd8e2ff6446e29 326190 main/debian-installer/binary-powerpc/Packages 37994773d8fa7b9e0e8568b0520396656459de7e 83151 main/debian-installer/binary-powerpc/Packages.gz 7eb0cece2187878e71d3df89172c7a88d06dec01 69520 main/debian-installer/binary-powerpc/Packages.xz 190bbd38800b218f71aed72ab71cb5748866f14c 85 main/debian-installer/binary-powerpc/Release 06e9351cad0c426ccd904bd0204c795f4ae5cb79 211381 main/debian-installer/binary-s390x/Packages e28869ebb1e3f0f37137c6bf0ebad24ce6655204 61216 main/debian-installer/binary-s390x/Packages.gz d067ca8122d43611445657373d46f3e7ca4ccc98 51472 main/debian-installer/binary-s390x/Packages.xz fd74b9ec778d495c0aa2477da8afb393c3761381 83 main/debian-installer/binary-s390x/Release f6a58785fed01644c3b0a96a543f13d645410bf6 211987 main/debian-installer/binary-sparc/Packages 151d07bf4024610d594f956c267f4156af4ff258 61792 main/debian-installer/binary-sparc/Packages.gz d511fe5ec8db07ea1953f06faa17297de69e47bf 52084 main/debian-installer/binary-sparc/Packages.xz c0610e86a744e9f5bda1aee1b098e9fc98dde1cc 83 main/debian-installer/binary-sparc/Release 11f760d88b75886e7ff29f19722335a0e8342e04 10212 main/i18n/Translation-ca c4dc361fe379a7373352f3246018466d1e5ba9af 3986 main/i18n/Translation-ca.bz2 d6fcdc620d78e6dd219525d5c0613a7946f5cf22 3265 main/i18n/Translation-ca.diff/Index 7afc046abe3f08811a774d7a7b2b30846e9c4c00 2083334 main/i18n/Translation-cs 95d510463eb400d7862b5c65ab74f2d7ba2de261 541607 main/i18n/Translation-cs.bz2 79137d1ed54f0e7d4d8fdf20a1cfd963ebbd7000 7819 main/i18n/Translation-cs.diff/Index 84362c195ab2906529f1d4022a58e5a40b5fb842 10917248 main/i18n/Translation-da c1d1f8f564375eb73e2577ab8cea3aff2b8b1d2f 2381081 main/i18n/Translation-da.bz2 82b79b609c03f390c3bd1a062046f11a47f34d71 7876 main/i18n/Translation-da.diff/Index f3079580873efc45567a952e82c0c9780e570d72 7811636 main/i18n/Translation-de 0d89da9fa80e70340a8ea48cb0a8e4e9be857920 1783651 main/i18n/Translation-de.bz2 942491adfb6ea84005a042b9dc323465a3be669f 7819 main/i18n/Translation-de.diff/Index 9cefb0051f9503cdcc848113ddd850abc2d8fd44 1347 main/i18n/Translation-de_DE c06dc96d1de20832869e5e4b9867e203244228c1 830 main/i18n/Translation-de_DE.bz2 5d0c67cc346a0bc1a7e68c90c256e8f82221939b 8287 main/i18n/Translation-el 8af68a2c14ce1de6ad2ddff6a8154a73b6e386fe 1896 main/i18n/Translation-el.bz2 fa39eee49a9f15221592541edcd10b8618074d9a 643 main/i18n/Translation-el.diff/Index 73ad40f7016a9543f3e7689053326aa9903628a8 22533282 main/i18n/Translation-en 2ca6883643faaac06fcccbe29ccbc0bd625f7bdb 4576178 main/i18n/Translation-en.bz2 2bfedbeda436f1f14626e3e494315b9e288411a1 7876 main/i18n/Translation-en.diff/Index 1040fcc74538581d2aecfd965557b41aafcb6a42 1504 main/i18n/Translation-eo ab3ef86a2608e7f1bd9d606836eed169f8861744 811 main/i18n/Translation-eo.bz2 2ea8064b527bc75c6f112da6e684a81941366269 781 main/i18n/Translation-eo.diff/Index 6407c18c1d4357b2869b9dbb031d5bbf1b9d190e 1356430 main/i18n/Translation-es 97c581c8463acb9f65e3605b4daf93f5b5c3dad4 327604 main/i18n/Translation-es.bz2 19330eed76a084ab4222d0f9f13244f6e5209b79 7819 main/i18n/Translation-es.diff/Index ef33578fb369dbd52ff2377877ff4e84796bd95c 17600 main/i18n/Translation-eu 72846e03c0ab767c3f8fc3d1440708b616920324 6545 main/i18n/Translation-eu.bz2 bec097d67301f837b3dfd703c19ec51c3ba15ed2 6163 main/i18n/Translation-eu.diff/Index f3b7de8911c6dec9eb8c95a052d53fe883025a5d 420323 main/i18n/Translation-fi 9566f50ba6126faed033e92cc1a1e156819f1ab5 115357 main/i18n/Translation-fi.bz2 6a3cbb9d99d86c07410d84399936529df229dfa5 7819 main/i18n/Translation-fi.diff/Index 4c872674cad460916075aff81036253f35c3fc86 3325423 main/i18n/Translation-fr 8048e62789e5a4e1e6cf80c953a1cad9b56ed6a0 742555 main/i18n/Translation-fr.bz2 6bb6f1863966dd68433665105dba90e93b3cc079 7819 main/i18n/Translation-fr.diff/Index 8c47332910739c52a61498b391b0c02e5d23360f 16814 main/i18n/Translation-hr e823045e42e3879f9d8eb903e0fa6781b7ad0e9a 6426 main/i18n/Translation-hr.bz2 fc30ee63887824df3166538998d9ec728780b820 4645 main/i18n/Translation-hr.diff/Index b0d1f7611f345a6c01484f2fc62c959c184263d1 110436 main/i18n/Translation-hu 9db370e9260ac2aedad39cff46d9c19d34135a92 35714 main/i18n/Translation-hu.bz2 70dcc7f68fc53bd7cac08fcd58db3d6907eaf5f1 7819 main/i18n/Translation-hu.diff/Index efa4d1d37013def2a438e1fc7d9e6510d7265af6 7753 main/i18n/Translation-id 4ac4429526acd4c4049527e9a223b67e0d938f75 3093 main/i18n/Translation-id.bz2 46b9b9b93e6c2c051671f624ffa085518146a963 3127 main/i18n/Translation-id.diff/Index a5d435d208dd97776a91dbe43e0340cc66426bb0 15963337 main/i18n/Translation-it 525079c07ba0e7742df311c2ddcb0e654ab9f3bf 3236630 main/i18n/Translation-it.bz2 f1756b239e205050896a1613befd655c02043711 7876 main/i18n/Translation-it.diff/Index 66617881d5420ae7a3c3c34d571812e4b11ab57c 4326439 main/i18n/Translation-ja 696a0895fd4396552b74e1d36b0269e388d8f2d5 795115 main/i18n/Translation-ja.bz2 f5c7eaf536bb76c501f3e1aec0047edbc8cc0061 7819 main/i18n/Translation-ja.diff/Index 1f946f87effb1a3083cc7ee4eafcade5a4603701 19391 main/i18n/Translation-km 923212bf4f845c53eb2d8f5a3b45e16b29884da9 3611 main/i18n/Translation-km.bz2 f3b7434280a9d4e12e0ed22595a282a7330128c3 3541 main/i18n/Translation-km.diff/Index 36fff17c418bddcde6326ee008f612fea4d6c2d5 466233 main/i18n/Translation-ko 20506fe1b26f2cab652a66a34adfe34a31610cda 108418 main/i18n/Translation-ko.bz2 c8639c766ffaef1a1cfcb46cf08045ff3eba6970 7819 main/i18n/Translation-ko.diff/Index da39a3ee5e6b4b0d3255bfef95601890afd80709 0 main/i18n/Translation-ml 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 main/i18n/Translation-ml.bz2 9fbff159cc2eaf3fd168faf673b9417abda11921 2325 main/i18n/Translation-nb 0a1d5e9c472db52dfa34ff9d17d3cdd3fed95f65 1302 main/i18n/Translation-nb.bz2 f81564c057e3acc8bfc22000fcff4a1fb87b018b 367 main/i18n/Translation-nb.diff/Index e3558a6ad46a50c7d4e6a3271c13165912c6cb31 303930 main/i18n/Translation-nl 441c852bced2774c8d24ea52eea7105ed2ca2c04 82529 main/i18n/Translation-nl.bz2 c73a77927132e69d0143ad149d0e2657ecbd074a 7819 main/i18n/Translation-nl.diff/Index 4771a5b595c96a0ec91896fe4116c2c69217dc59 2529869 main/i18n/Translation-pl 0767ce102b799b7fafd03db7ed031a64480c21ca 572467 main/i18n/Translation-pl.bz2 2df35adaa654de4f3eec1185a43a0b250304acb5 7819 main/i18n/Translation-pl.diff/Index ba55ae32c0afe579a953d8f7cf0842b74c4a0279 1862609 main/i18n/Translation-pt 4450924b786b702c61251d40668cd4d6fe1d8bca 453214 main/i18n/Translation-pt.bz2 c9f5fdb81630cd34f495f9ba163b1f9a049f3e6c 7819 main/i18n/Translation-pt.diff/Index 9bea9e90591f9cb93f0ea4e307df3d60ff945b6d 3043569 main/i18n/Translation-pt_BR 5012b48fa01a656b849766b0fe6e1cb61e5b3ba7 734688 main/i18n/Translation-pt_BR.bz2 9b4df3c5ed50ea32b17ccf0f1a66802dc4fa72a6 7819 main/i18n/Translation-pt_BR.diff/Index 0e79d618838b9ecf1e0d8ff3a2834e9fff8eb5a3 2949 main/i18n/Translation-ro 6edd468ced1103b7ca5647514d47270e7c0b5b07 1463 main/i18n/Translation-ro.bz2 79375858d2bfa27f9bee85fc1c10273c020ee939 1195 main/i18n/Translation-ro.diff/Index 68c2fe5839360149f200746b582edbfa609cd9a7 2563200 main/i18n/Translation-ru f8ea35c2fafac05d89ed9c187ce5613e021715ba 420970 main/i18n/Translation-ru.bz2 c993789042e4d5f6a9965d97efacdf259d2455f7 7819 main/i18n/Translation-ru.diff/Index 0ff6b9a003b8f9367c47cf1389b62cf4dd6a64ac 1804527 main/i18n/Translation-sk c5d680cca5c8ffaf82dd924968b2c2291a066fc0 427527 main/i18n/Translation-sk.bz2 90c388c0439607f30e4eba167b339d62782b3849 7819 main/i18n/Translation-sk.diff/Index bd875f843ef0f0b7dd0c5e4d6cde2172290547df 403940 main/i18n/Translation-sr 74d02fe04e1d66c4a8f76380d373bf79efd12ce2 71417 main/i18n/Translation-sr.bz2 203c913e20a598bb67b98f5f516641eb828bf0b7 7819 main/i18n/Translation-sr.diff/Index 08f13b45c78263cb0a06d2c98c68ffb25d44fdbe 139255 main/i18n/Translation-sv 35729c6c1fc65bad71abffac3964bb3125e9e214 41556 main/i18n/Translation-sv.bz2 02c236c5ab40b857c5361a1fe30845394a1b7076 7819 main/i18n/Translation-sv.diff/Index 9ce93c94dc38553c9f65d861bd8db0b5570d7bb7 902 main/i18n/Translation-tr e7b035cf84219392b6bf5eacec4e629ed7327ace 530 main/i18n/Translation-tr.bz2 94878c05f0f21c22ed650be7963596d88f4942b8 4999044 main/i18n/Translation-uk 27c51ad3759caf2bc90705fadbda9e4c018f7cd5 784640 main/i18n/Translation-uk.bz2 dc80cce434274a2b9f47cbeb557cd44322925204 7819 main/i18n/Translation-uk.diff/Index 3d69c015ff79a51c53fc895111353e7ae5d329fd 38901 main/i18n/Translation-vi 941d90e2d0a0878736a15af83626580f33041a5f 11052 main/i18n/Translation-vi.bz2 775aa532db0831eb62f1dbe1b50818713e11c415 7819 main/i18n/Translation-vi.diff/Index 594f432d94fc9cdc2a871e82ca007497a853b0a8 2799 main/i18n/Translation-zh 8a1732ac15d1a1a841e2f46dec4747db8a406ea5 1526 main/i18n/Translation-zh.bz2 1635d3f0b7a2b5a8a55ef3a5ddbbc56bcb840c38 1609 main/i18n/Translation-zh.diff/Index d2b724b526a8ce4e4d0ac24a2f537e8f828d5da0 417827 main/i18n/Translation-zh_CN 7083b1e1a5d66e06e6ab76f6146682e3ce9c6afc 113341 main/i18n/Translation-zh_CN.bz2 d686b17fcb6b9750ca2500b91f2e845e51345b22 7819 main/i18n/Translation-zh_CN.diff/Index 57f02da525d88db843cc72019b4f3d45706f5c56 65883 main/i18n/Translation-zh_TW 84f44589d7ff951d69e798a5f8da38670082e9a5 23191 main/i18n/Translation-zh_TW.bz2 d78e0f30459a9101ee21240d9b0338b492c3b8a0 7819 main/i18n/Translation-zh_TW.diff/Index dc00965b08011adb3ac0e2ef5ce1f331e398a83c 10309 main/installer-amd64/20130430/images/MD5SUMS b816e73c74681bac8cae30557d4f9e8e53dcca5d 14289 main/installer-amd64/20130430/images/SHA256SUMS 70c1cdc305643729939519a4327b1a28d5c137db 10309 main/installer-amd64/20131014/images/MD5SUMS e4360642182cd9f8f0200817425e919499665c33 14289 main/installer-amd64/20131014/images/SHA256SUMS 5ca60550882fa8792df62373dfd1fd60497fe0aa 10309 main/installer-amd64/20131211/images/MD5SUMS d30d6cbae3530381de8713329113aa28b9cd6255 14289 main/installer-amd64/20131211/images/SHA256SUMS 51199314778678d3b11de88859b7b94f176b9014 10309 main/installer-amd64/20140208/images/MD5SUMS 61b92a4a9942d0ea945ef49280b015cfbf50f24f 14289 main/installer-amd64/20140208/images/SHA256SUMS 54af1b4ab59ac2c2f43a9181be042738516e1994 10323 main/installer-amd64/20140316/images/MD5SUMS 6d650ed4bf8042d664daeb5a51780237bd278339 14303 main/installer-amd64/20140316/images/SHA256SUMS 54af1b4ab59ac2c2f43a9181be042738516e1994 10323 main/installer-amd64/current/images/MD5SUMS 6d650ed4bf8042d664daeb5a51780237bd278339 14303 main/installer-amd64/current/images/SHA256SUMS 7f9c5538a84385a6e6e1a1caa15dbbadf4920987 4807 main/installer-armel/20130430/images/MD5SUMS 4a2cd937c165d1af920c5fbad171f623d57f862c 6835 main/installer-armel/20130430/images/SHA256SUMS 36310627bb0cab1641d8983eb6bc4046a2c3c1fb 4751 main/installer-armel/20131014/images/MD5SUMS 03871a8c6c087957c11f16af1d28349da77b4e4b 6747 main/installer-armel/20131014/images/SHA256SUMS 15b7d99f3e112cf40e980691f78f268a6284846e 4751 main/installer-armel/20131211/images/MD5SUMS a38f675f485824d4af1f1b8980cbb40164f74a1a 6747 main/installer-armel/20131211/images/SHA256SUMS 98371041db659636351a7fc150303ab4cf733dec 4751 main/installer-armel/20140208/images/MD5SUMS 48e6ff0f8334e9dfc650024d6e454d176d92c2a9 6747 main/installer-armel/20140208/images/SHA256SUMS 655510e099b782ca2a6686db50eadef99d9833cc 3612 main/installer-armel/20140316/images/MD5SUMS 9c37dc62ff71d90fd4b9be70564c2f0a177bddb1 5128 main/installer-armel/20140316/images/SHA256SUMS 655510e099b782ca2a6686db50eadef99d9833cc 3612 main/installer-armel/current/images/MD5SUMS 9c37dc62ff71d90fd4b9be70564c2f0a177bddb1 5128 main/installer-armel/current/images/SHA256SUMS 12942d14e54870b9a53b3cec865a8e22d0b4dc4e 1108 main/installer-armhf/20130430/images/MD5SUMS ad72c6c4b778c6f71eeded4c5366a32cfc1c027b 1728 main/installer-armhf/20130430/images/SHA256SUMS 3a731c1753e575d61c330895691a2618a2c656d4 2373 main/installer-armhf/20131014/images/MD5SUMS 911daffa160fd1a8f8bb08014f04538ad90a940d 3569 main/installer-armhf/20131014/images/SHA256SUMS 858ca246ed228bd6b3d1d6f13678cd4e050d5fc1 1408 main/installer-armhf/20131211/images/MD5SUMS 0fdfb0b739ad5551510ed6f456ce678a53cb4976 2156 main/installer-armhf/20131211/images/SHA256SUMS 2c41d41adfd006fcd4dc5f30c709a4d8e51008a3 1408 main/installer-armhf/20140208/images/MD5SUMS 2dc06450c5679d785ced07089adc0a059d94fbd5 2156 main/installer-armhf/20140208/images/SHA256SUMS f22077e5d5d7e75d1a2e50c50e63e4051a67ef02 1408 main/installer-armhf/20140316/images/MD5SUMS 2e117f5d86051520e6a9ca53e0688062d11a25ed 2156 main/installer-armhf/20140316/images/SHA256SUMS f22077e5d5d7e75d1a2e50c50e63e4051a67ef02 1408 main/installer-armhf/current/images/MD5SUMS 2e117f5d86051520e6a9ca53e0688062d11a25ed 2156 main/installer-armhf/current/images/SHA256SUMS 49854da45639bb5a8f96b609aeae30bbe2eca3b3 10215 main/installer-i386/20130430/images/MD5SUMS f3fda001f2b57cf851bdd3d5d5ce128be38b86e9 14195 main/installer-i386/20130430/images/SHA256SUMS 4f8daeceeae8f963d53281a9950a834b3a87c04f 10215 main/installer-i386/20131014/images/MD5SUMS 7174c2b59bd216941bd2f83b42cc4ccc0ea42abf 14195 main/installer-i386/20131014/images/SHA256SUMS dcc08b333ab65d5ef9c9c6d99c26754dad771e3a 10215 main/installer-i386/20131211/images/MD5SUMS b9c3c30c3f044b053fdf2728194eea7748c0186b 14195 main/installer-i386/20131211/images/SHA256SUMS e9b1990f62011e3092a5484af0e6639e4a6a57dc 10215 main/installer-i386/20140208/images/MD5SUMS 4bf59b8ff93fd8f7f489aa81d4f25c06695006db 14195 main/installer-i386/20140208/images/SHA256SUMS 039dcaed86620994fd028917cecadc6c4bc89c68 10229 main/installer-i386/20140316/images/MD5SUMS 9bb1e75085672d44ac82bb480d08803bb2f0539c 14209 main/installer-i386/20140316/images/SHA256SUMS 039dcaed86620994fd028917cecadc6c4bc89c68 10229 main/installer-i386/current/images/MD5SUMS 9bb1e75085672d44ac82bb480d08803bb2f0539c 14209 main/installer-i386/current/images/SHA256SUMS 9afe4acf4a8fbdfafae4ebb2d89dfd4884e99152 3446 main/installer-kfreebsd-amd64/20130430/images/MD5SUMS 2071fa12cf30c67ac7e4cae81298dd5f7acbe3d4 5026 main/installer-kfreebsd-amd64/20130430/images/SHA256SUMS 4e7551e4e3e57ae717b7e88db50738fb8d8ae85c 1936 main/installer-kfreebsd-amd64/20131211/images/MD5SUMS 41c9d598c18f2b515c0fa3b3651f290eaaa87a3c 2876 main/installer-kfreebsd-amd64/20131211/images/SHA256SUMS e8f38832a0b4c228f53c525c1b1fcbccdb405d27 1936 main/installer-kfreebsd-amd64/20140208/images/MD5SUMS c994d77155f71891d0418c5b98685f217b966ee6 2876 main/installer-kfreebsd-amd64/20140208/images/SHA256SUMS fea19fddcca7399e0fbd9f1103f55a088561d2a6 3768 main/installer-kfreebsd-amd64/20140316/images/MD5SUMS 9fc5167e9094622a95a1becde2b144790f0ea448 5476 main/installer-kfreebsd-amd64/20140316/images/SHA256SUMS fea19fddcca7399e0fbd9f1103f55a088561d2a6 3768 main/installer-kfreebsd-amd64/current/images/MD5SUMS 9fc5167e9094622a95a1becde2b144790f0ea448 5476 main/installer-kfreebsd-amd64/current/images/SHA256SUMS f7e8979b84e23c63647ba86901048d34cbaca118 1738 main/installer-kfreebsd-i386/20130430/images/MD5SUMS 0c33885d249c1e003fc037b8d988af2577cfd473 2614 main/installer-kfreebsd-i386/20130430/images/SHA256SUMS 7a523339ae37ace4bab03f4c09fd5822d153d18a 1009 main/installer-kfreebsd-i386/20131211/images/MD5SUMS cae10d2969aea0d5325ed7c6cfc110116cd8e9d6 1565 main/installer-kfreebsd-i386/20131211/images/SHA256SUMS dd4039226de95a91060f1dbb69d82274faec813f 1009 main/installer-kfreebsd-i386/20140208/images/MD5SUMS b441fd6e7e85c1999dcab83537b1cab3e06c8812 1565 main/installer-kfreebsd-i386/20140208/images/SHA256SUMS 708da5f36a467e956ac512e5fcdfcdd228a9c33d 2088 main/installer-kfreebsd-i386/20140316/images/MD5SUMS 2cc82a4ddb3993fd3b844c5c61549e732d1414b3 3124 main/installer-kfreebsd-i386/20140316/images/SHA256SUMS 708da5f36a467e956ac512e5fcdfcdd228a9c33d 2088 main/installer-kfreebsd-i386/current/images/MD5SUMS 2cc82a4ddb3993fd3b844c5c61549e732d1414b3 3124 main/installer-kfreebsd-i386/current/images/SHA256SUMS a82bf419dae346c4bf90cdc2a5657b93f465a144 802 main/installer-mips/20130430/images/MD5SUMS df0be2681f0ef742cf64ebc4f4d9cba6e789f60a 1294 main/installer-mips/20130430/images/SHA256SUMS f1fd23c8fd992055cf928ded6951d62d1c1659a0 800 main/installer-mips/20131014/images/MD5SUMS 656e61057c19ae16e19892e77a279c1bafd49cc1 1292 main/installer-mips/20131014/images/SHA256SUMS 37e0969602d9ed666cd8e2482332b0aa7ee6de25 800 main/installer-mips/20131211/images/MD5SUMS a4b0b4546c8ead20953228c34aade6a3eac3973a 1292 main/installer-mips/20131211/images/SHA256SUMS 9ecb077d06f05ac046b89b98aaa6f79e5358258c 934 main/installer-mips/20140208/images/MD5SUMS b8b4c0ccd1b351233f995a82c65efe4e5c1d8b48 1490 main/installer-mips/20140208/images/SHA256SUMS 0dfad0cee5211ba58303308f0504b30125984a5a 934 main/installer-mips/20140316/images/MD5SUMS a9e7e9832408efa5a3f847f1d6a8d396abe4b24e 1490 main/installer-mips/20140316/images/SHA256SUMS 0dfad0cee5211ba58303308f0504b30125984a5a 934 main/installer-mips/current/images/MD5SUMS a9e7e9832408efa5a3f847f1d6a8d396abe4b24e 1490 main/installer-mips/current/images/SHA256SUMS 6ae8c5179a9d9c3d38b2a503a32dff5866dc86dd 1342 main/installer-mipsel/20130430/images/MD5SUMS 8f37a7fadd8839cbbe27665cf2fe53affec44844 2058 main/installer-mipsel/20130430/images/SHA256SUMS d5895a5b717686c67b6e88991e6c551970f54f12 1338 main/installer-mipsel/20131014/images/MD5SUMS cb3baa27245f1f7882367debde3bb479705dfd25 2054 main/installer-mipsel/20131014/images/SHA256SUMS e8fdd0d4c3c8cdd4e4006d1f133ce671803b2084 1338 main/installer-mipsel/20131211/images/MD5SUMS 59def0e93442b15c2ec3e6559578b28098af1537 2054 main/installer-mipsel/20131211/images/SHA256SUMS 1abd0b06f9266fa816b2939c4c1bdd5018190635 993 main/installer-mipsel/20140208/images/MD5SUMS 84fdd0d1de16b5464b3b5f04f8ce12c0dd8156ab 1549 main/installer-mipsel/20140208/images/SHA256SUMS 62f4559a6c6660c266b2c571100c5e6972a2271b 993 main/installer-mipsel/20140316/images/MD5SUMS 172002a5812ba7517341155fe62043343acd352d 1549 main/installer-mipsel/20140316/images/SHA256SUMS 62f4559a6c6660c266b2c571100c5e6972a2271b 993 main/installer-mipsel/current/images/MD5SUMS 172002a5812ba7517341155fe62043343acd352d 1549 main/installer-mipsel/current/images/SHA256SUMS 65c80a8ced27f07707031e8d039bbb3ccfd6e869 2128 main/installer-powerpc/20130430/images/MD5SUMS f679448fb845ce17964962554664bf4645cd17ed 3292 main/installer-powerpc/20130430/images/SHA256SUMS c7665afd0be6941748000bc6df12d141231d378b 2128 main/installer-powerpc/20131014/images/MD5SUMS b1ec81a26e88a04e323dd33ceffbe283ddce0ddd 3292 main/installer-powerpc/20131014/images/SHA256SUMS 6f90d574e287c126ff7c93b572a00b138fc45844 2128 main/installer-powerpc/20131211/images/MD5SUMS dada0869fbffdfe4c3652bdda7ded1491f603945 3292 main/installer-powerpc/20131211/images/SHA256SUMS c25dbfe48f44df78a3a504b0aa8dc901adb5724e 2128 main/installer-powerpc/20140208/images/MD5SUMS 0cdf8adf81f0a6b44709bd1653ff1f4cff60cef0 3292 main/installer-powerpc/20140208/images/SHA256SUMS 17edc9e25e116219067b720eecac05d37e148e75 2128 main/installer-powerpc/20140316/images/MD5SUMS a88d5f23766b8117c579a172a6b6e93163e0ca0b 3292 main/installer-powerpc/20140316/images/SHA256SUMS 17edc9e25e116219067b720eecac05d37e148e75 2128 main/installer-powerpc/current/images/MD5SUMS a88d5f23766b8117c579a172a6b6e93163e0ca0b 3292 main/installer-powerpc/current/images/SHA256SUMS 48dbd078528cf8ca9bc9f7a525702391bf42d694 604 main/installer-s390x/20130430/images/MD5SUMS 70c47a76e70132cf786406ffb3aba7fb75772953 1032 main/installer-s390x/20130430/images/SHA256SUMS a099bbac7772f0ef849b365f321c0619f23f5844 374 main/installer-s390x/20131014/images/MD5SUMS f87ae4098766b7275d35c78d08f55e9556a17438 674 main/installer-s390x/20131014/images/SHA256SUMS 09410f452a7c8c80c7e40832efd47365ef97ffce 374 main/installer-s390x/20131211/images/MD5SUMS fe18497d4c5078cb04c36ee872fb6e6d682d4370 674 main/installer-s390x/20131211/images/SHA256SUMS b4a3337e477d9ad730cb3676a8d71d4f6b962528 374 main/installer-s390x/20140208/images/MD5SUMS c114c8259bf15492a6bb480d642cacda07428952 674 main/installer-s390x/20140208/images/SHA256SUMS 6661786a94952ffb601c561f86aefbc6ba05ba8d 374 main/installer-s390x/20140316/images/MD5SUMS 651c7fed830b28ffcfca727bf8dfd396a4c84a1f 674 main/installer-s390x/20140316/images/SHA256SUMS 6661786a94952ffb601c561f86aefbc6ba05ba8d 374 main/installer-s390x/current/images/MD5SUMS 651c7fed830b28ffcfca727bf8dfd396a4c84a1f 674 main/installer-s390x/current/images/SHA256SUMS 40ae15a8d50678b2c47c81e56d3d64d9cf07c4cd 358 main/installer-sparc/20130430/images/MD5SUMS f90665142b85f3d097a724ee21b97b06b8c78d56 658 main/installer-sparc/20130430/images/SHA256SUMS 597f93448909fe0ddba368b3d021d30a4cf3ad72 357 main/installer-sparc/20131211/images/MD5SUMS 5742e61ae11b38b1a2befc0e1546807c4e3d6398 657 main/installer-sparc/20131211/images/SHA256SUMS 597f93448909fe0ddba368b3d021d30a4cf3ad72 357 main/installer-sparc/current/images/MD5SUMS 5742e61ae11b38b1a2befc0e1546807c4e3d6398 657 main/installer-sparc/current/images/SHA256SUMS 9c96130a5b8ffc622bce8b121efdffaf8421fc9d 84 main/source/Release d8cd6c141e0fadb233b1ea550e444ca7b9de5593 33695427 main/source/Sources 94026032cba3ee9017142920b9a8cf0b7869d718 7876 main/source/Sources.diff/Index 084fa61dff0201b925e04a9e19349d2d9b0ee090 9414551 main/source/Sources.gz 1d13e6f835c67c7b989c394854d281081627e328 7263348 main/source/Sources.xz 0a6817b5a5d6821eca4987ff2bab1165d9bb8ab7 7876 non-free/Contents-amd64.diff/Index 655452f746ec90d65dc1972d4206891eec66134e 747296 non-free/Contents-amd64.gz c080610b9e3b1834d255c94ca56b5cd417ecafa2 7876 non-free/Contents-armel.diff/Index 6a112ea01526a3cd9340bb95600414ab91a32754 692360 non-free/Contents-armel.gz bf07c86f96b19e212c4ff194dd7828a6e9e73527 7876 non-free/Contents-armhf.diff/Index f67142f72216a56b330d6b1c4bbc4e4b88f4bbcb 690391 non-free/Contents-armhf.gz 88f99ef2e7149170e80dd1d8c2116c18ed9b3376 7876 non-free/Contents-hurd-i386.diff/Index 44c750501088d0b59441d0ba4985af454522d176 689428 non-free/Contents-hurd-i386.gz 90092ea66ba92d38b055b4805b64bbe71c8e15f9 7876 non-free/Contents-i386.diff/Index 9ae51e94c16cce19dd3fccaae656fba600378014 740969 non-free/Contents-i386.gz b3dbb2040209a14aab2acc5a3e2ccb599b68a5c5 7876 non-free/Contents-kfreebsd-amd64.diff/Index 04528bdb779df01d21b025988f6adef2f9dee62e 690234 non-free/Contents-kfreebsd-amd64.gz 603380dd7aba0bac1a8892a077f4ef9f2787ebaf 7876 non-free/Contents-kfreebsd-i386.diff/Index 3d167f575212e8bcc58480f2fb62e98cf92a0f7d 691340 non-free/Contents-kfreebsd-i386.gz ae31bc22889fbae4d49acc25fa4a3b0607311ee7 7876 non-free/Contents-mips.diff/Index 0f0c47daef8c7dd0293b4ba0dc29a9d55a6c248c 692859 non-free/Contents-mips.gz 9e2989631f6382b3aa20ae2d2329455c7c6be567 7876 non-free/Contents-mipsel.diff/Index 67d02e4fd9826515ba52da015d6d8db5cfe39a63 693226 non-free/Contents-mipsel.gz 8d7eba3aced3a96ddbaa95eaa337f2f080da7959 7876 non-free/Contents-powerpc.diff/Index 26e738e3d7a453cdb23100dc9a41660ae36b9251 692776 non-free/Contents-powerpc.gz bf07c86f96b19e212c4ff194dd7828a6e9e73527 7876 non-free/Contents-s390x.diff/Index a6b4d6e25d3b1e297c790ec6d9212f309442f94e 689635 non-free/Contents-s390x.gz 8e08f95b1bf2d14214c16839569a497efa005bac 878304 non-free/Contents-source.gz 44ed2b55f0e3ebfaaa01baecb0809947dd8f3421 7876 non-free/Contents-sparc.diff/Index 28f347bf004e316af980a61fd808696f4d4260ee 693322 non-free/Contents-sparc.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-alpha.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-amd64.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-armel.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-armhf.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-hppa.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-hurd-i386.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-i386.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-kfreebsd-amd64.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-kfreebsd-i386.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-mips.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-mipsel.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-powerpc.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-s390x.gz b3ceff894d4e2283f7dcdd01444513cd3de99000 714 non-free/Contents-udeb-sparc.gz cc921f70e52a367726c0035b3e9c57dcfbcd982f 205641 non-free/binary-all/Packages cd798104b8ec869de3408355e73c673901b4a1e1 60301 non-free/binary-all/Packages.gz d65b34e0e7d3f7dce3f0700b317e7d14263eb464 51104 non-free/binary-all/Packages.xz c0330a4c76ce318d7a4c5f09072ed6136a013e19 85 non-free/binary-all/Release 56e65fd905c7c2d22953a28f545fb58d888357fc 399086 non-free/binary-amd64/Packages 300c66dcbf62ea9fb43ee75d19dabc7b6da9df8c 7819 non-free/binary-amd64/Packages.diff/Index bd536bc6175d27ea4a49fabbd80095a1313531df 110104 non-free/binary-amd64/Packages.gz b4e6121177bd35ddca072a61fa3dbc4a4f1a16a2 91232 non-free/binary-amd64/Packages.xz ffd37b8cabe15fc62a9f6b14cfb4fcaf457e561f 87 non-free/binary-amd64/Release 8005e62fbd92bd6bf8f652ee78654ba420cd1182 256534 non-free/binary-armel/Packages c677d296282bb6e0e6a5b7ff42537dc7913b1ce6 7819 non-free/binary-armel/Packages.diff/Index 9092cc1da8b2f9fd3bd402ea278794ee32625614 75455 non-free/binary-armel/Packages.gz 4679c333a1f0db6980aac5a1d9ef007131f53717 63408 non-free/binary-armel/Packages.xz 5014416c8e757409bf876af83595bbed1078d6dd 87 non-free/binary-armel/Release 9834b7b393f0fc11404946b1a2816a2c9730e8fd 262280 non-free/binary-armhf/Packages e32657c19fa2fc5358b2b39eb9edfd94ca641c80 7819 non-free/binary-armhf/Packages.diff/Index 3e24547f0fab9d84600d77daecb956450e8c071d 76497 non-free/binary-armhf/Packages.gz 72cbf7ec50f383081aa9a0fbd3056f70e47ac27d 64148 non-free/binary-armhf/Packages.xz 30ced96412b9d4cc0398fa7abc450af48b03449e 87 non-free/binary-armhf/Release 0fcb4eefb7154ea850731edb843650df0b674c6a 257246 non-free/binary-hurd-i386/Packages df05cb4ba36f4830d64c52540b25b81a00e419a8 7819 non-free/binary-hurd-i386/Packages.diff/Index 6760b3a248e0ac41d62ec3e7156c52fd9638b5f0 74841 non-free/binary-hurd-i386/Packages.gz 376e6b47c37340be2a158430b8fb8e38128bb303 63080 non-free/binary-hurd-i386/Packages.xz 0471c3c058a5ebbaada92c3a53f04396912be66d 91 non-free/binary-hurd-i386/Release 8fa5eda91ffd7ccf6c350e2d7ab23447a64a72d8 387138 non-free/binary-i386/Packages ac54dfa5cac1cd4c52d6d3a90b492af2e9971fd6 7819 non-free/binary-i386/Packages.diff/Index 5497129850a369f2cf2b84e1e5ae5d604a3ff982 105652 non-free/binary-i386/Packages.gz 4d493f25438f45040621c29493fb13c3c8bbb1f6 87824 non-free/binary-i386/Packages.xz caafe61460a0c84b55ea0afe5696cb364f8a5deb 86 non-free/binary-i386/Release 3498b0d4892a0d06c7e265becdc786effc959342 253378 non-free/binary-kfreebsd-amd64/Packages 2d466d3d858c6e0c6f829958f391db7a46597e88 7819 non-free/binary-kfreebsd-amd64/Packages.diff/Index 19b860a847442cdecb543b5d4368d4b57f95d8b8 73809 non-free/binary-kfreebsd-amd64/Packages.gz 4513dcd7ad4a4b9aa74a9589d8034f635b955456 62124 non-free/binary-kfreebsd-amd64/Packages.xz c23100a2daffa2e0e87172e211a5fcefba38014e 96 non-free/binary-kfreebsd-amd64/Release 841e36b2a9b1d7eef4d9555fdabbb17a0041fef9 257662 non-free/binary-kfreebsd-i386/Packages 2d466d3d858c6e0c6f829958f391db7a46597e88 7819 non-free/binary-kfreebsd-i386/Packages.diff/Index 1a8276851189ac2e04782507de089577901e0160 75004 non-free/binary-kfreebsd-i386/Packages.gz 73d96398a4cb5c4c88d7ecc0bbdaddf12844fd4d 63052 non-free/binary-kfreebsd-i386/Packages.xz e4c15fb8a054b9f8faede95e3aa3d12faaceb879 95 non-free/binary-kfreebsd-i386/Release a091e34ab135c0100e96ee5a7dfea017e4c183e7 253858 non-free/binary-mips/Packages 712987c8e6f1b16720df41ce64ee99c0b49aceff 7819 non-free/binary-mips/Packages.diff/Index 8c428b7bd2d6e2ad4c3be53a4753acb2120b0e8d 74686 non-free/binary-mips/Packages.gz d67d9b41b74eb2fdb8b1ee7f7976de1ee5adabaa 62728 non-free/binary-mips/Packages.xz ddb3fe2e045e739364c4e403c0acbfa279652fa7 86 non-free/binary-mips/Release 13cd50542b0de9ecc8d283f3f9042fbec7402bfa 257104 non-free/binary-mipsel/Packages eafce8eeaebe78d40fd56f4685eb62cd3b793e3e 7819 non-free/binary-mipsel/Packages.diff/Index fbbc776ee93511879dafe018940285bacce3fa53 75418 non-free/binary-mipsel/Packages.gz 98f2d6283d5443cb7d8440b6dad452061113cd66 63308 non-free/binary-mipsel/Packages.xz 71758c9eaad1036a439b8a41eb188d79aa8eaf13 88 non-free/binary-mipsel/Release 9a3d54bcb2bed3ca2a213b9c36a200ede1c62b4a 255252 non-free/binary-powerpc/Packages fdaf575f9cb5cfa307f3d1de3aae31c11b73b5eb 7819 non-free/binary-powerpc/Packages.diff/Index ddbe66cbea71fcbe0c1e93a0683e59368b3a90af 74812 non-free/binary-powerpc/Packages.gz ca8e5ad7ca4e676c97412dce501a12f9bad3f61b 62968 non-free/binary-powerpc/Packages.xz 2afee2e359463899417fd0203bc9c2ad57d52629 89 non-free/binary-powerpc/Release ef3c78637515b728a304e4d9e76b52edddb5a9f0 251692 non-free/binary-s390x/Packages e32657c19fa2fc5358b2b39eb9edfd94ca641c80 7819 non-free/binary-s390x/Packages.diff/Index 668116c297f023f691dcdcd7b111bf7640ae4719 73841 non-free/binary-s390x/Packages.gz 9a188f52b619a878c99a2eb241d070a262387dfb 62104 non-free/binary-s390x/Packages.xz 14cfa858d98fa04ca633126e064dc202b27253b8 87 non-free/binary-s390x/Release 4da56426361274b6d3386dd801aae39910c98633 255662 non-free/binary-sparc/Packages 4274572999c9b488fbbb728f2a539008773fbb3a 7819 non-free/binary-sparc/Packages.diff/Index 1dca17c0146933961f2ea249a251d0cda8ba70c5 75128 non-free/binary-sparc/Packages.gz dbc7f3bfc001586bbf77e7b7a5b79d2953d575e8 63144 non-free/binary-sparc/Packages.xz b85e296ecb2e9843306942791efafdd8f446ccf6 87 non-free/binary-sparc/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-all/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-all/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-all/Packages.xz c0330a4c76ce318d7a4c5f09072ed6136a013e19 85 non-free/debian-installer/binary-all/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-amd64/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-amd64/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-amd64/Packages.xz ffd37b8cabe15fc62a9f6b14cfb4fcaf457e561f 87 non-free/debian-installer/binary-amd64/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-armel/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-armel/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-armel/Packages.xz 5014416c8e757409bf876af83595bbed1078d6dd 87 non-free/debian-installer/binary-armel/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-armhf/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-armhf/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-armhf/Packages.xz 30ced96412b9d4cc0398fa7abc450af48b03449e 87 non-free/debian-installer/binary-armhf/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-hurd-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-hurd-i386/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-hurd-i386/Packages.xz 0471c3c058a5ebbaada92c3a53f04396912be66d 91 non-free/debian-installer/binary-hurd-i386/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-i386/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-i386/Packages.xz caafe61460a0c84b55ea0afe5696cb364f8a5deb 86 non-free/debian-installer/binary-i386/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-kfreebsd-amd64/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-kfreebsd-amd64/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-kfreebsd-amd64/Packages.xz c23100a2daffa2e0e87172e211a5fcefba38014e 96 non-free/debian-installer/binary-kfreebsd-amd64/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-kfreebsd-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-kfreebsd-i386/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-kfreebsd-i386/Packages.xz e4c15fb8a054b9f8faede95e3aa3d12faaceb879 95 non-free/debian-installer/binary-kfreebsd-i386/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-mips/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-mips/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-mips/Packages.xz ddb3fe2e045e739364c4e403c0acbfa279652fa7 86 non-free/debian-installer/binary-mips/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-mipsel/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-mipsel/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-mipsel/Packages.xz 71758c9eaad1036a439b8a41eb188d79aa8eaf13 88 non-free/debian-installer/binary-mipsel/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-powerpc/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-powerpc/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-powerpc/Packages.xz 2afee2e359463899417fd0203bc9c2ad57d52629 89 non-free/debian-installer/binary-powerpc/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-s390x/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-s390x/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-s390x/Packages.xz 14cfa858d98fa04ca633126e064dc202b27253b8 87 non-free/debian-installer/binary-s390x/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 non-free/debian-installer/binary-sparc/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 non-free/debian-installer/binary-sparc/Packages.gz 9746882f4236fa1c3a8f86be2f1d9c46680c0b10 32 non-free/debian-installer/binary-sparc/Packages.xz b85e296ecb2e9843306942791efafdd8f446ccf6 87 non-free/debian-installer/binary-sparc/Release 58c8cd15f45a9a0a7bbf0bed4d95f271ad051fae 345632 non-free/i18n/Translation-en ac9204d45dc42ead2390427bc378fbab83709128 76649 non-free/i18n/Translation-en.bz2 0781fabb742a75affb0bd59e7eac19a53b9a4466 7819 non-free/i18n/Translation-en.diff/Index 3630d9725b739f0b90a07fd05dc6c7996643ddf3 88 non-free/source/Release 7e423e07de040a2b1505e1dece9e670250e13258 432632 non-free/source/Sources a19fa4da418978d09bc55150ff71177ed28bc462 7819 non-free/source/Sources.diff/Index bfaaa290ac22510582e3996105d7e5c86e82b3c9 127628 non-free/source/Sources.gz 36a9d8be869bba214e48ca962eb4a384323e5cf3 106852 non-free/source/Sources.xz SHA256: b612c8d486df544643a725d2e29d430766766f7e06678690918474ff683212bd 29126161 Contents-amd64.gz 88e160e79f28e23d6f7dd0932ba65047a5c9979348e258537eeafc59e8e66162 28753408 Contents-armel.gz dec2f30d995f1b55d97f7f1dcf719a2bf127000e2f897279134c8b5069d7217e 28485312 Contents-armhf.gz 194faffba489193df83e47873488941ea3dd1c6f0009ba077b7aaf0cb4e4da20 26796983 Contents-hurd-i386.gz 6941a948b7963eba7db2ee183178e0fc2aee921cb6858b2f198c9e73e0a9a2bf 29331795 Contents-i386.gz 87c461ed2b18cd3ef773cca68ac2a3068a5175b0b0466af06c2dd0fa669ea34c 27824917 Contents-kfreebsd-amd64.gz fbd2e8c395bb5cf38ef2d9d6772cc0ff5725a114a538130f0fa9db29efd6e98e 27850902 Contents-kfreebsd-i386.gz 5f5c38b305adc65621c0094e281a1f91a1148be4ec49e6d40aa83552f576b70f 28457146 Contents-mips.gz b2ca5146e25fd8ab86d6ec36383b5d7679ad03f2aaf1080e301aa84f5bcb8921 28487260 Contents-mipsel.gz 6855a628fcc6aa8bcea84a88bb976644ecd34c5c59989175db6d2576dff1872d 28813161 Contents-powerpc.gz e300020c742eb0bf5b13234beee538ff44550a6002eac17d6fddd7f40e61abb8 28252350 Contents-s390x.gz 937c79646e9ecde6a122a6e49ebe8adea90e21bd7f7ea6668dd76d35f0509c6e 28214513 Contents-sparc.gz 0f9eef2028ab44ae7f7579d3ae139f5bbf8d9edac583c812a0d4b8f6204863c3 7819 contrib/Contents-amd64.diff/Index 707feb957ce49fe658a0245d4ce9915b94a5385846a63e9d27d32759f99f7c5e 101661 contrib/Contents-amd64.gz 8e70470516def13acf55915ac36ef80a220620cd496622480dbc239b2a18011f 7819 contrib/Contents-armel.diff/Index 2d534ca7e82d03557b836d0a9439b22417bb084a3f4b9a824ce6e661969be282 84379 contrib/Contents-armel.gz c461f6c6e40950983cdd0f73d9f2b6fdae5f77a28cce05a57de4a95f0be09999 7819 contrib/Contents-armhf.diff/Index 2c974f86a8fde06cdf840cf975baaf935f35ac2394f61cb313d37f4cde821874 84201 contrib/Contents-armhf.gz a84229bc528e9c85f1236e221bf14656125d53b28aca14c7adaf7577b29a08f5 7819 contrib/Contents-hurd-i386.diff/Index dab9dfadbe83781cc7f6be6543b0d140d4098f651c500b3e7c5c5bdc24f0f56a 81453 contrib/Contents-hurd-i386.gz 7736f1a795512fbf90262158983c784ec026c714d1f1bbaa1612f56c6417196b 7819 contrib/Contents-i386.diff/Index 3d8615ed6a6d8a04e931339900175669d5e5eeeee9a7835d52439ee8e01a6f63 100858 contrib/Contents-i386.gz 915a35e1774ee12f9b377341145f6d82544c311c7cb55c3bc8c312e80cf5c2e1 7819 contrib/Contents-kfreebsd-amd64.diff/Index 50301e6b3e8b7b5b69c9757ea62b068af085fd576b734bd93c666eae40c985a7 84100 contrib/Contents-kfreebsd-amd64.gz 915a35e1774ee12f9b377341145f6d82544c311c7cb55c3bc8c312e80cf5c2e1 7819 contrib/Contents-kfreebsd-i386.diff/Index 9f85ded05fcd6bcc368eebb115231bb8af3041b9e1533e60b2c822736a236987 84073 contrib/Contents-kfreebsd-i386.gz 11d68596748d8e26e33d7904f6903b6f8e86859dc276fb37cdf52164bd90ded8 7819 contrib/Contents-mips.diff/Index 800433696d23d1733feed8b58b617c135060bc140dcb394059c3ad8d81730f6d 84846 contrib/Contents-mips.gz a8e266b63bd4e0130d32950f8c0163f4d77e436ca1f9011fff2b098df1fd514d 7819 contrib/Contents-mipsel.diff/Index c70357edfb3882e20589f1459280f3d61b5f1b2a927ccf9c069a54f68685e4a6 84844 contrib/Contents-mipsel.gz 51db7da22c3a65a4817bc6c8d60bc294c83bd353179cd28eb91e4042bbca966e 7819 contrib/Contents-powerpc.diff/Index 0c3d3c9af656990d025daadba0d756cfa083b19f08be7e74fd7a314612256f24 84620 contrib/Contents-powerpc.gz 0d3a2b3726b3dc13e5fdb6a8783520d79eb4f2d988534de5a32a1f5eaa416e3f 7819 contrib/Contents-s390x.diff/Index e0e8441549d3dfcc6d70b1488a3534ff25e94065de389d8efdf4c710acbacc0b 84290 contrib/Contents-s390x.gz cc13473cd7cf7236ee0dcc3466924aa6438f74e417f1b7a05e726d991b195a0a 320817 contrib/Contents-source.gz 26783e716911dc3b604864c6f2a15d583b221c1baf36089b75b01bdb8b507f71 7819 contrib/Contents-sparc.diff/Index 860cc8b57d6e07c0de78b661129b56abac663592ad45130f77a7a51dad11dd02 84617 contrib/Contents-sparc.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-amd64.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-armel.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-armhf.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-hurd-i386.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-i386.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-kfreebsd-amd64.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-kfreebsd-i386.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-mips.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-mipsel.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-powerpc.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-s390x.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 contrib/Contents-udeb-sparc.gz 74fc4751e54d4d04d111e77715797c09d7bcb24e61cdecab2b2abec27941eace 93025 contrib/binary-all/Packages 347eef9e20256b7edd51ab5863609a77cfd2127c7fa7386b641c886ef0f20e9d 29432 contrib/binary-all/Packages.gz ab5a3ec50b2b05c888555956d7b0f90ee555c36b473eca1d35598b923f50c530 25984 contrib/binary-all/Packages.xz 0ff444925a094e4eb2e00778702468a614154668bbd5e8812b73f742c6596c6d 84 contrib/binary-all/Release 6cf5ae78fd1fb00f589c6d8ec1f7be961cc7d9d918391c7aadc52135a8fdbeeb 217977 contrib/binary-amd64/Packages 5f5a79b7c18e20877f70bfc68d26e1b8929f9d96946838963412e5b0e1908ce5 7819 contrib/binary-amd64/Packages.diff/Index 9f085d72b30f422883fe807ceb0aaa9e7e88e1b860bead7d266e343199fae80d 64629 contrib/binary-amd64/Packages.gz 8ac659dba380398ab4f3b7b1fb86c6e616d67c5a21900191ef59648b0f3335df 54404 contrib/binary-amd64/Packages.xz aa17e69f27044fec80308a0a0067b454caabb58e63ace02d31995b8c4b208b26 86 contrib/binary-amd64/Release 605a20a282bb3710ae6d7c4caeacea16761be90f572315d7703ba28c1d9dda22 157509 contrib/binary-armel/Packages d25ed3725b02fa0f2eff83d238462f1569df43bb34825fdf7c5d3ce44d8b70af 7819 contrib/binary-armel/Packages.diff/Index cd104178abf9c34811102337403fbb04c8a563cd1cf26078c713226d64522624 48157 contrib/binary-armel/Packages.gz d24dd7b9c315b79f2df8584baab35989852fbcb49f5e13e971f54bf55e0e14cc 41292 contrib/binary-armel/Packages.xz e401e1b60e57a6440631b3e10771fbfd81e5d09aa27dd951f36418dddb366e9e 86 contrib/binary-armel/Release acdc55184ce393282463a1ea04db46b0fad6181935defc000366f4d607143d27 160324 contrib/binary-armhf/Packages f83d83b392d578c66f92fd7d20360329199ee2729324165f9b8d24a281c18f0b 7819 contrib/binary-armhf/Packages.diff/Index c9ea1569e478ff42dcd556f1c1919ff5a2004a5ac646985be0eb78b2d360dfe5 48893 contrib/binary-armhf/Packages.gz 0a34587c11785b26288c7fb718baad6ff50c68f8e9dfdc71768c074e5ae225d2 41736 contrib/binary-armhf/Packages.xz 541dbe68028de6a6f3ea07b509197bdc3775c18550975a7024116ace9ccfa18d 86 contrib/binary-armhf/Release 8c6baa78723089f97b3e8fd67a0073ed576fed57b6c26a0f0ac719af6861dc71 142314 contrib/binary-hurd-i386/Packages d86deb4e0afc32ad335817b964ef3950370228c0b4757a65894cca2e2d3dcda7 7819 contrib/binary-hurd-i386/Packages.diff/Index 00fe832b73537f24d0cdf8683c5857f7ddab39941a93e56bdc8f020dd6067be5 44061 contrib/binary-hurd-i386/Packages.gz b98dc762234b3060b5fd2e5ab3a4d9ea87c92c997f2bff9ef4f68667d4bf5707 37744 contrib/binary-hurd-i386/Packages.xz 56a6b69ec4a445564664bd416b8c7de0b4777b174df580f5a51970c876f893c7 90 contrib/binary-hurd-i386/Release d24c09bb84a6a3f88b41e63e8eda4f4f7cf901400caf5680e74c8bc412e04dae 215343 contrib/binary-i386/Packages 230c45e94bf4f9007ef51fc7c0e66287634eb81d03c0d8c7d76a7ac21c153145 7819 contrib/binary-i386/Packages.diff/Index b268428a06a24eaa2f68d8f15f7605f148a3fa080dadda879776330979a5ecec 64028 contrib/binary-i386/Packages.gz f54f17f6c654953d5a1a6e6ee0af9cb1fd2788e07b71db005a9337bc9f74c33c 53760 contrib/binary-i386/Packages.xz d295fe143a89176007867cde658163c7606c6db1a7b9f6507ec4dd4fa8a30e86 85 contrib/binary-i386/Release 8ffb47f59eba9e0719c80b02b653e1cb9460b1d9788f744048fc6cef269b10a9 159685 contrib/binary-kfreebsd-amd64/Packages ec77fbf405e1c1ca6e222f5e9390b079c0a41c9d14de8621da85a3a461c1812a 7819 contrib/binary-kfreebsd-amd64/Packages.diff/Index f6b40412d4d310093a76c907233022468cfc9ee6f4d976484c0a8b006ac641a3 47934 contrib/binary-kfreebsd-amd64/Packages.gz e5a44a4243b76b670356c02c50f96286e9392e88dc96bf6406c472d0e9e2dec4 41212 contrib/binary-kfreebsd-amd64/Packages.xz 529d6f5dbdd854c55e596435e4ebe22f3b4feb26ea5adaf2cd08c5280b718a43 95 contrib/binary-kfreebsd-amd64/Release c51daf629be09df2fa04ce0b94856a80fb6374eeba3dd045f51f63d3ee67186b 159525 contrib/binary-kfreebsd-i386/Packages 89fc953faae8d753392ee42f1b1b8039a5ea369221aad9b6285d1d81a20c4022 7819 contrib/binary-kfreebsd-i386/Packages.diff/Index 9a56d432f5ce4936c183df3bbdd96093eb3a101088931623f7ac5c02b4a3110c 48140 contrib/binary-kfreebsd-i386/Packages.gz a6d12da7b05d8579c73b5d0c136289357387face29bbca9c37cead56cefecdd3 41220 contrib/binary-kfreebsd-i386/Packages.xz 5ae2619720e2af17548aa450d64cfddd966f0a70d4afb0815cb57eba88b58d6b 94 contrib/binary-kfreebsd-i386/Release 7de287adf3603020d0b42fab86333cff9744188d1f35d32e77f164147d40044e 159132 contrib/binary-mips/Packages 99661b429919d8e7557f59633f0512dd47c9ccf669512420841f2954def34d54 7819 contrib/binary-mips/Packages.diff/Index 1de1db19b876731451a2c8ef444a5b48205300a82ec20d8018d0c5b97ce51a11 48921 contrib/binary-mips/Packages.gz 26bdaf9aa8849e3963fbb003d78548c8499d9ff8375601c092123637ef39bc35 41708 contrib/binary-mips/Packages.xz 590f325f6f81f6741c8fca5124d83ba19537fb32f3b8fdd47f6fcf4d4651a3d1 85 contrib/binary-mips/Release 76e968f1ab4afa4c67008742163c4499216a177b948215c8ea6b5401f1e6d11c 159444 contrib/binary-mipsel/Packages d81f2014e28f1d5fea64810f1e6e7dc628b80c672be9f7a54ca9b82e7e5e8ac4 7819 contrib/binary-mipsel/Packages.diff/Index 2349ca8b635534b8138c7948bd0dc9831e91d66f520d124d26e44e7d078c2be5 48759 contrib/binary-mipsel/Packages.gz abbb16d6ecc7ce386e18574a121811ccb5a65a64ca4b355cee1d02092233f102 41760 contrib/binary-mipsel/Packages.xz 4d939a0673d5e563d87c675661e60a19cabe014896bc9f851aadbed1d53ef0e7 87 contrib/binary-mipsel/Release 33a917026d4f3d7a955f6fcfb7f6f434fc41ce07009a8f573b0126b725df5f47 157611 contrib/binary-powerpc/Packages bcabbad34c9d3a8c77ee593b39d566753aa1315f9663adaad340245832d7ac6d 7819 contrib/binary-powerpc/Packages.diff/Index 81a47cd3ca5e3fb0490ff024a3b64fa0ee334f927fef637e96759ca78e63c70c 48455 contrib/binary-powerpc/Packages.gz b693a07b3251262f754124976d674e19490d828cf42dec6341dbb5d46a4a0033 41396 contrib/binary-powerpc/Packages.xz 1c273a433d8bb8893650a87d77c351b99e99f2e3c29738dfc7a2a235dad2b0b4 88 contrib/binary-powerpc/Release 0df68d523b8e0a532a84a0a41b44ad3423a7354ea1d90d8a5b3c53f35fbd3e97 156138 contrib/binary-s390x/Packages f83d83b392d578c66f92fd7d20360329199ee2729324165f9b8d24a281c18f0b 7819 contrib/binary-s390x/Packages.diff/Index 662b249e262e9ea7787edb04a323166eeaf700d1a3222eaa6d9f9162de2849a9 47760 contrib/binary-s390x/Packages.gz e615cc6b11cbcbe75280082277d6633739435e06884a09a651035f9e18157f7c 40900 contrib/binary-s390x/Packages.xz 1f22fed24a5aeaaf71053ab74b5920ec3a36b5abdf9c070f32d04af04c047ad1 86 contrib/binary-s390x/Release d37cf1c83b2d7b8fa42522784149332741c88a65305bb6819711d21fbe24a9d4 157282 contrib/binary-sparc/Packages 045b76c191f0cb464d30065ad5ba4b733feeeb83f9a57fc381fc96ea95619221 7819 contrib/binary-sparc/Packages.diff/Index 0945b45793371584c8791d359619054b53158da25a28f802a78f797c92e8a3fa 48168 contrib/binary-sparc/Packages.gz dd7170045aadbe76cf419d6d510331c03fa605dd6fafc0d030c0ca44f0118b1b 41228 contrib/binary-sparc/Packages.xz 993fef821deda6c2022a2f32d888ee73b0b791596e1cd98ac84bd24fd0189cb4 86 contrib/binary-sparc/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-all/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-all/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-all/Packages.xz 0ff444925a094e4eb2e00778702468a614154668bbd5e8812b73f742c6596c6d 84 contrib/debian-installer/binary-all/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-amd64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-amd64/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-amd64/Packages.xz aa17e69f27044fec80308a0a0067b454caabb58e63ace02d31995b8c4b208b26 86 contrib/debian-installer/binary-amd64/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-armel/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-armel/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-armel/Packages.xz e401e1b60e57a6440631b3e10771fbfd81e5d09aa27dd951f36418dddb366e9e 86 contrib/debian-installer/binary-armel/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-armhf/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-armhf/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-armhf/Packages.xz 541dbe68028de6a6f3ea07b509197bdc3775c18550975a7024116ace9ccfa18d 86 contrib/debian-installer/binary-armhf/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-hurd-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-hurd-i386/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-hurd-i386/Packages.xz 56a6b69ec4a445564664bd416b8c7de0b4777b174df580f5a51970c876f893c7 90 contrib/debian-installer/binary-hurd-i386/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-i386/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-i386/Packages.xz d295fe143a89176007867cde658163c7606c6db1a7b9f6507ec4dd4fa8a30e86 85 contrib/debian-installer/binary-i386/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-kfreebsd-amd64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-kfreebsd-amd64/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-kfreebsd-amd64/Packages.xz 529d6f5dbdd854c55e596435e4ebe22f3b4feb26ea5adaf2cd08c5280b718a43 95 contrib/debian-installer/binary-kfreebsd-amd64/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-kfreebsd-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-kfreebsd-i386/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-kfreebsd-i386/Packages.xz 5ae2619720e2af17548aa450d64cfddd966f0a70d4afb0815cb57eba88b58d6b 94 contrib/debian-installer/binary-kfreebsd-i386/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-mips/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-mips/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-mips/Packages.xz 590f325f6f81f6741c8fca5124d83ba19537fb32f3b8fdd47f6fcf4d4651a3d1 85 contrib/debian-installer/binary-mips/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-mipsel/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-mipsel/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-mipsel/Packages.xz 4d939a0673d5e563d87c675661e60a19cabe014896bc9f851aadbed1d53ef0e7 87 contrib/debian-installer/binary-mipsel/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-powerpc/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-powerpc/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-powerpc/Packages.xz 1c273a433d8bb8893650a87d77c351b99e99f2e3c29738dfc7a2a235dad2b0b4 88 contrib/debian-installer/binary-powerpc/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-s390x/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-s390x/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-s390x/Packages.xz 1f22fed24a5aeaaf71053ab74b5920ec3a36b5abdf9c070f32d04af04c047ad1 86 contrib/debian-installer/binary-s390x/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-sparc/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 contrib/debian-installer/binary-sparc/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 contrib/debian-installer/binary-sparc/Packages.xz 993fef821deda6c2022a2f32d888ee73b0b791596e1cd98ac84bd24fd0189cb4 86 contrib/debian-installer/binary-sparc/Release 93aeec5cef70718d51af483fdfb5d23638a25da03851c7f5272ac6a82eaf2bfb 163386 contrib/i18n/Translation-en 380b7ed9182d5c9d684c4ff4fba334e20756e0bf5ef925f81aa88281428d72e7 42412 contrib/i18n/Translation-en.bz2 4e334ca646fefc99a2c500dd7b2b09121d6c55d08a0edebb9be8b84d3f63b27f 7819 contrib/i18n/Translation-en.diff/Index 87382c15e64768fc46ddfc65c5f6d6cf4e02a6ead7df009f77c81ea19a4a2417 87 contrib/source/Release 09e91ffa64b5eed5386e36f76bec3a621b9f6cc36f5c4ccf242b67cc3ded933b 214833 contrib/source/Sources 22c3b9975057084d88addd44c955f0bbcd3bf28f985b14c554daba2feed80877 7819 contrib/source/Sources.diff/Index e8e01bd3f607f1fca96eda7354ef345e115176f13e468e8f290250a59f38697a 65954 contrib/source/Sources.gz 2553b184143aba54dad2216aeba018bee6741a53e637618ae7795315c28298c9 56404 contrib/source/Sources.xz 799ef632863d3e49f94233e20c0fdaed4f855d458b7c7b834142b53ed82ed9bc 7933 main/Contents-amd64.diff/Index b612c8d486df544643a725d2e29d430766766f7e06678690918474ff683212bd 29126161 main/Contents-amd64.gz 154604a954d146d322cd1e9dd3e1fd8bcef7f6d4e676f6edc8d1ee6203dd6449 7933 main/Contents-armel.diff/Index 88e160e79f28e23d6f7dd0932ba65047a5c9979348e258537eeafc59e8e66162 28753408 main/Contents-armel.gz 87ecd2b6a5dd5b3945192e26eeecb2ef7b9f0185886882995dc898e709e88bdf 7933 main/Contents-armhf.diff/Index dec2f30d995f1b55d97f7f1dcf719a2bf127000e2f897279134c8b5069d7217e 28485312 main/Contents-armhf.gz ed63c66a1501a516476ddec09c7fa5162e03008dc38ba4c610cb75ea99bb737f 7933 main/Contents-hurd-i386.diff/Index 194faffba489193df83e47873488941ea3dd1c6f0009ba077b7aaf0cb4e4da20 26796983 main/Contents-hurd-i386.gz e918c1091d68dbc6c8eacb478614859928c28cc258f27c11645a2f74e39a19f8 7933 main/Contents-i386.diff/Index 6941a948b7963eba7db2ee183178e0fc2aee921cb6858b2f198c9e73e0a9a2bf 29331795 main/Contents-i386.gz e75ffa0632d09adb2fedf9519742256dc7e67ce3b792c5fed331aa3947bda94b 7933 main/Contents-kfreebsd-amd64.diff/Index 87c461ed2b18cd3ef773cca68ac2a3068a5175b0b0466af06c2dd0fa669ea34c 27824917 main/Contents-kfreebsd-amd64.gz b43f20998ac87c371f26e56cba8ab879813067adb95b0e87d959a871a12fe156 7933 main/Contents-kfreebsd-i386.diff/Index fbd2e8c395bb5cf38ef2d9d6772cc0ff5725a114a538130f0fa9db29efd6e98e 27850902 main/Contents-kfreebsd-i386.gz 7176b63496337615b590e1bc1a6981b9248d6062a47fc982226c95831e3eb5cd 7933 main/Contents-mips.diff/Index 5f5c38b305adc65621c0094e281a1f91a1148be4ec49e6d40aa83552f576b70f 28457146 main/Contents-mips.gz ed72385e663a6f1a5f49e67ad1ba1c6fa5ee69201675c9249071f20d4afef4f4 7933 main/Contents-mipsel.diff/Index b2ca5146e25fd8ab86d6ec36383b5d7679ad03f2aaf1080e301aa84f5bcb8921 28487260 main/Contents-mipsel.gz 02dca3b886ad1fdd63e64eba271843a2855ce3930b2b501687a945bec23f71ab 7933 main/Contents-powerpc.diff/Index 6855a628fcc6aa8bcea84a88bb976644ecd34c5c59989175db6d2576dff1872d 28813161 main/Contents-powerpc.gz 87ecd2b6a5dd5b3945192e26eeecb2ef7b9f0185886882995dc898e709e88bdf 7933 main/Contents-s390x.diff/Index e300020c742eb0bf5b13234beee538ff44550a6002eac17d6fddd7f40e61abb8 28252350 main/Contents-s390x.gz 78031aa2969a30521d35a855f03ac6a28ad29f7044dea27f4364240d791e51fa 42201895 main/Contents-source.gz cb3d10f3c86ade5ab35891a6d032d13001d82f83f656036689f6d3e4bbe3de35 7933 main/Contents-sparc.diff/Index 937c79646e9ecde6a122a6e49ebe8adea90e21bd7f7ea6668dd76d35f0509c6e 28214513 main/Contents-sparc.gz 5139cf88980e8f4e496eeecc3819f74336dc298c8eff5de80239faa7d4ee1aad 34470 main/Contents-udeb-amd64.gz a117955b1572a8630fa1259785afc6bb1213b060f87b20f020f7d8b45ef31e88 30168 main/Contents-udeb-armel.gz ed39fc0f730f7991a669cad772dd895f6d56ad90b68d7d62f69271abe7b458f6 26977 main/Contents-udeb-armhf.gz 6f4a5f5e979e3f7b3d3b26d2aff847e480e642abd95ee95bbf2f3e4c52862750 20196 main/Contents-udeb-hurd-i386.gz 360ae1ae42d21463779af91e23e6ccc5ee8a46d88b9885f3ae46d9c2caa7761b 47415 main/Contents-udeb-i386.gz b1848ec54ce62237658c4901aea4c5d7c92591f1c6760a76eeb1f0b2716ba55a 22694 main/Contents-udeb-kfreebsd-amd64.gz cae74e4ba6562281684c4d023d5197fa7e1123934f01cad12af05b1838368a0e 22764 main/Contents-udeb-kfreebsd-i386.gz f8562fd5ddd0cc885a04581d78f61457c475234fc5068849be6068b53413a3ba 26868 main/Contents-udeb-mips.gz 51dc6ab1c30570a363d03125218396e49840a5082a0fbe09af56a5be99460538 27496 main/Contents-udeb-mipsel.gz 356ee969e10e40707e87bf0e287d756d64ee6b04b960cbb51be6adbce99757b9 40941 main/Contents-udeb-powerpc.gz 8cc23f89b0e6a1c896f50a82f14f462f0e765eaa762e18a06afddfb647925a33 23637 main/Contents-udeb-s390x.gz 6ccd2bb71ca08af5d78b93c407632341c74bc8bb93a9ab5e15c5544d00b008b8 25142 main/Contents-udeb-sparc.gz 4c14c182f075aa00d751d5f8cf93e35d6be93024746c31d0947b59b66fb8f5fd 14618792 main/binary-all/Packages 286e8ec4a1e9318e506e05833166034d00f5e74aa4add8ee02b22770babb57d5 3969765 main/binary-all/Packages.gz 20336ccc3bbbfd76b834c9f20393a5afb41f9eb0cb4cd12e1c0b7c760d4e5b75 3028620 main/binary-all/Packages.xz 002c5db811dccea4c9d5018ee1e0ffecf7762534192f8b9eb680dbb40aa19c33 81 main/binary-all/Release 17cf7bf60aefb29d8a293a45f44b4b2879ad008a9abb0481356ec7ad8794fd12 33618877 main/binary-amd64/Packages bb062f8a1b450043a388948731fc15f77b7c25f418abc408da4bb40640172da8 7876 main/binary-amd64/Packages.diff/Index a928d72f1b2f6c6de14b2b4aa34b9b3735d29a495da014292170b7660b9a22de 8985791 main/binary-amd64/Packages.gz 06ecbe2ab183ec957e5510aa9571050d8ab87f2558a2c28bc5f80f938749eb55 6724080 main/binary-amd64/Packages.xz 9448fe9e95730ab7201eedf94a870492930b5bad0c97d28bd6a827eee1fc9b8a 83 main/binary-amd64/Release 04fcfe970c7e0e172ad53dbc1052b18cc079ac70c90ce4b890d77c8321b431a6 32806207 main/binary-armel/Packages 103e4affe2c9e81565d2356d3f60228314f75bf68156e5cc61a1e3ffcafdb94a 7876 main/binary-armel/Packages.diff/Index 138ac2fcc85afdc1e02c03d77588a9380198b4bf53408dc9b7a939051cbf23af 8780431 main/binary-armel/Packages.gz 50579797f4ef15acecbe4afc0b4c5a0f30a3787359d406d4694b807f10078775 6573736 main/binary-armel/Packages.xz 564b7db8992cd182b85493c2267b7951fd64856ef7bd3e9ad4b1050cc55aa49a 83 main/binary-armel/Release 9f2ac5f30ef2af27a3c55756ec8e0fafb0ec2a98fd10d14bc8276c854d44cd3d 32702650 main/binary-armhf/Packages 91de43e7f14b170a72d5a98cc9c17d9991acecbc9992c33a9e37ec85e3feb304 7876 main/binary-armhf/Packages.diff/Index 9acee3fa01e2b0d0d6136f2786881e4b36c11ab1660df029c711c10904e2b0c1 8752490 main/binary-armhf/Packages.gz 68407fc6eb1b3606333afc74b8148522ae083a803953fd13301b15e8a1fbdbcf 6553496 main/binary-armhf/Packages.xz 372196a26f2fee179e44b1b4155d56e3ab43cc889c887b157201c4414b20ce64 83 main/binary-armhf/Release 64903d52d226df1ac32f2de2d1c3081c5af067df6e0b988ab9dda61c9a817a4a 29457485 main/binary-hurd-i386/Packages 3f3a5ff0efb07665ca90acede0476051c6a6795d69efa9af65e2cddb65c4a1d7 7876 main/binary-hurd-i386/Packages.diff/Index 942a1bd999de40398a588f0ed2e727c82a07800965baff7f2f6c9ad9f069d482 7820791 main/binary-hurd-i386/Packages.gz 0b3aaa3251aba81b402e2a3c2326ec023009b1829c66c8d2444a5c1bc77332da 5871368 main/binary-hurd-i386/Packages.xz dd11a7eeeb73a01c6877f6ba31d5c33d43bebddb45b72d6d16e0682892c3f9b0 87 main/binary-hurd-i386/Release 7c273d92db8d59b4800b446d60a420ea49f4127b9258bd0cdd1067140a556d8d 33606129 main/binary-i386/Packages 58dbbbde3379cd48751f3dc16c55e887906f97fe0421440335d8e5bc89123163 7876 main/binary-i386/Packages.diff/Index e0790bc07d68b9178966c57a1e618f9d2c4d18f1583b87f5931e91c7380df0fd 8997921 main/binary-i386/Packages.gz 00b03fe64e67e731cec793ddf9e50e51c9847361bd78c16ed9aa13bb58428e78 6732360 main/binary-i386/Packages.xz 723dc6454fc1cb003f1a6a658b8b68be2fe4eac1fad6dbd9a968e2b9ef5a57a1 82 main/binary-i386/Release f3e006efe0440101a793f62045a21d58f9f039f58e30592a5dae30434269995d 31615279 main/binary-kfreebsd-amd64/Packages 3aee1df3e05ce2d440084f4b6a5e15032c78ebf5e282e13e2bfc42276237ced9 7876 main/binary-kfreebsd-amd64/Packages.diff/Index 6ffbe14c79491feadb8de8e6dcdc0ab0255a585e3c558be174d434017139125d 8337837 main/binary-kfreebsd-amd64/Packages.gz c1bee519f19fefad2652d294e15582bba498c7b6e294d8526a78e3db9cd658b1 6249852 main/binary-kfreebsd-amd64/Packages.xz 6de212c3aa919f4a9db91c539e5b386596f31c982ee164c73dbc0f7259a9e5b4 92 main/binary-kfreebsd-amd64/Release bea310784aa711011d5703fd3fbeb48970ee7f26f87738e9f15b7a25ef1c312e 31551588 main/binary-kfreebsd-i386/Packages 77084b4f04770869547e7f59cf24932919e4243a86ca4ee1fe856d92b3106f45 7876 main/binary-kfreebsd-i386/Packages.diff/Index 33e372c53efd5d7c0d0893bbb2d9cd54cd11ec9e0315242771c53093387146f3 8332623 main/binary-kfreebsd-i386/Packages.gz 795620c19a1a1f274791ad6f2b77eed86e5daa3ecf7cad015e27dc092e02152e 6247780 main/binary-kfreebsd-i386/Packages.xz 990ca05b0a784e287d15fa818684daed34ab15e4e998051ffa2ba5a82d2336fb 91 main/binary-kfreebsd-i386/Release b2f2bd69285bb07b4a552cdf4140f99944871e5684825a2f94947f0071f187d3 32480079 main/binary-mips/Packages c6ea5f8c10c25a9ae2eaf01b358161e11d8f9be7e4cc40b470291804e56e48a2 7876 main/binary-mips/Packages.diff/Index e05473232c2713ab9be455875cfd0c7a2f07a9b93d316e45031f0bb696a86cd1 8716064 main/binary-mips/Packages.gz 3290830330bde081db2192b3cbce5e359fe9aa4ef340267007f1b5db1e2be943 6524920 main/binary-mips/Packages.xz ec370845d04b4e3a0065bdf2ea05196f10809fb5c32475e80122f885c5a5f97a 82 main/binary-mips/Release 2123cd9d6a2185b3ed9c1180719f011d3e43951043f301f06430bbf9c5706a19 32596356 main/binary-mipsel/Packages 7098b9c7bebf0019a3660751e92f04ac26a1aa91a6e9ca02a441f5b93d321986 7876 main/binary-mipsel/Packages.diff/Index 1aad9c5ef4397f16ca526e5b0e06e0d67523f6294e4f75640a74cd7bff0654a6 8728556 main/binary-mipsel/Packages.gz a1dbb69dd92a2aae4127f241649f19c0ecaa40cb3edde4519cb3054de32b7d77 6535216 main/binary-mipsel/Packages.xz 1914ff9fbb576626492de048c52c6f45c17cd38f427dce7ce54e5e68981212ce 84 main/binary-mipsel/Release 873e5631161dd89ec5a2a8a1aa386863aa9474fad6c4ee6dad444153348bcd84 33154230 main/binary-powerpc/Packages 6cfca8c0d84a35b8ca6543773603406de867b5ba1d86cf313516e8b9076628df 7876 main/binary-powerpc/Packages.diff/Index d7e0496b51ea92c913660ef454e4f76ff78ea43a6362a264505a0890494e48e0 8848733 main/binary-powerpc/Packages.gz 8d15567ae084deedc9478539bfbea25b608c910ae9fa7bc689a886c592f5042b 6623544 main/binary-powerpc/Packages.xz 507fd84c6cef3b9df8c91a0da7381d6930a20ab1b585ed0074d39c3d8afb0cc6 85 main/binary-powerpc/Release 0828d65daffaffd9163fe9616c5af10ed337e9ae398cd7d8dfe3e036ee6e3167 32297598 main/binary-s390x/Packages 91de43e7f14b170a72d5a98cc9c17d9991acecbc9992c33a9e37ec85e3feb304 7876 main/binary-s390x/Packages.diff/Index 0b8150ac351c89f531ffc045a636f305d49ed6304544ca3a4db0a3f2cdf8b0d9 8657047 main/binary-s390x/Packages.gz 520feaaede4a46f63e1b385a442fc84c0038985348a134b16e0b9637ba87cfb6 6481076 main/binary-s390x/Packages.xz 6140ecef0ee776de97f0d45e1e11513984d57dc31ccaac8974b761f3af0372fd 83 main/binary-s390x/Release c7fad89b5462e78b3782d53b31edadbea694d12da8716ead7f8a6c38d594f0ca 32390467 main/binary-sparc/Packages 1b3620056f7292c6a191b71e8b204c16ad84c2b8744f573ff624fc9bb4bc8eec 7876 main/binary-sparc/Packages.diff/Index 5a9cf69e47fc189972c4204176458c8bc7df21f9e3092b44d02b51ac91460dba 8675573 main/binary-sparc/Packages.gz 9ae3f84d953ab4c74d57cd1d875a491f215fa8775cc35bafad38b966137a671a 6495944 main/binary-sparc/Packages.xz 8e91e27007027600d45e22b3cf70f8589a281e9e3ba5613d0feae7b21f36e4ee 83 main/binary-sparc/Release c001c380915dacd2c20f995208bf056f90ec18207476c06d993057daf52e0fad 71965 main/debian-installer/binary-all/Packages de45c3333db8c03828d8b29f30703d7f47f7a49a8bc5348ad405dd80f3a17a34 20810 main/debian-installer/binary-all/Packages.gz bf656939c1c748b95e0ba5c5a40ee0c17197f776dbfa9f76026073fd9a188f9d 18100 main/debian-installer/binary-all/Packages.xz 002c5db811dccea4c9d5018ee1e0ffecf7762534192f8b9eb680dbb40aa19c33 81 main/debian-installer/binary-all/Release 51a4ca4e788cf252cb9470a77657f18e175b913c3a9b5be62023b1d85179102d 271101 main/debian-installer/binary-amd64/Packages a3849b8b6e1aa9813e537f306006ab93bce9d48cd80e4253ad354a74f9288f9b 73559 main/debian-installer/binary-amd64/Packages.gz 960f57c6450a881cd9e770dbe95ab1640ae3c10200ba5453eba729efb9adb4af 62096 main/debian-installer/binary-amd64/Packages.xz 9448fe9e95730ab7201eedf94a870492930b5bad0c97d28bd6a827eee1fc9b8a 83 main/debian-installer/binary-amd64/Release 4ff13f861b835940615e487797d450571e6f12b2b5cf20b853c18f9a16a5c0a5 327884 main/debian-installer/binary-armel/Packages d2c135724a4d448ebbbc582fa7830b738b2dd559e32a217e0c7d061056f8e386 82972 main/debian-installer/binary-armel/Packages.gz 91178e60bb49ef7c5f8edb823738465e695fbc9bccf56f1da4223b9ead214e7f 69496 main/debian-installer/binary-armel/Packages.xz 564b7db8992cd182b85493c2267b7951fd64856ef7bd3e9ad4b1050cc55aa49a 83 main/debian-installer/binary-armel/Release 888abf030b5500a0cf56011ee525139ac213fec141f5241ad2d46d437c3c8ebc 215371 main/debian-installer/binary-armhf/Packages 24d28c8f5a340579825f806fc2ae008ae4a902f84dd46f0e8ada906a13b26683 62714 main/debian-installer/binary-armhf/Packages.gz f1266667f357c0cd327a2d8ac08d2398a1e31980b0f08559f1d57ae84390e18a 52924 main/debian-installer/binary-armhf/Packages.xz 372196a26f2fee179e44b1b4155d56e3ab43cc889c887b157201c4414b20ce64 83 main/debian-installer/binary-armhf/Release 4044e4226c5ee77d6c46bb9eb4cbf78ef477d78111edf1f93e7dc955dfb97c6c 164280 main/debian-installer/binary-hurd-i386/Packages bc9b1d2b9632958ad9cd18bf47d16b49f14829070d97295a109e059c8a946c35 48130 main/debian-installer/binary-hurd-i386/Packages.gz a71909fb96061fb5b5892c8b85dc969e0b537a5c21cc318886e90580b48b2e0d 40652 main/debian-installer/binary-hurd-i386/Packages.xz dd11a7eeeb73a01c6877f6ba31d5c33d43bebddb45b72d6d16e0682892c3f9b0 87 main/debian-installer/binary-hurd-i386/Release 6ff77cafb26e41015e07f959ab0f236f796335ab515ec5929875994155ab15e3 345491 main/debian-installer/binary-i386/Packages ced79088cb01ed16382f7e87cf95e56d2e590c74eb74b348a0180c6ebd4cdfe1 86948 main/debian-installer/binary-i386/Packages.gz 971a1cf8961dc47ed51b80b92a97d6384434f5d8952cca44bd94744fbc75265d 73012 main/debian-installer/binary-i386/Packages.xz 723dc6454fc1cb003f1a6a658b8b68be2fe4eac1fad6dbd9a968e2b9ef5a57a1 82 main/debian-installer/binary-i386/Release e9174fda33c7b1c8b84f39955be286ab86480ffb0586ea7bfcac8b9eb2725d6c 225819 main/debian-installer/binary-kfreebsd-amd64/Packages 5e037f0f6e9602c34233d08e6e1a8dd71d9a455e0c1b5947dc7bed3ac0a859ea 61365 main/debian-installer/binary-kfreebsd-amd64/Packages.gz a87c7365ab7ae9ebed57545631867d651f951f974c8f96e99d7e3cf117e50cca 51708 main/debian-installer/binary-kfreebsd-amd64/Packages.xz 6de212c3aa919f4a9db91c539e5b386596f31c982ee164c73dbc0f7259a9e5b4 92 main/debian-installer/binary-kfreebsd-amd64/Release 2fea8d5232068a986855125b19368ddf83c45d875ddf1b56e01b79614954ba6a 224725 main/debian-installer/binary-kfreebsd-i386/Packages 874be667a32bbf7cb5aa828192621b9e9bf86a29276115c1352bf38c2721e20b 61102 main/debian-installer/binary-kfreebsd-i386/Packages.gz 72532886d5774ca1bebc410b29d95782d85e69cd79ee4ea32a86c814bfec3b8a 51660 main/debian-installer/binary-kfreebsd-i386/Packages.xz 990ca05b0a784e287d15fa818684daed34ab15e4e998051ffa2ba5a82d2336fb 91 main/debian-installer/binary-kfreebsd-i386/Release 17fe039b8b706e75f851cf9b55318d887d92e5806f744200c04b535f0da6ed1e 271887 main/debian-installer/binary-mips/Packages 464c8be538915029c8ce7354276192a9714b1c89fb9532002f97628cda91fa0a 72939 main/debian-installer/binary-mips/Packages.gz 7ab306db6e9cb0b706109528ed44d2603c8bcabdff86c8d640c998bd950f7acd 61176 main/debian-installer/binary-mips/Packages.xz ec370845d04b4e3a0065bdf2ea05196f10809fb5c32475e80122f885c5a5f97a 82 main/debian-installer/binary-mips/Release a9bbf466695bfa76f521e2b4c87932bf2a9012831901fc904c615c17be74c7ab 268044 main/debian-installer/binary-mipsel/Packages 4c8e0e9470c12a66a5f1554fa7b6b17fb4a0c7b43307622eea8c8c03c55c386f 72122 main/debian-installer/binary-mipsel/Packages.gz eb5982e7913d41a70d22210961da5f3559631083931a6473684a515fbd47fed4 60384 main/debian-installer/binary-mipsel/Packages.xz 1914ff9fbb576626492de048c52c6f45c17cd38f427dce7ce54e5e68981212ce 84 main/debian-installer/binary-mipsel/Release 6301e96f0bf122596eafe43d3d3f54ee69e025f8952c1838e11691e2ba8d70fd 326190 main/debian-installer/binary-powerpc/Packages d7677f34398762d02bf6aadd887804596f086a01545837ddde8525f08a42d182 83151 main/debian-installer/binary-powerpc/Packages.gz 83bffa1d724ee406a6785a7b3f4364e98d032a0a5fc24a7daec7c1dbed3de226 69520 main/debian-installer/binary-powerpc/Packages.xz 507fd84c6cef3b9df8c91a0da7381d6930a20ab1b585ed0074d39c3d8afb0cc6 85 main/debian-installer/binary-powerpc/Release 3da91ec4e0a8373596de1708c3286d633fe7ac56e7043480649a5fc3fbc781a2 211381 main/debian-installer/binary-s390x/Packages 0cd7d538be2bfdec147db132bff7268c20b1ce7ff1c803358b11a68a8d72bac5 61216 main/debian-installer/binary-s390x/Packages.gz ac25901b72c75675ccc9326fe9b4050c2c858ee0fff3a47759c2f6433146af9b 51472 main/debian-installer/binary-s390x/Packages.xz 6140ecef0ee776de97f0d45e1e11513984d57dc31ccaac8974b761f3af0372fd 83 main/debian-installer/binary-s390x/Release 41feac753fa7cd846f3f9ab1b32efebfb5baf28076c516774177ef534474c567 211987 main/debian-installer/binary-sparc/Packages b2e2a8576025ebc219393ad6fecb95c406270b5d30bf28c40c1ce3274ff8df9b 61792 main/debian-installer/binary-sparc/Packages.gz b8ddf5653629ef3e0e9c4331abaf4b724e0224879111cfd15136e7cba4c5a1c9 52084 main/debian-installer/binary-sparc/Packages.xz 8e91e27007027600d45e22b3cf70f8589a281e9e3ba5613d0feae7b21f36e4ee 83 main/debian-installer/binary-sparc/Release 500b9a234896dbed5121fae9d8179cb85b769777369d7ba2d5a81809283393b0 10212 main/i18n/Translation-ca 432e21791cdeb810e026d735c91be72f1ef7e93d171c4eb2190f651d1a0c94d1 3986 main/i18n/Translation-ca.bz2 651fb4af407fa18ed99ce32100036912d82c134e77952100815c795e0b4c04ba 3265 main/i18n/Translation-ca.diff/Index d16a6e86fa62de6797982f3ce5282f0a37f46a8b7025d19ff6d5071795b329d3 2083334 main/i18n/Translation-cs 81967544591469f434e15a4a949dac63148827e6deeeba626865f0b6404eda64 541607 main/i18n/Translation-cs.bz2 c91153613928c2cb029d1a918f38fa6548be9fa112dc244fd68ab2727e053eae 7819 main/i18n/Translation-cs.diff/Index 6bf3c7a5f4d95e728a46509729ab1ceabff86017ccd093691558bbb9bbfe9550 10917248 main/i18n/Translation-da b04f68d67eb64d9e3a9dfe1d70abb1cea1bb54aa12f82621c4a03e718b7be608 2381081 main/i18n/Translation-da.bz2 72645dc014af54549c5edef18ab3f854060c6d965dc1cab07a270ae628f5765c 7876 main/i18n/Translation-da.diff/Index 28f7b61a90d09bf4fbe02eee52e1a4b20d0f160ae2f6a9cf6be80bcb521d795f 7811636 main/i18n/Translation-de e731c7bc0c8e72993c22a447c989e24ac2b38ac06c7930bfe5e6e1bd55018a4a 1783651 main/i18n/Translation-de.bz2 dd3c17be066a3e5842f9213a331f372df327f27a8d145e0a3ec7080d1553b220 7819 main/i18n/Translation-de.diff/Index 284169348b8bd4e0de4cc5641eeb05577e80d2bd736452e454976c052cf3cbe2 1347 main/i18n/Translation-de_DE 481a435ad350105b74c4972859c44f447b7a8b5edea0d42f6dd635792e00a461 830 main/i18n/Translation-de_DE.bz2 9f9abe444c71a7c8c9541f626211c000e4f311c8ea0a9061ff125c53ce18a210 8287 main/i18n/Translation-el 8e4906ba999712818c7839947cfcd30d3575e7e6462d7c3c2a230f9ce84defc0 1896 main/i18n/Translation-el.bz2 35714d10cfce7a052f30d212f450be313cf05fe5f7ca352bea0759383cf27a76 643 main/i18n/Translation-el.diff/Index 09d381cc461b82fbaf21abd80f1cccccdb2434f3640b48c01db95ce237e8f3ef 22533282 main/i18n/Translation-en 32a2af715a1c729e6694115e4bd20ec9cc48ff4a77961bec10088abaaddb653e 4576178 main/i18n/Translation-en.bz2 543b552207757d8b52d48def960c8e4fae8b96eec1452c0178608376a29a6ebd 7876 main/i18n/Translation-en.diff/Index 3850e7e44b1ce901689455f8ca5ae93a5c5cee8185ddf650e90b974545028c1e 1504 main/i18n/Translation-eo 7d5a2ba7b9353f5490855958d0acdcb5fb2fd75fc1d511faafeb998bee48be81 811 main/i18n/Translation-eo.bz2 025353759058c31627d32e5f61f227a180cf7551e632dd24d5f87cb74083a058 781 main/i18n/Translation-eo.diff/Index 1971faec7d3ca0906655cd8ab5f3416ba289b1889640c74f89c5f015d8c4858b 1356430 main/i18n/Translation-es f2df68f0f0a1aa4e592c03445e095721f4b50da7d7801607a21af5a87eee0c41 327604 main/i18n/Translation-es.bz2 c8a482251641d9229c2c79187455d81fcafad7d42e82bc57bfe612d0998fcada 7819 main/i18n/Translation-es.diff/Index a46bd4a09933e443bb44b68bac5750f95577bca61aaa805759071500697f7610 17600 main/i18n/Translation-eu 3ecfb6a02142b5aab11fbe9c757b503faf7252d7fb2bf30fdabc61347d149d64 6545 main/i18n/Translation-eu.bz2 9fbfc01fa1e6a636e14be1b91166901c0f201d54fa68c3225378a7f8a923faba 6163 main/i18n/Translation-eu.diff/Index d4b07dfaaca315a7c4b385a6643341b590bc628ea18d2ce37c7bca7153e15a1f 420323 main/i18n/Translation-fi 34ae8f8e34cf11de5cf020aff5f0d884910920c9ccd6b6325ab663039c70bdcb 115357 main/i18n/Translation-fi.bz2 50b1e8c2696888aa338f2b963891bf2ec178716d5008b729825ba0fdb196e020 7819 main/i18n/Translation-fi.diff/Index e62a815f85edf30432c5a927f09af86ad2231dcc269750cb310face45a79cc55 3325423 main/i18n/Translation-fr 8120f670d8806ab9abb49c09d9d1dbd25403cabc9bc4f73ecb73420c4ac44164 742555 main/i18n/Translation-fr.bz2 ba9aabc504f4c3afa39bb5932154d6fc83b8030520ab1e8edc7b66a87f1862e2 7819 main/i18n/Translation-fr.diff/Index f90783cae6df0a756e6aa7c39ba6690fb6a622403a9a75b58a60977c7cb3ca1e 16814 main/i18n/Translation-hr ec727b274d676f78e183aceb258763226f591a2bd09158fefc8ba808dd0bdf3a 6426 main/i18n/Translation-hr.bz2 35750118b153834820c7d61a4ffc9de243026083bf970a9bbfce1bcea0a7bee9 4645 main/i18n/Translation-hr.diff/Index 5538ffa54e32c36e4e3f1db3fd467b7e29ea522cac0c3dfee646f4cff4d2c33d 110436 main/i18n/Translation-hu 8653b9878887f4bcfaff1162a7b23c4568eb23d7795ef20fdc7a2bd66d8ade36 35714 main/i18n/Translation-hu.bz2 e96d04f2f8ca00f1af1fd84b3da4d0eb1bfad94ad5e09cac75e8f2cdd1224209 7819 main/i18n/Translation-hu.diff/Index a57a7f9bcf3dc7707e92df28176161ae75b84a2ca903e7ee80bdfdd0ac89a0e6 7753 main/i18n/Translation-id a4e33fbc299198efcfc47c3df98c55c95197667099caf7dc2ee455309cbb3761 3093 main/i18n/Translation-id.bz2 58c329d5509125767072c7f08753458d30d1564034ff2dbf573dbecb30714d36 3127 main/i18n/Translation-id.diff/Index 99f6f10009ccec446a6d260914fff28533873ca8aa76181332c2c897423ee259 15963337 main/i18n/Translation-it 6ead91d5b343947d24882d3ee4bb2783603816e729e80bcf2b591fed1c861ed6 3236630 main/i18n/Translation-it.bz2 381f39e0e6772a481b613f4e3bdc11820e4cffe990bfeacc605dba76c3e80a45 7876 main/i18n/Translation-it.diff/Index d572c510facb3a5a5f50efb159628c799ee0a1d4332f7946e17c9924c8c7ecfe 4326439 main/i18n/Translation-ja 3f07289b502a4dab5001c0ec9ceff636b2568195a82a985a68cb1c436c95dd08 795115 main/i18n/Translation-ja.bz2 fdda7643bc0e3c6f5fb2b236959d16ebaecc9a6c3c67d05882cd72b57ddbc013 7819 main/i18n/Translation-ja.diff/Index 80443a2374380957b2247b650be1839f9ba06bed7490e95b1a01b0464bc80f93 19391 main/i18n/Translation-km 4b670edf0be8d86595ab36fa072604734fe33c3fb848cd2a7c75a46d5d8fd2c2 3611 main/i18n/Translation-km.bz2 e9710594029325e2a60eaf1acd32cbc4b942d1a728896d90ddd822c41d084fc4 3541 main/i18n/Translation-km.diff/Index d46db3450cf9a2643c1f04fcccc330e9cc86c886c984d49e005e4cbae21a08cc 466233 main/i18n/Translation-ko f1a7cc810fed0d8adfc8b4ddc15ce2c50140127cbaf8db46d16c4162a098ee83 108418 main/i18n/Translation-ko.bz2 2ce5188026c6a13278ed58f71611fa6360257d15f6150980369bd779cc0a2d11 7819 main/i18n/Translation-ko.diff/Index e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/i18n/Translation-ml d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 main/i18n/Translation-ml.bz2 917a62d4d2bd8fb889d77caae2e4ff39abb23410919ecdc553e8aa4f1854da36 2325 main/i18n/Translation-nb 487379711cdb467cfdc7ff412a0a844796bc8371252b051fc1b325f9ac90832d 1302 main/i18n/Translation-nb.bz2 46545b521d541f6edb2bba903f6ed3a78d40dc3bd0d10f5be00eb5392cd56fad 367 main/i18n/Translation-nb.diff/Index a7b9366dca8503537169fc287d6dde4f4de44fd5d25eca9f24eeff510224d812 303930 main/i18n/Translation-nl 839a11e81c14e686cb66b9feb22728c19afcfecfab2c6376843b02373b0a1fe4 82529 main/i18n/Translation-nl.bz2 b9bdb92d4cd8cdecacdb0de9aefb97ff52caedadf1d2e60db88a96dcf4562c9e 7819 main/i18n/Translation-nl.diff/Index b2c58337ef6bf885105949978234aa303dd18f9fa46eba8a2dd748681539df86 2529869 main/i18n/Translation-pl a6a0f8270e16a734aab837a567c138da403beda66ddae9bd2e799e2202d61195 572467 main/i18n/Translation-pl.bz2 cf1a1ca2769a8c273e9b690ea096eb50227eada7e6bbe98eb38279b7d9a91fc0 7819 main/i18n/Translation-pl.diff/Index 6d6812d74c74222ec0c203a9f8b0acea2c6b20c3f816ed093ab325c907e6d3f5 1862609 main/i18n/Translation-pt 6bf49b8bc0016c8ce1c247ec7f99b46b906b72580a1933481d80a5fe64d58a98 453214 main/i18n/Translation-pt.bz2 bec902614ed46c5bb1b0f0d464fc0f70fec058284ca5e2eea56f3522811a40dc 7819 main/i18n/Translation-pt.diff/Index a705c67343c45a0daad9b8d122e2cc724124baac5d39c6160403f27c16ac7c17 3043569 main/i18n/Translation-pt_BR 3689f5bc034b86de7430d97175b5c2d16cc529e8d44faaa8c4a10a0cb3a71259 734688 main/i18n/Translation-pt_BR.bz2 923876f32a5809d6761903331df1ca4bac38157020425e76e4b9757739127419 7819 main/i18n/Translation-pt_BR.diff/Index 00908d40a00314c1ceaf85a68550d22995a466bf22ebe9ee2d6ad5045e18734e 2949 main/i18n/Translation-ro 93cee00ae5cf8a56439faf45ce383d73376e7628e4d6394c463363b52c24eb32 1463 main/i18n/Translation-ro.bz2 ee158f97303488f6263834b3418dc13e22dfe2d1009fb528ba670dce80923ed2 1195 main/i18n/Translation-ro.diff/Index ad83ac75d3205ba02a6918d97e1140a616fa9f294aa317068e9d9d0c89d29fc9 2563200 main/i18n/Translation-ru 70d136552bd773d7d069ac5de646a823b6f7928e6675e2084cf37ac74321ca4e 420970 main/i18n/Translation-ru.bz2 354de6fdc77425c4ee497d9826d8ea366a2949d81a959a20dbb58bb9e84dc294 7819 main/i18n/Translation-ru.diff/Index 577d4406a1d2a0c2dc0621f655d88a5c15da4041da1b8508b4ae8ea35954ab0c 1804527 main/i18n/Translation-sk 190c8a4b261c29ef64d5bf2c71b0f8716f65981493ab1e2cd003cbbe92ab8e14 427527 main/i18n/Translation-sk.bz2 cf7e8aadc20a39f8267b4a728693fa1f7495a4adad65da6157e26888b60526b0 7819 main/i18n/Translation-sk.diff/Index c7d7a141e18b609b6afc5df3eee2c86213339088a44387e7724030586e37bca6 403940 main/i18n/Translation-sr 43c0d881e1e1f6752e35b51ecf5936bab4871ab460ff09ae6d108bff0bfc759a 71417 main/i18n/Translation-sr.bz2 fc5bd27d95bc58c0d88d36a09b5ca7a345a1e126e31b3bcf8ee722627a7c7e22 7819 main/i18n/Translation-sr.diff/Index 52d3217fd1360f13b6d84a0f098017dba8236953fbcec6689db6fe7b572dfa66 139255 main/i18n/Translation-sv 600b525f158fb79473c18ee948a6fd298fb806b8dd61da310d7e9f38799eec89 41556 main/i18n/Translation-sv.bz2 07ce3809d68a244a24a3833b3623ad7cbc23324118b59c3703cb2937a0f124cc 7819 main/i18n/Translation-sv.diff/Index 926b4a85b107381c03f2ae77007d2a9e628b1da209a654ad190d720adfbdd546 902 main/i18n/Translation-tr b53b66bec94d548702370107afb1cec937abbd7b5b29ed47e5f64c1f7416414d 530 main/i18n/Translation-tr.bz2 323428059bc703bed3341e43743823ae52ea317568d7c4b595336b60cf3e4dac 4999044 main/i18n/Translation-uk 9864d86ef5155791de15ec0173c5a34bc96f0b6fb43c4034d2a1e9be63837b9b 784640 main/i18n/Translation-uk.bz2 fa3449cb3227bea462eae1c1de38a0484cfe32642b5b1633aef4c9631c7d607c 7819 main/i18n/Translation-uk.diff/Index 023edda7b1dee247fa436364933239bc97d2ba3d5e4da0f01dae41b295b47dc5 38901 main/i18n/Translation-vi fab5fa226a1318e644f0fad891300605742e4f9d183878a39f2f36b21b58cdc0 11052 main/i18n/Translation-vi.bz2 eb0b1c270bd36cb47c21211a16357e2615cc3dd6c22bec520886e51417893fbb 7819 main/i18n/Translation-vi.diff/Index ba5bf385ecf4799de85e8ab873c233fe0478bbdd30611baf528aea51ae2b97d2 2799 main/i18n/Translation-zh ebb2e1910c3096f393f46f4fb6b1316e571d805d654c2d97d0ea92ddb2229424 1526 main/i18n/Translation-zh.bz2 531b516ab9c998fe291ec399b8c6e9a52c8cd51695486c81a9645a892e0f1d53 1609 main/i18n/Translation-zh.diff/Index 19394e01279fc098d4244646f75e732b616e81b7888ecef299b305db19ed5f50 417827 main/i18n/Translation-zh_CN 580739eb1cd26fdb5ff93349d124fb4e3600755254cfe144757b6f0711482747 113341 main/i18n/Translation-zh_CN.bz2 30c49fea33399c2d5532ad16d26e7c43c0b6df51e76a5a8a6f401f7bfc4d3a7c 7819 main/i18n/Translation-zh_CN.diff/Index 2193514b9d1e341b11e0b15f440cb7a062ae1df4cdd890ab46b68afc57934ba8 65883 main/i18n/Translation-zh_TW f8ed1a51315ea425aeda0053f48657bfaada1f8eb6233c3fd692d33a89acf016 23191 main/i18n/Translation-zh_TW.bz2 f0ca7fe49bc8894f2c4eec55534e6da6d6f6c6833b4781d8f7ec2089b9711224 7819 main/i18n/Translation-zh_TW.diff/Index f9d0f13f047d74bc23e51bd56a8f8a98f0ea79c405958c505d3c13594b23ffa2 10309 main/installer-amd64/20130430/images/MD5SUMS bafe68d4a10ea5c4a7cb507bb8afb505ac176ae288dfe541e8402aab97287618 14289 main/installer-amd64/20130430/images/SHA256SUMS 6cf028e399443527e3fe0c4876c7dd45a1ea11639476e6d548f1e7eaa8c7ff95 10309 main/installer-amd64/20131014/images/MD5SUMS f77dc5fdfef5f956bd19d7755a6ff6a51c21c197919a3f10603c5e349e218fc5 14289 main/installer-amd64/20131014/images/SHA256SUMS d2938e14a131532b2f9d16672cf882c5fce696d68b751656b87bddc8428856c9 10309 main/installer-amd64/20131211/images/MD5SUMS e3808403dad2c4b0d45d5bdd31dc3d89e4afd84c99988ea6dae380f824cdabb4 14289 main/installer-amd64/20131211/images/SHA256SUMS 584af09dcc18dc127b10b9fb60e75768ff82a37288f4a632dad11d730c872e90 10309 main/installer-amd64/20140208/images/MD5SUMS f8da05394ef865258f3551e6225fc396a90ad8c0ce5415ecbcd853568a6206e3 14289 main/installer-amd64/20140208/images/SHA256SUMS 1333fd3f7a721d9ea10df0b985d7ddb84926e2c66b608b6d98c211d4bcaad9e5 10323 main/installer-amd64/20140316/images/MD5SUMS 62350d180981bea7ae8a395e566069cb6bccee4fe94769e5c478e08148e7a5c9 14303 main/installer-amd64/20140316/images/SHA256SUMS 1333fd3f7a721d9ea10df0b985d7ddb84926e2c66b608b6d98c211d4bcaad9e5 10323 main/installer-amd64/current/images/MD5SUMS 62350d180981bea7ae8a395e566069cb6bccee4fe94769e5c478e08148e7a5c9 14303 main/installer-amd64/current/images/SHA256SUMS ae091d32f8e66360c6d16e4f6af20f997004230e0b3afa5d98a2002d011bff7f 4807 main/installer-armel/20130430/images/MD5SUMS 0adab1fa2d53dc51e16fe0a7b465a6671f141b0c9e7c8c3041c1e0e922f24650 6835 main/installer-armel/20130430/images/SHA256SUMS c8380c2320bc09ba522548fe34c9f3af7607aec702d141fcc19ecf9efcd37d4e 4751 main/installer-armel/20131014/images/MD5SUMS 899e4c303b0cedb9325e7e98862eda2446640c6a406c8430b6f8c09612189574 6747 main/installer-armel/20131014/images/SHA256SUMS 259eac31602b581155f34f3d9f6cf543acebbaf723efb48ff4f9539f0020530b 4751 main/installer-armel/20131211/images/MD5SUMS 333ee9cac7a295f39ac8562ff2a81e37a2cf9b6a8a8f45e08b0719e51a38ee9c 6747 main/installer-armel/20131211/images/SHA256SUMS 564a4fa2f43b9ddba4d36b02bfbdbdfa0b3f14ee3e4e600e7cd6c016397a99b8 4751 main/installer-armel/20140208/images/MD5SUMS 5a98c19e36ea1d3b2784ff477550cf6e31c7d825e833751a10dfbd3cda763c5c 6747 main/installer-armel/20140208/images/SHA256SUMS 62464b823aa2d66eafc607101a1bd9567e2a59df260998175896902441543f4e 3612 main/installer-armel/20140316/images/MD5SUMS 22de24038ede7642141596b62f6fe03e6d41d4ed89d1bdb7906374bbd1649c7e 5128 main/installer-armel/20140316/images/SHA256SUMS 62464b823aa2d66eafc607101a1bd9567e2a59df260998175896902441543f4e 3612 main/installer-armel/current/images/MD5SUMS 22de24038ede7642141596b62f6fe03e6d41d4ed89d1bdb7906374bbd1649c7e 5128 main/installer-armel/current/images/SHA256SUMS 68a783be52a9c316a79f1bfbc42e55397b811883d1fe6a03a41b5a0e1322f18a 1108 main/installer-armhf/20130430/images/MD5SUMS cfeaf6c6fd34d5bc706755b98a2628a5a6233f35a27ad246b3f1e043f16e84fb 1728 main/installer-armhf/20130430/images/SHA256SUMS 52cd33bf8e2353961bdb43f449fd2314fe4dd189a5bd5ca50ebb31879b4c57b3 2373 main/installer-armhf/20131014/images/MD5SUMS c1e6a9dcf31091b422f3312626f357e92cd44fc0702af18be8eca0f9a661e07a 3569 main/installer-armhf/20131014/images/SHA256SUMS 3387a376c8309845caa88eb71075546108176739905a11cacfb5ebc038b1e883 1408 main/installer-armhf/20131211/images/MD5SUMS 11e44962a868e93017816094eb924c38bfa108c9d5838bdac6cd430cc27a4502 2156 main/installer-armhf/20131211/images/SHA256SUMS 7a76da5c05b2c79ef10eb94117f41a47ad043db2060aebf8c432321144a72e69 1408 main/installer-armhf/20140208/images/MD5SUMS c24b4b1b987cf5281ecdaf14b5aa633dc4887e3ff5896f404322331b203a0150 2156 main/installer-armhf/20140208/images/SHA256SUMS 3cf3a93676ef7011dcbf2311dabfa5cbb76c5f520f7fb37f963b161e49b41f20 1408 main/installer-armhf/20140316/images/MD5SUMS c4dcbf695061c4d3e63b2329e302795f4b5b81b9308daa928ddff3a0d817a3f7 2156 main/installer-armhf/20140316/images/SHA256SUMS 3cf3a93676ef7011dcbf2311dabfa5cbb76c5f520f7fb37f963b161e49b41f20 1408 main/installer-armhf/current/images/MD5SUMS c4dcbf695061c4d3e63b2329e302795f4b5b81b9308daa928ddff3a0d817a3f7 2156 main/installer-armhf/current/images/SHA256SUMS 8c2bdd8fb2344948411f6e2282a622d8e69caaba631b496999366d2af541deec 10215 main/installer-i386/20130430/images/MD5SUMS 8a6a4ac80b8d44de83a2bc267ba7b20561bb8236564de7dab49beacec4f6e210 14195 main/installer-i386/20130430/images/SHA256SUMS 825b34e538e04685ccf857d00193c4354fa05276a866233b2f0fd1f16b14a8fb 10215 main/installer-i386/20131014/images/MD5SUMS ffed6de099da055e3a3463860b0e9033da72f87a0b8179c6ecd66b7f9f7311b4 14195 main/installer-i386/20131014/images/SHA256SUMS e6a3d206837b041c6c06ac57786e072ceb0725ba448bf15277a0ae193ef7117b 10215 main/installer-i386/20131211/images/MD5SUMS e276dc0932466295e7a914043d967fb6cd3f045e0acc261b9549667c6d97bc98 14195 main/installer-i386/20131211/images/SHA256SUMS aaceff09b45f4da85da556837d4a35e60920153499c4e881753ce31a0b06b017 10215 main/installer-i386/20140208/images/MD5SUMS df38e2ebc9057e276f5be6e693dd23af478122cdbef6a932528170cef4f1d41e 14195 main/installer-i386/20140208/images/SHA256SUMS a1a6ff39be59195ea5687c43fdbeb6fa5c6a9733784dbbabba4a0def804a4390 10229 main/installer-i386/20140316/images/MD5SUMS e070ca1038bc4aca056189b88f5602401d32039db97a640f682398431b054061 14209 main/installer-i386/20140316/images/SHA256SUMS a1a6ff39be59195ea5687c43fdbeb6fa5c6a9733784dbbabba4a0def804a4390 10229 main/installer-i386/current/images/MD5SUMS e070ca1038bc4aca056189b88f5602401d32039db97a640f682398431b054061 14209 main/installer-i386/current/images/SHA256SUMS 649497f309b4cd6ce801f3a5a37d3e8b344e1ceb80e44165772bd6a5c630917e 3446 main/installer-kfreebsd-amd64/20130430/images/MD5SUMS 5529ba0b7c026ab998d6ec1884405c9bf9b0e4b700ed10ade638000031e6f0b9 5026 main/installer-kfreebsd-amd64/20130430/images/SHA256SUMS c73ffc20fe8bbd8ecb4784a918b6dfa2446ad25d0f8e2ea2bf07f01a91c2349f 1936 main/installer-kfreebsd-amd64/20131211/images/MD5SUMS 612e7ebc52f4ff272845e5cfe78d9df76a5a0dea437d83d3e7b0154a534016a6 2876 main/installer-kfreebsd-amd64/20131211/images/SHA256SUMS e5360ae1b81c9c5bdfd50ee3b2e58b4e7a433af83c2e3508f3ef73f7ac698f5d 1936 main/installer-kfreebsd-amd64/20140208/images/MD5SUMS 900bb4a7e2627ea741a0ed2689ec902c618098cdd5186b1cf0468d3f514984f8 2876 main/installer-kfreebsd-amd64/20140208/images/SHA256SUMS 024ac89e7daad55c503bd9554bc8ff6a93c6b2f65ed4471ad7c5725c3933e80c 3768 main/installer-kfreebsd-amd64/20140316/images/MD5SUMS dbbf05c425b8d89b55696554cd4ff41aca62597445ad31fcb26cef70aafb77fb 5476 main/installer-kfreebsd-amd64/20140316/images/SHA256SUMS 024ac89e7daad55c503bd9554bc8ff6a93c6b2f65ed4471ad7c5725c3933e80c 3768 main/installer-kfreebsd-amd64/current/images/MD5SUMS dbbf05c425b8d89b55696554cd4ff41aca62597445ad31fcb26cef70aafb77fb 5476 main/installer-kfreebsd-amd64/current/images/SHA256SUMS 2f69a7ed72ea83c3ec63e3bf81cd8d100a0e82b318ae51dc3162dbab7fc2ff1a 1738 main/installer-kfreebsd-i386/20130430/images/MD5SUMS 5ca38c3805915566a68b1796377ceaaad1bb261caa9fea7527da0c5950f9aeb0 2614 main/installer-kfreebsd-i386/20130430/images/SHA256SUMS fb45fb16dc651d61615ed61b166c5b0716900eb77235b060617eec4fd46c59d8 1009 main/installer-kfreebsd-i386/20131211/images/MD5SUMS 76db2daa20c86a01c8c0c29e5192cfd2cec2ade01ddb968043efa2caefbfb0d5 1565 main/installer-kfreebsd-i386/20131211/images/SHA256SUMS c47009693a0102f288775b22f65713ce0ec4621ee8ce34d481d642e8d19eae0d 1009 main/installer-kfreebsd-i386/20140208/images/MD5SUMS 12a8b794ba5df7feafb5f45951911b167e2f20dac3f724116507390c189698cd 1565 main/installer-kfreebsd-i386/20140208/images/SHA256SUMS f59583821c1364bf02fa4e3cd81d02fd4bfefe172a75459d5e3896288c154cbf 2088 main/installer-kfreebsd-i386/20140316/images/MD5SUMS e4a0dd6c6297814f9aea7715dd4f727763cb661c37e9a4fb433f4c228bc94dbf 3124 main/installer-kfreebsd-i386/20140316/images/SHA256SUMS f59583821c1364bf02fa4e3cd81d02fd4bfefe172a75459d5e3896288c154cbf 2088 main/installer-kfreebsd-i386/current/images/MD5SUMS e4a0dd6c6297814f9aea7715dd4f727763cb661c37e9a4fb433f4c228bc94dbf 3124 main/installer-kfreebsd-i386/current/images/SHA256SUMS 25952885cee4f7bfd0bd224371129bc61f8b139081994c314f84fdf11490bb9a 802 main/installer-mips/20130430/images/MD5SUMS 170caaa7654b02e6b89eb802057e179e79c47d39cffe6c5e062b6ced153e17a5 1294 main/installer-mips/20130430/images/SHA256SUMS 0b103fd42ab33941bb7f36bc34808f6857a6f44628410e562c7af3ae518757df 800 main/installer-mips/20131014/images/MD5SUMS 5b0a2066bfadc19ea6c79ddba9b5017fd9f9ab57064ee4eda757c342ac01a831 1292 main/installer-mips/20131014/images/SHA256SUMS 6e264d4acb07d7b1e4ba0f5c7f3598dc9a674af41e83e346316a5056d4fcee30 800 main/installer-mips/20131211/images/MD5SUMS 2413692481b91bec67df7d059d3a3578633836617fbd28cd9186402b22472fa8 1292 main/installer-mips/20131211/images/SHA256SUMS ad2f6bf72a7ba0f958c68e74a9cbf5c9113edeff16f62c7a394a0797694e1ec1 934 main/installer-mips/20140208/images/MD5SUMS 36b9844b49eb24332304c2d8d5830205acf3094dec57a2a13c3d2dfb48349bee 1490 main/installer-mips/20140208/images/SHA256SUMS bf0ceed4b263b394679b7c1db384b58936887ef57661a2da788ed8ced692a25c 934 main/installer-mips/20140316/images/MD5SUMS e5b1c1d5b6bffb997e16047819497a8358665ff546e1e60e8fa755dd8343651f 1490 main/installer-mips/20140316/images/SHA256SUMS bf0ceed4b263b394679b7c1db384b58936887ef57661a2da788ed8ced692a25c 934 main/installer-mips/current/images/MD5SUMS e5b1c1d5b6bffb997e16047819497a8358665ff546e1e60e8fa755dd8343651f 1490 main/installer-mips/current/images/SHA256SUMS fc33893e7aa9025adaced5f88867c9b7d5ada12e700ffc2ca43d938a28595612 1342 main/installer-mipsel/20130430/images/MD5SUMS f76d6e2314079bbd8ad00809cf703e5aeae28dad95ba19bcba45ed0358a6c5fb 2058 main/installer-mipsel/20130430/images/SHA256SUMS 13550ede80312844e7dbae54d5dfbc8a34ff8287cffaf7f50625dbec2f1f8ebe 1338 main/installer-mipsel/20131014/images/MD5SUMS ac4809771da840d17139eb886cd37142578acd14524385a62f3c4e3b44edaa50 2054 main/installer-mipsel/20131014/images/SHA256SUMS 934806ae5415e188191fb6ae8066c8ff8595f0e8818f6ea0116e78e4a6c6d601 1338 main/installer-mipsel/20131211/images/MD5SUMS 014986f2e929bf6a5a61f6868eaeadb1c7a476344d0c38d4d61f6fa44e9dac21 2054 main/installer-mipsel/20131211/images/SHA256SUMS 56f2a94b0a0dc966bee928c953e68a982b6f9de4f8d046b0dc2eb02cc0cbdf53 993 main/installer-mipsel/20140208/images/MD5SUMS 59f7bcd26ac94abf3068f4199dba9dec26c947d632aef4432629100b38261202 1549 main/installer-mipsel/20140208/images/SHA256SUMS 088dd4c428e73246773711513255e8053d88e9df49ea77fd6e172eb513bf2a56 993 main/installer-mipsel/20140316/images/MD5SUMS 87e9d1b4732fb76a6f26c8365a020a9331a389d7aab77577c4fb03d7be977949 1549 main/installer-mipsel/20140316/images/SHA256SUMS 088dd4c428e73246773711513255e8053d88e9df49ea77fd6e172eb513bf2a56 993 main/installer-mipsel/current/images/MD5SUMS 87e9d1b4732fb76a6f26c8365a020a9331a389d7aab77577c4fb03d7be977949 1549 main/installer-mipsel/current/images/SHA256SUMS f69b1566b38861489fefe1dc0de6aeafe66a7261c5a8074aee43015fe8eea75c 2128 main/installer-powerpc/20130430/images/MD5SUMS 8032eedd2987c03eb2f2fd4ab39f15bba5e3238249f646281790c371a12b60f1 3292 main/installer-powerpc/20130430/images/SHA256SUMS 41b24f02ec5760b3da65cb643ba15e23a4e7562cc3b72a399b5fd9b45197a080 2128 main/installer-powerpc/20131014/images/MD5SUMS 60d41e570c774a6e8a78cff7549186b1e649462f48016229c2c583de41293211 3292 main/installer-powerpc/20131014/images/SHA256SUMS 05b06b1849576072095be216ee96e3e1ace8fda9d32393a620489d613d48411f 2128 main/installer-powerpc/20131211/images/MD5SUMS 69fe9e3406c4cf38e960c7f1cc40897c81306345b13363a7d2aaa4feadb6445c 3292 main/installer-powerpc/20131211/images/SHA256SUMS b14300fc87ecef13da54652adb4fe2d87ef8442afa5e88d3056f117089709e39 2128 main/installer-powerpc/20140208/images/MD5SUMS 3713d6f755c4f76589bf14388f4f99cb8c7d5fc27f4f90a30852b80c17d753ef 3292 main/installer-powerpc/20140208/images/SHA256SUMS a0a5ece92b8828363e5085a6e055c74001503c42a592105e14cae9454b48545d 2128 main/installer-powerpc/20140316/images/MD5SUMS 5a672614db67512c00207dd3429b2002560bf97b57f43dbd5b65ebac3d6934a2 3292 main/installer-powerpc/20140316/images/SHA256SUMS a0a5ece92b8828363e5085a6e055c74001503c42a592105e14cae9454b48545d 2128 main/installer-powerpc/current/images/MD5SUMS 5a672614db67512c00207dd3429b2002560bf97b57f43dbd5b65ebac3d6934a2 3292 main/installer-powerpc/current/images/SHA256SUMS bdacfb646bd0b8ef37c2e1c01952958c69bff9032f8861ca57a95c2bed7945f1 604 main/installer-s390x/20130430/images/MD5SUMS 69bca9619cf96ff18d9515bdfc22e0f17a5445158bd6b8c3d8e3a5e5c6a87995 1032 main/installer-s390x/20130430/images/SHA256SUMS 8e04c5bf216931af9dfe8823e193547c4955a3039fdf6d49b246c9a52f268156 374 main/installer-s390x/20131014/images/MD5SUMS 044e90d83b531ec610a9d9dfc5e007eb4215c8d7a89b661d9e0c74c61cdb90bc 674 main/installer-s390x/20131014/images/SHA256SUMS af93774908702a126fe0fade08b49448ddaa3489143b5a0b633edb2a2b5ebef3 374 main/installer-s390x/20131211/images/MD5SUMS ae38dde23d8dfb53742e39a93bc748929d30d7f8f05ac34223e786382a763fd2 674 main/installer-s390x/20131211/images/SHA256SUMS 907d602e5f3afa8109eb5dce6f03446000d5f9ecfda3333192c462a474a4f990 374 main/installer-s390x/20140208/images/MD5SUMS bf279f04a63acdb6b7fda2ba5b926923053292acc17b017b6f51465b0cb9d9a5 674 main/installer-s390x/20140208/images/SHA256SUMS e8dd1bb3bfcade2a7557135a8e567f17dd023acce7ed08dad5e1ac16be8b2a88 374 main/installer-s390x/20140316/images/MD5SUMS c50555c153ccc4e48a15b44a68ef6127cbc0ccdaa108128ab309382436790326 674 main/installer-s390x/20140316/images/SHA256SUMS e8dd1bb3bfcade2a7557135a8e567f17dd023acce7ed08dad5e1ac16be8b2a88 374 main/installer-s390x/current/images/MD5SUMS c50555c153ccc4e48a15b44a68ef6127cbc0ccdaa108128ab309382436790326 674 main/installer-s390x/current/images/SHA256SUMS 81e21c388d290af672bbec3f74b18dfee6a03a27d49c1c71bee01e797023bbd2 358 main/installer-sparc/20130430/images/MD5SUMS f4e6cf0372e9914a0a5593199eba4490b30e33d3a039ad5993b6d41168a3623f 658 main/installer-sparc/20130430/images/SHA256SUMS 33447c70dbfd3e66c4e6803b336c8b210a3a084b11aab70b5a795448710cc0e5 357 main/installer-sparc/20131211/images/MD5SUMS 3c05fcf260309823dbc113dee4d0584e3c859206ed60dccb42211349e4091587 657 main/installer-sparc/20131211/images/SHA256SUMS 33447c70dbfd3e66c4e6803b336c8b210a3a084b11aab70b5a795448710cc0e5 357 main/installer-sparc/current/images/MD5SUMS 3c05fcf260309823dbc113dee4d0584e3c859206ed60dccb42211349e4091587 657 main/installer-sparc/current/images/SHA256SUMS a39c2f2f086da12dac96ba0f0a8a7cd9baae9a3d77b56a088546266dbabbf20d 84 main/source/Release c321f7586d85f264a9c6df9663548ce105eeac277645bca076c29b33fd6165ef 33695427 main/source/Sources 49fd6bddb4904f7de4777742cc51b69e22f4686a33daa585f81df27ccbbed852 7876 main/source/Sources.diff/Index 9319724e1d7ceaf9116866ee090c09009975476ae3090013c0094631bc278d6a 9414551 main/source/Sources.gz 25111c4a3fe6116586b1d26599d20885744ef2913fcbf2791d94c96e11688f79 7263348 main/source/Sources.xz 54d068e494d9fdc41f76ede29a206a9c6dda637904c5b90367090f41f5ec011b 7876 non-free/Contents-amd64.diff/Index 9a89307a966df8f3e4a7e3447b4c27eb603bae1d1319ecf175dec4b22d0c318c 747296 non-free/Contents-amd64.gz 022a99af149a12ef8c11f684fa18f1c0662fb70ca571852dfc9a5bfa7b0744d9 7876 non-free/Contents-armel.diff/Index 348c0b342945c570764b950b697752236d14e6b912dad8bbf56ba59baa9ff6db 692360 non-free/Contents-armel.gz 03f6b6aa2c66cbcb2f0df96a0ba2c29e74ebbbfa65905ed1807e37626787c378 7876 non-free/Contents-armhf.diff/Index 2212dbf1cf2397952bebdd5c61672b7e9f54f89577104ff378a6e59997d370ec 690391 non-free/Contents-armhf.gz b504861506b8894561c9dc0478b1ea7971a637ab3bbd949373f3117ee222ad8f 7876 non-free/Contents-hurd-i386.diff/Index 00cc0fce86698a212071ab326942ebfe9f421e0f711e7723fab5eeb10ca65196 689428 non-free/Contents-hurd-i386.gz ad4af923ba29889f60e732e535777caca6c7fbcecc0e5f240cf2acd73f6c0448 7876 non-free/Contents-i386.diff/Index 8e8a93be462b1618a83bd59510246d7cf6f88cf37ab94a9e79a25987b5232741 740969 non-free/Contents-i386.gz afcef2c25c2e871e4e36d4c9e43a924238aa28a9712e5e9bd52dcd179097824a 7876 non-free/Contents-kfreebsd-amd64.diff/Index a41d29189716dbaa336deb1bd47547eb847674a4d33b06d86f6e222d75bf8bcc 690234 non-free/Contents-kfreebsd-amd64.gz a4537671e7c20c60dabd49117c13bcc8103122c6e3f045b6a514410374f7b8e0 7876 non-free/Contents-kfreebsd-i386.diff/Index 8e6aeebe0eecc5d2bab03e1612a6f921f55a0f2fd7958b1e0131aff6453b49d2 691340 non-free/Contents-kfreebsd-i386.gz 943f0fa92c2fea56e6fd554c3a415c2c41b7e08dc7b709ad354267d4093afb89 7876 non-free/Contents-mips.diff/Index edf65a939a1dc004bb80ee1e1a89a2753c652b371958b67983a8b28c4fcdf70a 692859 non-free/Contents-mips.gz f4d1e169e22347b07502e920ecd269de44fb8378a448f2cac3fce9b298e5f5ed 7876 non-free/Contents-mipsel.diff/Index 067906234956bf5c4714fc88d9aadc6cd19e8defe563339ce0330d2bf7883b47 693226 non-free/Contents-mipsel.gz 78e7c1c2654680a89b114343cf387ad8fcb7a817720c45e0d8fc3348a9f5ee87 7876 non-free/Contents-powerpc.diff/Index c796a9f271d53508e6aba90b91501178cb6d93388330ecea8f8c6c2bdb3e48f7 692776 non-free/Contents-powerpc.gz 03f6b6aa2c66cbcb2f0df96a0ba2c29e74ebbbfa65905ed1807e37626787c378 7876 non-free/Contents-s390x.diff/Index fb3c5d4337261a76e8878fbaeea671a02363d24e755ce3d30bf7b2f2d5f1b95c 689635 non-free/Contents-s390x.gz e466bc8ab363191947654932fc10a2ed2ea24ce3ba06fced15cbd2244ad06c60 878304 non-free/Contents-source.gz a9b2c9244187fc300d9cb4a3f33d18281c5a7ca101e9576cd7e3e82cbc82100b 7876 non-free/Contents-sparc.diff/Index d3979d5b62e642a17d39f80dfef362c3c6235469ed1f1f8dfcf7e2d2388b7f86 693322 non-free/Contents-sparc.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-alpha.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-amd64.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-armel.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-armhf.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-hppa.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-hurd-i386.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-i386.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-kfreebsd-amd64.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-kfreebsd-i386.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-mips.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-mipsel.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-powerpc.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-s390x.gz c4267846b1957a01bfa98528e92e8095a9e26aa5b26f62e54f8a4990ea77707b 714 non-free/Contents-udeb-sparc.gz 393e0c8dbb019b3b013d7a852f50e30252060ba3eebf960ed6ce53ea87116deb 205641 non-free/binary-all/Packages fd06c9f41396e3d983199cac957af896fc9eb3a4d653ea2308dd3d334bf9214e 60301 non-free/binary-all/Packages.gz 9cd99ed462ba4e42814c0237b77276fa7bfb8b9a7c33ddb8afcf83784b5acc66 51104 non-free/binary-all/Packages.xz c64ad10282091b3234a7b5f276d9c330170f4091a62654d3d72d544a9d3b1d5b 85 non-free/binary-all/Release fe9bbf8b510f84335aecc9649ce7a71ac156f1175c02a1194d824eed89abe85d 399086 non-free/binary-amd64/Packages 0a9144b350d973b4e5f2caaa609cb7c54c4b28e4f84b932977b0576dfb7523f3 7819 non-free/binary-amd64/Packages.diff/Index 129d600b91a8b2f2bc7ebdb4d223cc00df5ebec40bb0c0e4e970a8f8bfd44dc1 110104 non-free/binary-amd64/Packages.gz 01d4cc8ca9f5c1ff43a1d654afba22d6f3f56da320f64034e543fc085b75784e 91232 non-free/binary-amd64/Packages.xz dd4dc89dd0fdf6a062134bb166017e6e784fdad19d9033c1081d4b703575aefe 87 non-free/binary-amd64/Release cbfa210e4690197ae70d204f0c6258805c9e1fa86347e6b6a5775889b405018a 256534 non-free/binary-armel/Packages 3a2828259967e0b3376f57ea2ff502a5c293c3df2b62af39b60c13cf42f801de 7819 non-free/binary-armel/Packages.diff/Index 8a34296e5f6b779d575a005e5036da0b4f7f4d891a8a7228576b9290393f5ba8 75455 non-free/binary-armel/Packages.gz f8eaf58e66a1efc79a32b80c3d7aa9410c151ea626da14d3d259c2a4dc090b3e 63408 non-free/binary-armel/Packages.xz 36aa3d28c41807f457c92bb68372872020e2919fe047f937aef10cdce5963046 87 non-free/binary-armel/Release e9549f6dceb964d17e1554b80832eb6200601981beffb085b354c9b4b246f2dd 262280 non-free/binary-armhf/Packages 235dadd71d486dafd961afb7cdd1161901d9126b2508acfcaa84cd8ac9e1ad45 7819 non-free/binary-armhf/Packages.diff/Index 65d3197dffa7ef7f332be2ec871edd4d85b8e5f9c96767d174cfacb7dbdaa4e8 76497 non-free/binary-armhf/Packages.gz eb7c3745e5ae203a88359b58001bf3dd1488f6f3b8df956f93ba0e48654e8550 64148 non-free/binary-armhf/Packages.xz 5dc7dd91870ce6a9ceed2a016f47b8fd58c25f816fd1396625e377e7e9621e1a 87 non-free/binary-armhf/Release 2bf14781032c71b2535f85d79c03b4606f4860557db1e78b9c6b212b096c87f7 257246 non-free/binary-hurd-i386/Packages fc728d224f9a079ea834237b85fa194895e520c68ff74fac9d7ec235c675caeb 7819 non-free/binary-hurd-i386/Packages.diff/Index 7b70447e0c92d4c81e583df8ecada084e4ccc99d3f734ac6e5a86380c1b4bf14 74841 non-free/binary-hurd-i386/Packages.gz 5726f1e1fddf695b62b21637777cfec0cf280e3440f881663dd80b0c9084dd97 63080 non-free/binary-hurd-i386/Packages.xz 4bc66e62d52411a395775d5bb6d97049e6fd9dc41a4960585809a5b063d60b97 91 non-free/binary-hurd-i386/Release 5548993eb1d4741fcab8e21e01b4919f4a75bc0b3076a8278023ad55327a38e1 387138 non-free/binary-i386/Packages 052a5bb72472603750852cf2c3cb5c038060a9707e9f318c0e18cc4b42674650 7819 non-free/binary-i386/Packages.diff/Index 47b6a64452bdda87fd5477078ebe6d9b0783052b5d0bfe815f2adcbbe3e87429 105652 non-free/binary-i386/Packages.gz 39079393a9897c706118d54b7bd5c044893ac93b07cc296a21b0b063d817ee34 87824 non-free/binary-i386/Packages.xz 1f0fb9fb1cc3ff79ae6657730cc8e66f877a075dff946eee59c80a791f8c8320 86 non-free/binary-i386/Release 9dd5afe2d2418684e6c6e901d77d0325098abfa0f28a160596430e95c2424ea3 253378 non-free/binary-kfreebsd-amd64/Packages e84490e62d2152ba9ca09448a8cd26d7948f6520720050df418e680887fcdc79 7819 non-free/binary-kfreebsd-amd64/Packages.diff/Index 202f57ec7c8dedfb8c464fd0eee84563ebef3ba8a20a8dfa06109fb8f1839966 73809 non-free/binary-kfreebsd-amd64/Packages.gz 78239ae948ea4dbc40f4e48387d4825f37710b127b3ae90e68cc9001ddf8e9c6 62124 non-free/binary-kfreebsd-amd64/Packages.xz e36be4c894c17bd21a50996697dacdba3077553c7fe7bff1ce699090caea352b 96 non-free/binary-kfreebsd-amd64/Release 85290351a34ac51f4158869d6bed23bc8c0c588fee218eb6a198c14ea4be927d 257662 non-free/binary-kfreebsd-i386/Packages e84490e62d2152ba9ca09448a8cd26d7948f6520720050df418e680887fcdc79 7819 non-free/binary-kfreebsd-i386/Packages.diff/Index 09c5d85bacae4b4d959c6f62905db229d32c86af6c7836e380097230ab336e8c 75004 non-free/binary-kfreebsd-i386/Packages.gz c9775c010554a99d653eae4920464df0735d06046467cb1798874fc9159c4ed6 63052 non-free/binary-kfreebsd-i386/Packages.xz e03ef118a1c72f4a587c9603f29689aaa9c086099040b57c17994bae199171c3 95 non-free/binary-kfreebsd-i386/Release 3a8c8fe13a22bd7ebe002ab62ad45b4e9b4de437685ec75f1c093e98e02cf75b 253858 non-free/binary-mips/Packages 1a0702a9d6fbc4e1f6cef7ef6eaec61fa295c3989687297db51f9d4b46ae65d5 7819 non-free/binary-mips/Packages.diff/Index d985a77019fcd3dceb86f7ae78de5cca469207167b52bae0460cfdfd2255de2d 74686 non-free/binary-mips/Packages.gz 6facffb0f4b143ab4e5bb74f96792a2d05dc4693c73bc268e12330d3aa7913f0 62728 non-free/binary-mips/Packages.xz 8b863244a661c711d23fe1c0f14e2fca15084608e0be4405ab99fcba9e5a7427 86 non-free/binary-mips/Release 5a96027883704b6ff82348fe3c8dd6556fa13065e718d55e6b6d69652897e42c 257104 non-free/binary-mipsel/Packages 8eb8e20d4e3d90a0aad1273b44d49011322d05945e886998b6365c2370f8f507 7819 non-free/binary-mipsel/Packages.diff/Index fad97c6874c2d0204ad4ba72f76621b57a3b8a21aa20d21834785a9376a3371d 75418 non-free/binary-mipsel/Packages.gz 43a62c6395b59509004cc45f60e6ae6cb867b0980a430bbd895128e274c77e48 63308 non-free/binary-mipsel/Packages.xz 8cecbb92e252278b5d2d7ec7666e9a8fce8f0864340b416253c69cb0576b5531 88 non-free/binary-mipsel/Release de93cef8c80ecf237cc7f496dcbb98606616db67721f977840ba2dd291fe9c55 255252 non-free/binary-powerpc/Packages 3c54db6faf64ea503eb843af699f3832a65a670175fb5c8b6a50dc8b04a520d5 7819 non-free/binary-powerpc/Packages.diff/Index 27768a7d368798ef4b031607b438bba4b157faa9c7b64414aab0a511dd5c3fce 74812 non-free/binary-powerpc/Packages.gz 3a5e827bba3ae02563ca68362412ea18872126e6ba3d04f1c2196cd76b0f168f 62968 non-free/binary-powerpc/Packages.xz 648e1bf34491b4647a196cd4660c465b76dfc47b8cc41d88cd75f471012f348f 89 non-free/binary-powerpc/Release 83f1381b9a6e6cef778c22fed032a4821d395d825de9113a82b236fcd5d25b36 251692 non-free/binary-s390x/Packages 235dadd71d486dafd961afb7cdd1161901d9126b2508acfcaa84cd8ac9e1ad45 7819 non-free/binary-s390x/Packages.diff/Index 9a85b35d4c97c084dce48f048ccc1ab1c7c56fe7f2c3bd8f4e9c03cca04db8b4 73841 non-free/binary-s390x/Packages.gz a203b4968dcf49f09902a50bed3ac09ef7eeaf2bc3e8f48eb0107f65b147b1cb 62104 non-free/binary-s390x/Packages.xz d7369327172de4ef73491d6c8c7a3b26caa27d58b82c8b045eb9179b7af6d0bc 87 non-free/binary-s390x/Release 1c93d7f57bcaea2754e42388c209720b4d68397aa006027acbddd1480a707f54 255662 non-free/binary-sparc/Packages 940b2d85af03178808bf6370dcece6c7d792c67584490cbc6d01bec457a8b0fa 7819 non-free/binary-sparc/Packages.diff/Index bdb93e33105931208dc743594d86a000607460ad95bf2bbdcfad6e92b46f9c30 75128 non-free/binary-sparc/Packages.gz 4bc930ea0698a3aed57015280ca00ad6652e3e5489e596311fc14e5fd7d36c8c 63144 non-free/binary-sparc/Packages.xz 0320beff3456f188b92004a94867db8e11c0d2ddb363e2e62c38d68309e910fd 87 non-free/binary-sparc/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-all/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-all/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-all/Packages.xz c64ad10282091b3234a7b5f276d9c330170f4091a62654d3d72d544a9d3b1d5b 85 non-free/debian-installer/binary-all/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-amd64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-amd64/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-amd64/Packages.xz dd4dc89dd0fdf6a062134bb166017e6e784fdad19d9033c1081d4b703575aefe 87 non-free/debian-installer/binary-amd64/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-armel/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-armel/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-armel/Packages.xz 36aa3d28c41807f457c92bb68372872020e2919fe047f937aef10cdce5963046 87 non-free/debian-installer/binary-armel/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-armhf/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-armhf/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-armhf/Packages.xz 5dc7dd91870ce6a9ceed2a016f47b8fd58c25f816fd1396625e377e7e9621e1a 87 non-free/debian-installer/binary-armhf/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-hurd-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-hurd-i386/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-hurd-i386/Packages.xz 4bc66e62d52411a395775d5bb6d97049e6fd9dc41a4960585809a5b063d60b97 91 non-free/debian-installer/binary-hurd-i386/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-i386/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-i386/Packages.xz 1f0fb9fb1cc3ff79ae6657730cc8e66f877a075dff946eee59c80a791f8c8320 86 non-free/debian-installer/binary-i386/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-kfreebsd-amd64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-kfreebsd-amd64/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-kfreebsd-amd64/Packages.xz e36be4c894c17bd21a50996697dacdba3077553c7fe7bff1ce699090caea352b 96 non-free/debian-installer/binary-kfreebsd-amd64/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-kfreebsd-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-kfreebsd-i386/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-kfreebsd-i386/Packages.xz e03ef118a1c72f4a587c9603f29689aaa9c086099040b57c17994bae199171c3 95 non-free/debian-installer/binary-kfreebsd-i386/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-mips/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-mips/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-mips/Packages.xz 8b863244a661c711d23fe1c0f14e2fca15084608e0be4405ab99fcba9e5a7427 86 non-free/debian-installer/binary-mips/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-mipsel/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-mipsel/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-mipsel/Packages.xz 8cecbb92e252278b5d2d7ec7666e9a8fce8f0864340b416253c69cb0576b5531 88 non-free/debian-installer/binary-mipsel/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-powerpc/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-powerpc/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-powerpc/Packages.xz 648e1bf34491b4647a196cd4660c465b76dfc47b8cc41d88cd75f471012f348f 89 non-free/debian-installer/binary-powerpc/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-s390x/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-s390x/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-s390x/Packages.xz d7369327172de4ef73491d6c8c7a3b26caa27d58b82c8b045eb9179b7af6d0bc 87 non-free/debian-installer/binary-s390x/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 non-free/debian-installer/binary-sparc/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 non-free/debian-installer/binary-sparc/Packages.gz 0040f94d11d0039505328a90b2ff48968db873e9e7967307631bf40ef5679275 32 non-free/debian-installer/binary-sparc/Packages.xz 0320beff3456f188b92004a94867db8e11c0d2ddb363e2e62c38d68309e910fd 87 non-free/debian-installer/binary-sparc/Release 8ea117857b15c3720d52c53152fbf168f0600cde5c0e0ad47a07489ed3bfa40c 345632 non-free/i18n/Translation-en 9aee7f77f074dba4f19c08fd8838a1e80e88bf830b20b4b6eef6850a2a1899e1 76649 non-free/i18n/Translation-en.bz2 de5bf93f2f1d488feb2c98f5d5c9aa821147c781d11d8da755a05917e3a34bdc 7819 non-free/i18n/Translation-en.diff/Index 6baab9dd64343f2413fd85b70199164f4c11bb5f55883c81d82d01052e08e14f 88 non-free/source/Release 4ff75b5b905793ae4e47e67f2d7a7fdaf7b20af1991d2165424cfd96e1bb9449 432632 non-free/source/Sources bc98787adcaaab7df154c66c5c93008b66eaa28d7d4a51e2c0f3061de1385d26 7819 non-free/source/Sources.diff/Index e0a8e1bbc0a7212b6adc0b94621b55e0d081f4b8623b14510aded9ebe5069445 127628 non-free/source/Sources.gz c47d8bd1d4bfa9647d720186057a463dde415eea0612ee21220a2a6dcad3bb9c 106852 non-free/source/Sources.xz PGPy-0.5.4/tests/testdata/signatures/ecc.2.sig.asc000066400000000000000000000003441403641706600216510ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQR/D5etU51R90sBi9EGLmrFIF2HHgUCXMILLAAKCRAGLmrFIF2H HmI3AQC70mikthv4+gadsD7E8STKEPKtrkGaWTLQ6Q+U9Rc7sAD/dkUfbeRB7UvU COB64/0yz5kupCYt5+an6jH85yWNTgc= =RSff -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/signatures/ubuntu-precise.key.asc000066400000000000000000000300671403641706600237440ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG/MacGPG2 v2.0.20 (Darwin) Comment: GPGTools - http://gpgtools.org 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 pDKj7DVPDHoMosX7esXmd/UXdA== =EITi -----END PGP PUBLIC KEY BLOCK----- PGPy-0.5.4/tests/testdata/signatures/ubuntu-precise.sig.asc000066400000000000000000000003061403641706600237270ustar00rootroot00000000000000-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.10 (GNU/Linux) iEYEABECAAYFAk+Yf4YACgkQQJdur0N9BbVHsgCfR7AVn0dpd488Ge5cYlOCv5GA g8wAmwaLRc0PwlYfNr3MbsgQ5T+RBbbd =J4xr -----END PGP SIGNATURE----- PGPy-0.5.4/tests/testdata/signatures/ubuntu-precise.subj000066400000000000000000001406331403641706600233530ustar00rootroot00000000000000Origin: Ubuntu Label: Ubuntu Suite: precise Version: 12.04 Codename: precise Date: Wed, 25 Apr 2012 22:49:23 UTC Architectures: amd64 armel armhf i386 powerpc Components: main restricted universe multiverse Description: Ubuntu Precise 12.04 MD5Sum: 6a815674c5b3178152d449a9396cb2e5 1640344 main/binary-amd64/Packages.gz 98140fa3444c9e945f6944acbb9ddcff 7818931 main/binary-amd64/Packages 846e0e856bcbf9b64d9119c8727cda8c 97 main/binary-amd64/Release cfd5f57de107941bbe661ffada4dce88 1272844 main/binary-amd64/Packages.bz2 5b220aea8056a900c8eaf28e79cdd64a 97 main/binary-armel/Release 92e3160bbb664f8b5d7d4f2d161dd81c 1619078 main/binary-armel/Packages.gz 28fbf69ee965639c92c8a54256cd6ba1 1257389 main/binary-armel/Packages.bz2 4e3ba67129f73f8afe28186b31eb3112 7743353 main/binary-armel/Packages 81cfd32bf54d2b007542e14e09953bae 97 main/binary-armhf/Release ed404b1123d1497cb09aceae8850fc06 7620333 main/binary-armhf/Packages 64156d29df19fdaa36fa4eafd4c17dc1 1257653 main/binary-armhf/Packages.bz2 3d3238bd89cb1e8e23a1a4a5bf574739 1617483 main/binary-armhf/Packages.gz dc2fe62f05e29f36ffe4e58499796ae6 1273857 main/binary-i386/Packages.bz2 7c678c50ce682e9f5cc5ba8f8eb2d6ad 1641082 main/binary-i386/Packages.gz b6aa9a96c765bbd4202dae7dbaf18cc2 96 main/binary-i386/Release eb3b4870b877863fecf1d3307c3beb54 7816415 main/binary-i386/Packages 54658d89b612a38592431fe6b8a780a1 1627734 main/binary-powerpc/Packages.gz 4185aca6984f00fd65aa0c0de12367d4 99 main/binary-powerpc/Release fc9bf1959082733fc42c682285bf46e7 1263942 main/binary-powerpc/Packages.bz2 c32afd79c9163cffe013f98669deb727 7661552 main/binary-powerpc/Packages ff5434612595a569236f7ba4990a3b63 62166 main/debian-installer/binary-amd64/Packages.gz 7dd470290bacbacc7bec24830100aade 234592 main/debian-installer/binary-amd64/Packages 013d9839e9c8f8c102daf6eb77841bf7 48784 main/debian-installer/binary-amd64/Packages.bz2 08608ef832f2410970d07fdd802fc4e4 47964 main/debian-installer/binary-armel/Packages.bz2 0a0a559023aac4096a38e2fb51870ddf 230310 main/debian-installer/binary-armel/Packages f79f29b841a05b971ac318a9e0a396e0 61118 main/debian-installer/binary-armel/Packages.gz 20a72276b6607fa58f52fcc5b7742ff4 62777 main/debian-installer/binary-armhf/Packages.gz 8da4a15400cec4b06e2aa1bba6cfc2c3 49051 main/debian-installer/binary-armhf/Packages.bz2 49f9f82a7c7e9e13c399d15df43148f1 238862 main/debian-installer/binary-armhf/Packages 3dd181be504206f7abb41039dc508ed9 52279 main/debian-installer/binary-i386/Packages.bz2 5c2c6ca586bb6ffb2de414e2cd063c70 259996 main/debian-installer/binary-i386/Packages ca1b7db323ebef593617ef0a7c833dfb 67180 main/debian-installer/binary-i386/Packages.gz 876f115ee26518319458fc26ec785485 246636 main/debian-installer/binary-powerpc/Packages 49402b5b12b10804abfae14629d23f1c 50309 main/debian-installer/binary-powerpc/Packages.bz2 29010a7ba3ac1e60a0efaef04f6f2e42 64468 main/debian-installer/binary-powerpc/Packages.gz adf74189a01512a8f68d4bfc411dc692 3706 main/i18n/Index 2f2ddab9be4ecc2c9e190bb639304943 4356187 main/source/Sources 5c2893c352ebbf3ee380ebdab6b5e487 933770 main/source/Sources.bz2 323e5ca1ba86c7a503c4c7b0772749b1 1174967 main/source/Sources.gz 3c3104465b2c7e54f4b8f566ac825339 98 main/source/Release f75f8a98e9e952194046da388a11c42a 119109 multiverse/binary-amd64/Packages.bz2 c2df9a9ff319486e3d6f46d9c35a8530 151924 multiverse/binary-amd64/Packages.gz ece719c6a770134150f158cdb65ca6fc 581550 multiverse/binary-amd64/Packages d3f34ec2fc86c95e4d3bc4606d751c66 103 multiverse/binary-amd64/Release f296954282382f88b12dd8c64d813f5c 136295 multiverse/binary-armel/Packages.gz d0da88f8a408fba12d44d5b6e107cfc0 519605 multiverse/binary-armel/Packages 6d0c32b1cae4bdcfd6f18fd2d6fbf31f 103 multiverse/binary-armel/Release 6744aaa8a3457d139348ea18379781ce 106873 multiverse/binary-armel/Packages.bz2 1cc2613becf46fd578aa6d52ab12db94 104529 multiverse/binary-armhf/Packages.bz2 b0f8df0c9d700a1f7d295be4d4c03788 505901 multiverse/binary-armhf/Packages 73cb5bc3d0c5021e5a4a413a73bcefce 103 multiverse/binary-armhf/Release 00c07f1601226b8387fe4c9afaf2b044 133117 multiverse/binary-armhf/Packages.gz bf0237c8c5d06a6df172db28710b8a36 121196 multiverse/binary-i386/Packages.bz2 cf110f58668bf5731e593ed78af54c27 591662 multiverse/binary-i386/Packages 8a915986a504c0f3eb95b61ae909c9a4 102 multiverse/binary-i386/Release c6d89a2752d1154a219c295e6d70b697 154762 multiverse/binary-i386/Packages.gz ae93681c6b316c95207091b3c91042a7 105 multiverse/binary-powerpc/Release ec463c2070c515de099f8baa3a4b5993 107209 multiverse/binary-powerpc/Packages.bz2 675204a2b4aabeb9e99e406070b2af9b 520882 multiverse/binary-powerpc/Packages c806ea7584c782d57363df12ddb28839 136930 multiverse/binary-powerpc/Packages.gz d41d8cd98f00b204e9800998ecf8427e 0 multiverse/debian-installer/binary-amd64/Packages 4a4dd3598707603b3f76a2378a4504aa 20 multiverse/debian-installer/binary-amd64/Packages.gz 4059d198768f9f8dc9372dc1c54bc3c3 14 multiverse/debian-installer/binary-amd64/Packages.bz2 4059d198768f9f8dc9372dc1c54bc3c3 14 multiverse/debian-installer/binary-armel/Packages.bz2 d41d8cd98f00b204e9800998ecf8427e 0 multiverse/debian-installer/binary-armel/Packages 4a4dd3598707603b3f76a2378a4504aa 20 multiverse/debian-installer/binary-armel/Packages.gz 4a4dd3598707603b3f76a2378a4504aa 20 multiverse/debian-installer/binary-armhf/Packages.gz d41d8cd98f00b204e9800998ecf8427e 0 multiverse/debian-installer/binary-armhf/Packages 4059d198768f9f8dc9372dc1c54bc3c3 14 multiverse/debian-installer/binary-armhf/Packages.bz2 4059d198768f9f8dc9372dc1c54bc3c3 14 multiverse/debian-installer/binary-i386/Packages.bz2 4a4dd3598707603b3f76a2378a4504aa 20 multiverse/debian-installer/binary-i386/Packages.gz d41d8cd98f00b204e9800998ecf8427e 0 multiverse/debian-installer/binary-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 multiverse/debian-installer/binary-powerpc/Packages.gz d41d8cd98f00b204e9800998ecf8427e 0 multiverse/debian-installer/binary-powerpc/Packages 4059d198768f9f8dc9372dc1c54bc3c3 14 multiverse/debian-installer/binary-powerpc/Packages.bz2 a2bcfa86da39328db94629011506a877 2676 multiverse/i18n/Index c2ffda2a848000b71573dbc3dc7d4402 154990 multiverse/source/Sources.bz2 f1d64bb88933686a71108de73b1f2262 628753 multiverse/source/Sources 3d35747578528fa13640b98184120e51 188325 multiverse/source/Sources.gz c9828946b46ac900fec682369c52bfa7 104 multiverse/source/Release 5644835af0d1ed82cc7c14e34c2a543f 9098 restricted/binary-amd64/Packages.gz d3058923c862e74c2c08b9a4ad7ec51e 134705 restricted/binary-amd64/Packages 97ecff09a695f1460177843ff5d2b3e6 103 restricted/binary-amd64/Release f8ed966e5400930411a32a7183357810 8452 restricted/binary-amd64/Packages.bz2 60e74c701a6e40b7f869dd83b335ec5c 103 restricted/binary-armel/Release 4a4dd3598707603b3f76a2378a4504aa 20 restricted/binary-armel/Packages.gz 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/binary-armel/Packages.bz2 d41d8cd98f00b204e9800998ecf8427e 0 restricted/binary-armel/Packages 55c08a48fc4b3370acc95a391bde1189 103 restricted/binary-armhf/Release ce2da4621bbbaf55d858ae4243e17715 1103 restricted/binary-armhf/Packages.bz2 b26814493282faf0c5b269c44b799653 2477 restricted/binary-armhf/Packages 784050b4fd16ea71e10cf130e47132d9 941 restricted/binary-armhf/Packages.gz c4280a67444afbb8e2564d6f2249d397 9108 restricted/binary-i386/Packages.gz 6dfd90555b37a912f82894b4ec3b63a0 8431 restricted/binary-i386/Packages.bz2 48d3e36bf54be9b3fc7576cfcd0aac79 134582 restricted/binary-i386/Packages e49b38cbf4dc409e8c25f6ab4b32fbe4 102 restricted/binary-i386/Release 4a4dd3598707603b3f76a2378a4504aa 20 restricted/binary-powerpc/Packages.gz 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/binary-powerpc/Packages.bz2 d41d8cd98f00b204e9800998ecf8427e 0 restricted/binary-powerpc/Packages edb68a453747a9faa9e98389787fb79d 105 restricted/binary-powerpc/Release d41d8cd98f00b204e9800998ecf8427e 0 restricted/debian-installer/binary-amd64/Packages 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/debian-installer/binary-amd64/Packages.bz2 4a4dd3598707603b3f76a2378a4504aa 20 restricted/debian-installer/binary-amd64/Packages.gz 4a4dd3598707603b3f76a2378a4504aa 20 restricted/debian-installer/binary-armel/Packages.gz 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/debian-installer/binary-armel/Packages.bz2 d41d8cd98f00b204e9800998ecf8427e 0 restricted/debian-installer/binary-armel/Packages 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/debian-installer/binary-armhf/Packages.bz2 4a4dd3598707603b3f76a2378a4504aa 20 restricted/debian-installer/binary-armhf/Packages.gz d41d8cd98f00b204e9800998ecf8427e 0 restricted/debian-installer/binary-armhf/Packages 4a4dd3598707603b3f76a2378a4504aa 20 restricted/debian-installer/binary-i386/Packages.gz 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/debian-installer/binary-i386/Packages.bz2 d41d8cd98f00b204e9800998ecf8427e 0 restricted/debian-installer/binary-i386/Packages 4a4dd3598707603b3f76a2378a4504aa 20 restricted/debian-installer/binary-powerpc/Packages.gz 4059d198768f9f8dc9372dc1c54bc3c3 14 restricted/debian-installer/binary-powerpc/Packages.bz2 d41d8cd98f00b204e9800998ecf8427e 0 restricted/debian-installer/binary-powerpc/Packages 39ef6c1d54f83252b07406f9cc3e9204 2596 restricted/i18n/Index a76089a7a653d4f2196c38093058d1aa 19001 restricted/source/Sources 3990b36e6ef2846251b58a58cde3768d 5470 restricted/source/Sources.bz2 f0a32107aaf12daf3e64b4dc3ee11321 5306 restricted/source/Sources.gz 7871a3f6f83e033ab93c06bf886e305d 104 restricted/source/Release 3464b1b15950e714151f8bb43982951e 25546870 universe/binary-amd64/Packages 9340d5c4051da92820bb5bd5ba05f7a7 4785960 universe/binary-amd64/Packages.bz2 1f6974aea9904921afdb4d1c5d0e8578 6166988 universe/binary-amd64/Packages.gz 75ea366982b4862a41d9640687778dd2 101 universe/binary-amd64/Release 5492f7f7183461d52f8d58871026c3e8 101 universe/binary-armel/Release 420abe7ca02b5cb2abcd1b273efcfea9 4667308 universe/binary-armel/Packages.bz2 4da3448f54e710222b26646b0bee14e8 6009219 universe/binary-armel/Packages.gz e99405db74ba425a3f898fdda0a42113 24901082 universe/binary-armel/Packages d0545845bbcff572a5c852b80582b269 5948128 universe/binary-armhf/Packages.gz 8f0d262f1eb03fc3523cd80b3112a7e0 101 universe/binary-armhf/Release a10169d0cc23f526bcee5769d27778b0 4618508 universe/binary-armhf/Packages.bz2 952259d2cdb2c85df177702ac92075a0 24642528 universe/binary-armhf/Packages df43c3b4ec37e79a00023475a09e2bfa 6179579 universe/binary-i386/Packages.gz cc44a3e2ad759febb38ef2bec15ab29e 25568759 universe/binary-i386/Packages 826b1d8609f0944a6d2ae95617e4d05a 100 universe/binary-i386/Release 50690005918dd03ad9b71ffffa678d6f 4795820 universe/binary-i386/Packages.bz2 8a1f21204f4178574251a2238c00f317 25188905 universe/binary-powerpc/Packages 7409876b9e1238d5a147720b41233a26 6080488 universe/binary-powerpc/Packages.gz 9bcc15c59aa3fbbd15f0d187fe90b353 4716652 universe/binary-powerpc/Packages.bz2 c3bdb05d2be1efa2dca9d2bac4e85b13 103 universe/binary-powerpc/Release f8259410f0e1ad66324dbce895fdde2d 15255 universe/debian-installer/binary-amd64/Packages.bz2 ce60affbf23a069735c29951bfb0b818 17243 universe/debian-installer/binary-amd64/Packages.gz 13ce59ecd4540ddef3670dbbed73cdbc 61801 universe/debian-installer/binary-amd64/Packages 988da583db40ce21d400926641fe6ed8 113584 universe/debian-installer/binary-armel/Packages 75381e3ed15a3a2fa1480fdea72cfd24 23193 universe/debian-installer/binary-armel/Packages.bz2 4a8e6a98277f254660e8690fd050b232 27397 universe/debian-installer/binary-armel/Packages.gz 02e7128ef42cd61e66c768520961fb11 20065 universe/debian-installer/binary-armhf/Packages.gz 851afb686177a6819b291a714fa15813 17619 universe/debian-installer/binary-armhf/Packages.bz2 ce3b6645e37226c4047546a40675ecdd 76034 universe/debian-installer/binary-armhf/Packages 229235ad9979a343e3bea9aedb5af8da 17260 universe/debian-installer/binary-i386/Packages.gz 8065c9994844e578af00ef8794709b18 15272 universe/debian-installer/binary-i386/Packages.bz2 f28d6328611ab1e382fb0d0e798aca97 61718 universe/debian-installer/binary-i386/Packages 60f54adbd38213dbbfe5d638f98a17e9 61121 universe/debian-installer/binary-powerpc/Packages 1d48a07b3f4214200ff3eb1c5894e4a1 15024 universe/debian-installer/binary-powerpc/Packages.bz2 51eb13c4b9baf089e4e8b0e85556b90e 16860 universe/debian-installer/binary-powerpc/Packages.gz 155e0b646671f37a7fe235c4579e59f2 2922 universe/i18n/Index 2ef7ccbe106edb394dc69d8511775122 21256524 universe/source/Sources e52b7cb491cc6a950cd11fa6263d7330 5019105 universe/source/Sources.bz2 c722166709cfe9c398643b9c1a443610 102 universe/source/Release 5ddd8bd0dda063b203d1a1da150983a0 6238766 universe/source/Sources.gz SHA1: 0b326daa3b2ac8748ca10942aaec15ebdcc78b36 1640344 main/binary-amd64/Packages.gz 8a6068a75feb86e12b088dad2478600f6670f2d7 7818931 main/binary-amd64/Packages 19655f20d48d9819ad95f2c9ecc59e5b1d94c3d0 97 main/binary-amd64/Release f9761ecf8536859ef38b670a7f17d83febec4a37 1272844 main/binary-amd64/Packages.bz2 a3a5faadbdf0a49d1587f07181b9eca870cb24ce 97 main/binary-armel/Release 3c5d8f3a401427110adfd7f7d65513bfa47b933a 1619078 main/binary-armel/Packages.gz 4d54e387978fdf829b4ff7336ed4d02e61c54d6a 1257389 main/binary-armel/Packages.bz2 969dfd243cc3f514eea9914de571db28621cd9bd 7743353 main/binary-armel/Packages f8f33265eab2ff9fd8a6353e014e36a9d318a54d 97 main/binary-armhf/Release 1d210f8ad3547b771bc8c8d2a9eb5ee99d437d81 7620333 main/binary-armhf/Packages 5057a8b2d11d2325bb2546ad6613517b208fff18 1257653 main/binary-armhf/Packages.bz2 25fc010c2789028727308fbf6132a8da387423b8 1617483 main/binary-armhf/Packages.gz 79369a31bc481f7f9f71f666906c3bdb356c44d8 1273857 main/binary-i386/Packages.bz2 aaadaa6eaf0b7e73b0d371cdebae573f28833a43 1641082 main/binary-i386/Packages.gz 6f8e5e9dd04a2379a7c6d8dc23b4ff8df5584741 96 main/binary-i386/Release 8509eead0c5e9410e23d4226ee5d190220db1275 7816415 main/binary-i386/Packages 7da3fd8ad7102912a4cc9882c66fbb1b65edd4c0 1627734 main/binary-powerpc/Packages.gz 8a0c3b7757b738a89644e8c5a3b9afed806d2f83 99 main/binary-powerpc/Release 4063338a28f6504f7bc2f9c00fc34ac26fc5a1fa 1263942 main/binary-powerpc/Packages.bz2 81844e44aaf0ed255ca200e7316bc9279ef238b6 7661552 main/binary-powerpc/Packages d17439034551742aaa4762b4c174c1d72881f49f 62166 main/debian-installer/binary-amd64/Packages.gz 05e024776b06a40253b9e252caad6dc4a13a90b9 234592 main/debian-installer/binary-amd64/Packages fa692a307ecab69c106a5253107f980527cf58a9 48784 main/debian-installer/binary-amd64/Packages.bz2 fb8be98ef08265d2f101cf265b9bf37654d750ac 47964 main/debian-installer/binary-armel/Packages.bz2 8953964fd2b54539e8276237cd5e4e2d4f9dc2ab 230310 main/debian-installer/binary-armel/Packages cfdde60bbcbfb25c66fa474d28217e03a4c06789 61118 main/debian-installer/binary-armel/Packages.gz 468306dc06acc828c50196427ba324c8ce225c79 62777 main/debian-installer/binary-armhf/Packages.gz 17e7331a837675de31c365529ea9454cc48baf98 49051 main/debian-installer/binary-armhf/Packages.bz2 3404140163a5acece9a054912abf72d11a5591d0 238862 main/debian-installer/binary-armhf/Packages 2bb7e052999eadc333a9f6481bdc20acb238d4c1 52279 main/debian-installer/binary-i386/Packages.bz2 b2ad69cd6759724461c3566d91c1c5ec209eba07 259996 main/debian-installer/binary-i386/Packages ebd0ab3923b3df4eca53eb863773bf0a9a4c3a67 67180 main/debian-installer/binary-i386/Packages.gz eff551b62b72a1c0b183d4903a1452f2be08f3da 246636 main/debian-installer/binary-powerpc/Packages 5c8aa09d48d7a792d555e7b16f4c89733e8441af 50309 main/debian-installer/binary-powerpc/Packages.bz2 582a86208e89e77a7f284e10a50b9cceaf4358ee 64468 main/debian-installer/binary-powerpc/Packages.gz f426621b1015147e766dc003d1d2f140dc9c062d 3706 main/i18n/Index b22a946cdae39d29535a63b020c0f2ad74c3c992 4356187 main/source/Sources 711225fd252e77d85c7bb992aeb5aa5e45414ae1 933770 main/source/Sources.bz2 a8807bf20dbaceb9d408f959840951131fd7d9f9 1174967 main/source/Sources.gz cc2d2f6ce53597666df1a5ab216a08f08995f43f 98 main/source/Release 06b070fc1ae771806c65e791742832320cc588e7 119109 multiverse/binary-amd64/Packages.bz2 ae591617f4b6f988d6534270d4c32e3f0876166b 151924 multiverse/binary-amd64/Packages.gz a28786a87a6136fb74a005c480c78a152123b9c0 581550 multiverse/binary-amd64/Packages 3860a3ce6d87bb8a43803a1048cc96d4de3ae8a7 103 multiverse/binary-amd64/Release 4bae80c3f5270e45f825141bcadb94d7dd82cd0e 136295 multiverse/binary-armel/Packages.gz 9534dfc2e4a40386f48eff79062ee1742212b7d3 519605 multiverse/binary-armel/Packages 92d1536ae99c958afd74299ffe30bdc6800cd8d0 103 multiverse/binary-armel/Release 8e3ec557dc8f750e82e8ed5cbb0c509182feba79 106873 multiverse/binary-armel/Packages.bz2 009531e7cfb08701883a9e7a5f50235325e109cd 104529 multiverse/binary-armhf/Packages.bz2 596a666233560852574d9bca0109f4933a12c949 505901 multiverse/binary-armhf/Packages eca4ab620c41d76c00a9615d8530db5a9c918fe8 103 multiverse/binary-armhf/Release 53916a24cff0523e218bfee2c5464866d2099042 133117 multiverse/binary-armhf/Packages.gz a7518b6b3e693d840a49b125020785d2049e75b9 121196 multiverse/binary-i386/Packages.bz2 84069f1643bd0092f4ec1b24eb921310532d72b2 591662 multiverse/binary-i386/Packages 1d42b054d297b33cf69af011fa91f601c6b1a1b9 102 multiverse/binary-i386/Release 8eae892b29234e9aac4c58a7098b097fe5ebde16 154762 multiverse/binary-i386/Packages.gz 873bc8f864de428a4a47a3afaf53bc3a3a6e81c0 105 multiverse/binary-powerpc/Release 665942774934afa56721d082a398735a067afe91 107209 multiverse/binary-powerpc/Packages.bz2 c965416be0f7bf88c78394becf4a72aee342b829 520882 multiverse/binary-powerpc/Packages e304951d28df0b75065fd3ef8166c65415a3cad2 136930 multiverse/binary-powerpc/Packages.gz da39a3ee5e6b4b0d3255bfef95601890afd80709 0 multiverse/debian-installer/binary-amd64/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 multiverse/debian-installer/binary-amd64/Packages.gz 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 multiverse/debian-installer/binary-amd64/Packages.bz2 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 multiverse/debian-installer/binary-armel/Packages.bz2 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 multiverse/debian-installer/binary-armel/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 multiverse/debian-installer/binary-armel/Packages.gz a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 multiverse/debian-installer/binary-armhf/Packages.gz da39a3ee5e6b4b0d3255bfef95601890afd80709 0 multiverse/debian-installer/binary-armhf/Packages 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 multiverse/debian-installer/binary-armhf/Packages.bz2 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 multiverse/debian-installer/binary-i386/Packages.bz2 a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 multiverse/debian-installer/binary-i386/Packages.gz da39a3ee5e6b4b0d3255bfef95601890afd80709 0 multiverse/debian-installer/binary-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 multiverse/debian-installer/binary-powerpc/Packages.gz da39a3ee5e6b4b0d3255bfef95601890afd80709 0 multiverse/debian-installer/binary-powerpc/Packages 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 multiverse/debian-installer/binary-powerpc/Packages.bz2 09a8aff01c419e0eae19749acf3b223e1f95eccc 2676 multiverse/i18n/Index a088c61bca210afebf4c53904049e2a969d8ece3 154990 multiverse/source/Sources.bz2 df4078a91645024ce93b1ee363003c83ffa2aa84 628753 multiverse/source/Sources e6ec0430d594fa7fa2c98cb9a5fa8ac7ed0d506d 188325 multiverse/source/Sources.gz 0750588f28b1c2cf6a005501c7d027cfa663cce1 104 multiverse/source/Release 200fdeee1984ac78b6fdabfad34d2b485512ca2d 9098 restricted/binary-amd64/Packages.gz 0e7ebd3d2690c7f89d19f8b337cf292cac913c18 134705 restricted/binary-amd64/Packages c968d68baa554ffc7009688ee7d0d3e70663243c 103 restricted/binary-amd64/Release 4185a5b6c2e702ea4754437ebfef23d828ec67a0 8452 restricted/binary-amd64/Packages.bz2 27886dcc6c7d08369cc65d4c35f26b806f57be56 103 restricted/binary-armel/Release a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/binary-armel/Packages.gz 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/binary-armel/Packages.bz2 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/binary-armel/Packages d83803a5f6c2f5c7321d68d126733b6015c8e2a9 103 restricted/binary-armhf/Release 6607111b78dcd3de05cb88692c1e2142abf9a4c1 1103 restricted/binary-armhf/Packages.bz2 b9f55d161632f89b5125a638ca6ad4fe5e9d11fe 2477 restricted/binary-armhf/Packages d0c0a616aeac580d13256693cfbd507ae7c9b280 941 restricted/binary-armhf/Packages.gz f3e483bbe77cbf0f64accbd0291df19b4e4d694b 9108 restricted/binary-i386/Packages.gz 48d76b03a19e4d66d6f7a20339dab91acebaba99 8431 restricted/binary-i386/Packages.bz2 3ca46ea8f32b7cbc49ce76dd1c1ab91589900fd7 134582 restricted/binary-i386/Packages 2aad61f5084ecdd64ff520520d77e980e8b21f81 102 restricted/binary-i386/Release a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/binary-powerpc/Packages.gz 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/binary-powerpc/Packages.bz2 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/binary-powerpc/Packages 6b0a230bbf47463e3d7e88f535e210aaa96a1251 105 restricted/binary-powerpc/Release da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/debian-installer/binary-amd64/Packages 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/debian-installer/binary-amd64/Packages.bz2 a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/debian-installer/binary-amd64/Packages.gz a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/debian-installer/binary-armel/Packages.gz 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/debian-installer/binary-armel/Packages.bz2 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/debian-installer/binary-armel/Packages 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/debian-installer/binary-armhf/Packages.bz2 a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/debian-installer/binary-armhf/Packages.gz da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/debian-installer/binary-armhf/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/debian-installer/binary-i386/Packages.gz 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/debian-installer/binary-i386/Packages.bz2 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/debian-installer/binary-i386/Packages a0fddd5458378c1bf3c10dd2f5c060d1347741ed 20 restricted/debian-installer/binary-powerpc/Packages.gz 64a543afbb5f4bf728636bdcbbe7a2ed0804adc2 14 restricted/debian-installer/binary-powerpc/Packages.bz2 da39a3ee5e6b4b0d3255bfef95601890afd80709 0 restricted/debian-installer/binary-powerpc/Packages d59f5ac2532dcc7cb2f1e5b788c700bf8ab13b66 2596 restricted/i18n/Index 8a80cdcf50cdcabcf4f47c772d7b252587cc9dc1 19001 restricted/source/Sources ff7d82cf1d965953c745d224a1d4adc67b586528 5470 restricted/source/Sources.bz2 f64da9da2038712c5d73ce3337e91d92ee39cd30 5306 restricted/source/Sources.gz 5c963f5f4d4720afa5fbb914375d0033bcd50078 104 restricted/source/Release 10c6989f4a241aabe00146905e776391fc4d9ac0 25546870 universe/binary-amd64/Packages f6900616102430e0eafa8ac89795efff7edc0710 4785960 universe/binary-amd64/Packages.bz2 4f938bde9dff32a49bccd917613666017185882d 6166988 universe/binary-amd64/Packages.gz 9d6cba1ed46b5eee1f6c065934e5f4854b3efee5 101 universe/binary-amd64/Release 3573e863c714c0a083f9c962ea9136916f796e92 101 universe/binary-armel/Release bb8f53ead3723737c13950e5343327884f737da9 4667308 universe/binary-armel/Packages.bz2 43d9a98706b6e50c21092ce35313b5b034f30d01 6009219 universe/binary-armel/Packages.gz 7f97dcbe710882d281efcfd2f8d70ca7d4e47265 24901082 universe/binary-armel/Packages 8f6d42d7f8178a51a7065d7bf3234eecbca12810 5948128 universe/binary-armhf/Packages.gz ea648f433d0edd47de820582fa6a1cd89ef66681 101 universe/binary-armhf/Release e6ad9bdb18ce9e09e262b9e6f85b0b307a3456f1 4618508 universe/binary-armhf/Packages.bz2 ba55530da6c3a9604977ea4a37b4b4d8943ff994 24642528 universe/binary-armhf/Packages 05de59263866a33c104787943347164e7b124aba 6179579 universe/binary-i386/Packages.gz 286a3dd2fda0d98d2ff14eafee0bba5c912d6df2 25568759 universe/binary-i386/Packages 839529b6f6e2a64465e4a825fa5ad46a36f1c73d 100 universe/binary-i386/Release 70c27be4d8bc87dc26bbe6f21fbb7328dc1c4d01 4795820 universe/binary-i386/Packages.bz2 06af7fdef1a54920a7667728a7b810553d00a9c8 25188905 universe/binary-powerpc/Packages 4df1b07075b25ccae6e60d26d5a5761444ece689 6080488 universe/binary-powerpc/Packages.gz 15d041ad1284527b07f75218cf6eb32322092f84 4716652 universe/binary-powerpc/Packages.bz2 42d6a46ed2e525b219f8f6dc076dadbd06fc7f1b 103 universe/binary-powerpc/Release 92c3bef6ad40051021a4e9dadb16e5edc7410b57 15255 universe/debian-installer/binary-amd64/Packages.bz2 31d8725b0d238c282d9b572bb56b7e45c0ff53f8 17243 universe/debian-installer/binary-amd64/Packages.gz e334a7c80e14dae3055950d9e45213db65d4087b 61801 universe/debian-installer/binary-amd64/Packages 1fd1ae2b87eb85525b173ea982d15f3c98e6e33d 113584 universe/debian-installer/binary-armel/Packages c56579feb77b5aac2d261abbbb6c89a1458ca4d9 23193 universe/debian-installer/binary-armel/Packages.bz2 e4b08e57397f3ab0599e0bf6a2fbcba3aed438b5 27397 universe/debian-installer/binary-armel/Packages.gz 5a9608213061eab983392258288e8aec36d006f0 20065 universe/debian-installer/binary-armhf/Packages.gz dc558d56aef72991a3188909a14f752aabdee325 17619 universe/debian-installer/binary-armhf/Packages.bz2 c6afa0e14c706aceea60aad033b6a067320fc165 76034 universe/debian-installer/binary-armhf/Packages f359cf916a19055133546a7b7f3e35c7c260488e 17260 universe/debian-installer/binary-i386/Packages.gz 23920ee4974d88ba824b0e884f8df6e2711a20db 15272 universe/debian-installer/binary-i386/Packages.bz2 21cfd020eefc848307fac14b8f0efe0d6cd9c6ea 61718 universe/debian-installer/binary-i386/Packages f2ff72c8f1fe4ce40ccf44f8ccd6623cedf4e6f0 61121 universe/debian-installer/binary-powerpc/Packages bd9c731941b261b22c022d97ca139bfeb1ad70ba 15024 universe/debian-installer/binary-powerpc/Packages.bz2 e173071bda799068783c9192bff6536db9790a27 16860 universe/debian-installer/binary-powerpc/Packages.gz 59a86abaed7cab292600b6766b18752b7e7c3d49 2922 universe/i18n/Index 4b0ed5f327b0fa9b3f9d9410933a3d2afe467a7e 21256524 universe/source/Sources d0525203f9ad5ec9183996e6765d0ef9a024691f 5019105 universe/source/Sources.bz2 00847d46051ba44d436000b0394b218503de125b 102 universe/source/Release d9706a8ab2ffeadb51b50d042712536a95dc4343 6238766 universe/source/Sources.gz SHA256: 0d61aacd269015c0abfe01fe7f90a4f534c368e9c513f7e90d3111af82656b3d 1640344 main/binary-amd64/Packages.gz a1bc8d839ca9966a0b924e4a4c60f1c23b4d431deb81e1bc529edf95f30fc29d 7818931 main/binary-amd64/Packages a55d3b2e6e2a175529d73e6ca92989018cf57745e705f7ff675b05f80e5141f7 97 main/binary-amd64/Release cc0d3a19c51188b4b4acb80e3013264462c6e0f60759bfd46206c60681bd4ba9 1272844 main/binary-amd64/Packages.bz2 a841750f49bd11f99b9dae6941d2fa6ec1fd87906139d0ceeacf0d4df57a87cf 97 main/binary-armel/Release e80eaf12c1aa520b353de8ad97e79364779e82ef011cb93db372edc900eb7be9 1619078 main/binary-armel/Packages.gz 0ab0929c3c44837886e532f8ec4bee77f3664bdcc2cc3192a02b991c52b156ce 1257389 main/binary-armel/Packages.bz2 ea400cf67f84c12265e4bf419de442a38880fab37d76999985972fc6df3e13b3 7743353 main/binary-armel/Packages f3c40f057bb085f28ef2ed950f62366483d2a418571435c355dc27c0912dccff 97 main/binary-armhf/Release cde037224f43e4619213c5195f2ea5c2f91d078f449579652dbd4128793d5062 7620333 main/binary-armhf/Packages 7c6ea67e609b96dec6f2185df4cd81160e37ba467f9132a9bfb101da3f9a0468 1257653 main/binary-armhf/Packages.bz2 2b83bf5501ecae3347e5c96658edae7d48eef42108b4786471a3de241e75e7d3 1617483 main/binary-armhf/Packages.gz 4d74c53917b84d37cb3277e2b755672a8733e2cfaf949f6e644e6e88094cdaa2 1273857 main/binary-i386/Packages.bz2 07f33bddfefdb4a0c44ddee59fd3eca497df2ad0456e0eeade136e4f0302ee3c 1641082 main/binary-i386/Packages.gz 5182e22f799fe66c8db6dfb073fb040e9e583d88bb9d4d77e058b2afb87e9479 96 main/binary-i386/Release 4cecfc8c0d2113d51b03afa8fdcdcc963d9ad74474696472ec1cdbdb38b856e2 7816415 main/binary-i386/Packages 2795904625f466b4a2fb96d41c00b000ab7f2bdc7f288b0c9ef1283d7e110f87 1627734 main/binary-powerpc/Packages.gz a9247e6d8b0c5977bc1e72be09b1f42a83b5f5a6a70b17f4fef35a0657e3c206 99 main/binary-powerpc/Release 6e745b7edcd67755fa09f54cc3afdd0ffbd0475302a74293472e97e46ba75ddc 1263942 main/binary-powerpc/Packages.bz2 8b953dbae4a14e7ab47151044a47c7b0f0e1dd2a6480170b8172e00d9dad7a2a 7661552 main/binary-powerpc/Packages a5bdf4116ecfeda052d5b3751138c6153e814ac58b2f551503f3ed90e6c3510c 62166 main/debian-installer/binary-amd64/Packages.gz 6a9a4837a4a7df3e7e0566b354b7f1dd2dcf46254335ae3d06a72538f85e410a 234592 main/debian-installer/binary-amd64/Packages 0da4f8190eebfef22103f1f6f7051adbe9489d454ab7224f09d05646407881e8 48784 main/debian-installer/binary-amd64/Packages.bz2 ea01244357deb22c2a4bd7eaa34a1635c0915b89ce174f312c0e0a4b081eaf30 47964 main/debian-installer/binary-armel/Packages.bz2 4177b0519c75f7f950e5a0f0d72d40cc0c4ccf29ebe89fbb9bc1f11a80874526 230310 main/debian-installer/binary-armel/Packages 2b6f81ef9fa687bfb2eb56bb3e90faef0c012351d096b141caa710fd50846043 61118 main/debian-installer/binary-armel/Packages.gz 52c834247ff3a5475466e647802f6eff393f85589e5da5fd3e5b497669b8b49c 62777 main/debian-installer/binary-armhf/Packages.gz 7090f1ad1307a012fbfff883885f16099ed66ebffdeece356f837e632b177a4f 49051 main/debian-installer/binary-armhf/Packages.bz2 4bae13f507993e977c279937406fc03e37fede7805a92508f6d3cba76f1aaf95 238862 main/debian-installer/binary-armhf/Packages d1d23926ff15cfaa6160c5fd0327d181721093fbd2f2e8125be5559a991a81a8 52279 main/debian-installer/binary-i386/Packages.bz2 30e0ec7a2c3d47d5501de8414b436482ff523e9c4983b536b2c9911a30618b98 259996 main/debian-installer/binary-i386/Packages 7a4dcb001ed4bb5fa2458af901de312e11a745bc86a0f877e47567d0f911bc0d 67180 main/debian-installer/binary-i386/Packages.gz 30c2f590c2dedc9f78dfc7f0026b51bc9baa712ac8c9310404d9d6577af77d90 246636 main/debian-installer/binary-powerpc/Packages 6c53fab780cf774c5cabb1788eea1e3446c528cde4352d106907f4ec22449370 50309 main/debian-installer/binary-powerpc/Packages.bz2 b003f3fbf2fa6dbf7d47cf3fbd029ecd86b316ec497a9ac4eea3614cf4ec76af 64468 main/debian-installer/binary-powerpc/Packages.gz fefed230e286d832ab6eb0fb7b72442165b50df23a68402ae6e9d265a31920a2 3706 main/i18n/Index bb618cebb361a2a7148be0bad9af012c8d9de23dbc32d6d9ba035fa6ee0078ab 4356187 main/source/Sources 0aeef2c2258136f9f774c36a158cf759389acf6a35a3153a03d3fa41d4f346d5 933770 main/source/Sources.bz2 4a058ba65244e8eaf17d159b72edebe4e621d54c274a82d4a973b358b4af9a28 1174967 main/source/Sources.gz 864ba9a26e348c6297c08c047d8c228e5ed031ec3d46ef7aad93c3fa550395a8 98 main/source/Release 85477d2b2e7ea2f46b6a059f7526cf52d75fea1a5120aa3b256c576e904d40ff 119109 multiverse/binary-amd64/Packages.bz2 2967ae6c1cc065bec03225d808b4511b138cc13b8de801a0562fec6e30710f36 151924 multiverse/binary-amd64/Packages.gz 18fcf61bb74ef2a01c3d4a8d4646a75836f43244168b43d6ae202f368167b224 581550 multiverse/binary-amd64/Packages fbc4931ef84d50a39da65d110f787aee274df8819a758a3c0aa1ff13f0ba6ee0 103 multiverse/binary-amd64/Release 49f48a34696d08a13a0fdc19a0f6896af2cb477e72860a8880954926c7d45e60 136295 multiverse/binary-armel/Packages.gz f20d7f0bc32b5b2fbcb442f7c128aaad7e18aece3781d53f560932bb191d6830 519605 multiverse/binary-armel/Packages f7ea72b2c07af81f2e342414025dce7a658a6a9915c4d8adc13b992cb3b9fd2f 103 multiverse/binary-armel/Release dd3d4e8a6ec9055d5b553af49822de74648f071ceb0fd314d6cd1aaf7ad6882b 106873 multiverse/binary-armel/Packages.bz2 567c1f9d30a4d6650552d66c5fb43d2d8910d3fed69793daed622d2c699f4bc8 104529 multiverse/binary-armhf/Packages.bz2 a47ef2c0a68adeb70a0bc6b22c94b08402396ff6f5c77664e06c2fb7ee0e7ab0 505901 multiverse/binary-armhf/Packages 6b95e8edaa2bb799f6e15a4a6aaf223da0faea670cd03340395bdcea90205afc 103 multiverse/binary-armhf/Release 14721b333f19a6344addb185f161d1cd14e04ac284c8fa9d726064ec228269a8 133117 multiverse/binary-armhf/Packages.gz 454436f374186007075445c1f206ba5c926f30609baa732c495f1ba456d71e59 121196 multiverse/binary-i386/Packages.bz2 9fabd7bfdbfd216968f7a17265e5609cdd72f1ea7c8f50941e294694e76b180d 591662 multiverse/binary-i386/Packages 7141881b898ac6a78f1ca6f3e81481ee6657f6762fa22768816ab39f6b17e695 102 multiverse/binary-i386/Release 3f4cae31df741f55d523ecea758d05a7e012a205bb03974ee20eb09e3f4fa63b 154762 multiverse/binary-i386/Packages.gz 332dde644a8467496eb5f45ffd2d735ca61ea781da21cd205b3267cd83fa0563 105 multiverse/binary-powerpc/Release 99ef0a611aa32ffa4f16a006d641fbd8dd9e3e73bde3c93b831cd6583746e64b 107209 multiverse/binary-powerpc/Packages.bz2 60f2431dab7bd02fe2c2428bf400c3535be49641cc9d5645a8f1b4fd44f5086f 520882 multiverse/binary-powerpc/Packages cacfd10b40992a617ce32c479f9505531c8cc57e4cf964687d663a5f41f8dcbd 136930 multiverse/binary-powerpc/Packages.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 multiverse/debian-installer/binary-amd64/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 multiverse/debian-installer/binary-amd64/Packages.gz d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 multiverse/debian-installer/binary-amd64/Packages.bz2 d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 multiverse/debian-installer/binary-armel/Packages.bz2 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 multiverse/debian-installer/binary-armel/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 multiverse/debian-installer/binary-armel/Packages.gz f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 multiverse/debian-installer/binary-armhf/Packages.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 multiverse/debian-installer/binary-armhf/Packages d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 multiverse/debian-installer/binary-armhf/Packages.bz2 d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 multiverse/debian-installer/binary-i386/Packages.bz2 f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 multiverse/debian-installer/binary-i386/Packages.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 multiverse/debian-installer/binary-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 multiverse/debian-installer/binary-powerpc/Packages.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 multiverse/debian-installer/binary-powerpc/Packages d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 multiverse/debian-installer/binary-powerpc/Packages.bz2 f0b16a5cfd2d633c9ddecfadfa6742544b18c23ed30023286e2b20ef29f33c73 2676 multiverse/i18n/Index faa0360612fc00453dfdd55b6a1bb20e4f876e041ad6fca410d5da65608ab31e 154990 multiverse/source/Sources.bz2 2f0deae62e2cf7e5257bbd858cb0bf2a94122c4eb82be13e13768d0b9ce84c9e 628753 multiverse/source/Sources 28f6d95fcba03e442cf24dc547653d5ec60177a29d7cfea771efcc5501077747 188325 multiverse/source/Sources.gz f35f721bf16691842cc916c3563fab535f6bb83329f40c33ac02f4ba637707d3 104 multiverse/source/Release 3e872fa356cbce4dfd75a88caa4fc6b47616e1fc7d224f4fc2123650fd7f4be3 9098 restricted/binary-amd64/Packages.gz 459a26c3ef3cb5db8c8355ea6abfa8cfe0a7a266a197929d86d37686daf8a337 134705 restricted/binary-amd64/Packages ea47572182da041b46543e471cb7a6fcc4e001fbe19a27740085ebf5d77252a9 103 restricted/binary-amd64/Release adb08d7f0fa444f2869e8d932db7adb1515839f11af6032284cf1e20060e2dd6 8452 restricted/binary-amd64/Packages.bz2 65a5ac0820d61383f7dcf33699aa029b5965b7906bc8341f94f8f7f354cdcd83 103 restricted/binary-armel/Release f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/binary-armel/Packages.gz d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/binary-armel/Packages.bz2 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/binary-armel/Packages ee447ce81793bd3bc8c127d4e065c6ec24e5901573dffb7cc5abedfbcb86592c 103 restricted/binary-armhf/Release d88ed7df97cd60cdce35c3ca81de66e2bedf0f22e67ec8922dbd5eca545b5e50 1103 restricted/binary-armhf/Packages.bz2 9ade66f4a49598fb371705a79244e5f3abb74c04467f9f9954641ae5acec6766 2477 restricted/binary-armhf/Packages 03d8b64c445f327ce9e369bca815652844bd6aafb344d0287fb4e71f321d0414 941 restricted/binary-armhf/Packages.gz 07e344ed07234876c3fddd9aa763e04bfc2e013fc18428738be71abfb9e1ca77 9108 restricted/binary-i386/Packages.gz 8061335b923c49e72a2b60b437d5bbad1b98a45ac178a68fd8359cec9fad27ec 8431 restricted/binary-i386/Packages.bz2 122336146860047af3d5817dbc423f01d57a90cbf41db1ee0ad9235c0559a43e 134582 restricted/binary-i386/Packages 58634ed42b6fadb280d48f419b960e28151320a62b4486e520ca327719db554a 102 restricted/binary-i386/Release f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/binary-powerpc/Packages.gz d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/binary-powerpc/Packages.bz2 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/binary-powerpc/Packages d9bce398e46f0eac57d1d33fd8a6caa0bd7ab6334508c0640956cb7adbe1eba1 105 restricted/binary-powerpc/Release e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/debian-installer/binary-amd64/Packages d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/debian-installer/binary-amd64/Packages.bz2 f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/debian-installer/binary-amd64/Packages.gz f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/debian-installer/binary-armel/Packages.gz d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/debian-installer/binary-armel/Packages.bz2 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/debian-installer/binary-armel/Packages d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/debian-installer/binary-armhf/Packages.bz2 f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/debian-installer/binary-armhf/Packages.gz e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/debian-installer/binary-armhf/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/debian-installer/binary-i386/Packages.gz d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/debian-installer/binary-i386/Packages.bz2 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/debian-installer/binary-i386/Packages f61f27bd17de546264aa58f40f3aafaac7021e0ef69c17f6b1b4cd7664a037ec 20 restricted/debian-installer/binary-powerpc/Packages.gz d3dda84eb03b9738d118eb2be78e246106900493c0ae07819ad60815134a8058 14 restricted/debian-installer/binary-powerpc/Packages.bz2 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 restricted/debian-installer/binary-powerpc/Packages 17dde58abfdb4dfdad9c8a82db09c9dbc3d8a7cd84b51dd9167579d6899e9ff5 2596 restricted/i18n/Index ee3655459e45778fdfa06fb649565e66b25d2dd0870c75890005fb3597bb71d7 19001 restricted/source/Sources cff18d2ad74ead8712f1b77a23b32e84e54269b03ba2a409ae4227860d1181f5 5470 restricted/source/Sources.bz2 cf085bdcb323dd2c2a599ddb7a9b3ae7bd37121f42024d68b367a4f735df900f 5306 restricted/source/Sources.gz 9137393fc24cf64808d55ca7665bc5a7bd46b48918e6720a95ba239a8fab092e 104 restricted/source/Release 901469729d2354891be94c192dabd8c1d0bc31e1497ea8360b70d2e847c1f3c1 25546870 universe/binary-amd64/Packages 799347395d4e011a215aa5ce0c9006449d8af884795ffbce7a35767a55f99074 4785960 universe/binary-amd64/Packages.bz2 68b08847604c4efe7d6f56ba79f923ce0ab82127dfcc6e8cffaf12af25d7adba 6166988 universe/binary-amd64/Packages.gz 52ffdd1777a886edc5e1e1ef430b03a72937920f9722fd453ee8243cb0aac860 101 universe/binary-amd64/Release a78a1304e105b2fe4c950c77c1794f715c1256d14d8541cca8f5cd13db48119e 101 universe/binary-armel/Release d6d4bfa5d0891086f5a4f2aabfaecd7a1e0c0d8b46aef33b3470e349e7a9210e 4667308 universe/binary-armel/Packages.bz2 374d50d0335c655da46f9cd54cd00d9a20058d2fe7c56989aa121b49883cfb88 6009219 universe/binary-armel/Packages.gz ab5073e90417b729d1fe3b68052e6a8e66e48986c35470944f6a58676e967450 24901082 universe/binary-armel/Packages af74034d1a3e1f90745dc48b996a98c471d997b12a1d810eb8754088540591d7 5948128 universe/binary-armhf/Packages.gz 6697d196b35850817476e884fdc013d9670b4bac73310c54a4d62cd810f02c70 101 universe/binary-armhf/Release 1ca17d3aecec2325cba53e1c299aeb6a1fed01d7acbc40163595de9e651abdeb 4618508 universe/binary-armhf/Packages.bz2 2b422ffa77d4374650d4cc543c5a1123b2535effb2c8cdaf25fd77d1dde632c4 24642528 universe/binary-armhf/Packages cd6b5cb8165553482abee1bf85e5cd3288abadccb6acf34239ec45f79a090784 6179579 universe/binary-i386/Packages.gz 8ef7db20ba08cf1b4d98a618189c615c69865f4da025ac654e3e6b8a4382a3ae 25568759 universe/binary-i386/Packages 06af492500145bd64762d885417d167269db6ea03022c6968f1a5d0515ac55dd 100 universe/binary-i386/Release 530a2efb8051a63ed17431ae0c7243df79ecb418acf1dadc2487cd6fd79fb420 4795820 universe/binary-i386/Packages.bz2 1e8fa52a64292d2c73cee0645d0eed5583ea7cc1138af4744838c6833716d638 25188905 universe/binary-powerpc/Packages 5d2b8e23e0a16f13e25595b63807fb64afd9074aadf7a37b8e238b2011e894b8 6080488 universe/binary-powerpc/Packages.gz eb482b008c8c882b349230abaa812ed6e545a2ef9132bb0d3d3bffa74da0c6c7 4716652 universe/binary-powerpc/Packages.bz2 98d44cc7544f79c18b8e8ea697d476e9b85d91088385b643c82d4064b21f4657 103 universe/binary-powerpc/Release 3da2d1e57aaca628148e2688a951cbb784a9a54b7f6b1f84d530add1b66fcceb 15255 universe/debian-installer/binary-amd64/Packages.bz2 43f891ac590f44fde5854de9ba15222c088b70562f5dc4ff26064909e60cf62e 17243 universe/debian-installer/binary-amd64/Packages.gz 3084a8a441e961eeb3865ff411557166ec105be86a55df268cdb6725f49e1f67 61801 universe/debian-installer/binary-amd64/Packages a1ff01f18766744f36d0774a68d8a89355246c585c4b28ee18e5e139fafae530 113584 universe/debian-installer/binary-armel/Packages e0713f86f5f5121deb60ce61d774951468625184a7ae9576f81d70202ef585b7 23193 universe/debian-installer/binary-armel/Packages.bz2 5a8411e2b0648e553fa25ac82ea83fb17dd2d2a77bd10cec14cab12f5582d4c4 27397 universe/debian-installer/binary-armel/Packages.gz b79c86d926c3129f5c27e50185157a78d85abde8ada90a9910338e660c4318be 20065 universe/debian-installer/binary-armhf/Packages.gz b2113b25380423be8f6202a4860479e44a00072e46fa035f0da2f3a5a280de20 17619 universe/debian-installer/binary-armhf/Packages.bz2 3f023d2cc55d6ebab883f6f2d7305a4e3564f918f63ca4f745d6fd1318e67ab7 76034 universe/debian-installer/binary-armhf/Packages 5ea61a62a3e8fc755c22e23c9d87b20924707c0986a490458472a3d7e9cbe117 17260 universe/debian-installer/binary-i386/Packages.gz 7a90b014c655311e92de1ea4cf24e100665c564a2ed699df63d17c82ad9e1349 15272 universe/debian-installer/binary-i386/Packages.bz2 7e39417ce073e3a35d048847a29a0414af69c4e923c018dc22438319c79adea5 61718 universe/debian-installer/binary-i386/Packages cdf17a791544d0c522fa853a23b317deffa76ac643e88bec0b84b0aa5afe957b 61121 universe/debian-installer/binary-powerpc/Packages b470146da791dc4f4593d2bb00ea4e305d6f55f346a5f3ac6755d890a3318080 15024 universe/debian-installer/binary-powerpc/Packages.bz2 810d1590d1cd7298e1fd5465f85ba49b6ae79780b42d8e8b68aebb42283785ea 16860 universe/debian-installer/binary-powerpc/Packages.gz 563a55a892e1ec8bf565e3294c033b4e8dbbbe4651e73733eac7338db77282f7 2922 universe/i18n/Index 7bc01d4f10bbcf882ce6931aa9371b2de6b35277efc2ae52e233280dcd12a18d 21256524 universe/source/Sources 95135631873f4dce05ba657478475033d02462bbb8f7263832585d1decb5c9b8 5019105 universe/source/Sources.bz2 0fd2ae580be352cb8ab4bb87e5504b78f78bcb7249b644719b3c2db3b5d3ca8c 102 universe/source/Release d1dd96015e24dd369ea22413a2b876686a60c5d9d91958a5df3745a66289910f 6238766 universe/source/Sources.gz PGPy-0.5.4/tests/testdata/simple.jpg000066400000000000000000000022541403641706600173170ustar00rootroot00000000000000JFIFxx }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ? ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( (H#~tPd ЊZ:PdzP@P@csS@ Vj{~䞴;5`>΀ziA ր (>΀hyPGҀ%QހzPmրvqjzh (}I}/NBԊju4M(1@)۸h:Z}1=hP 3k 9P T> ('7@01@ @P@P@P@  ( ( ( ( ( ( ( ( ( ( ( ( ( ( (?PGPy-0.5.4/tox.ini000066400000000000000000000017661403641706600136730ustar00rootroot00000000000000[tox] envlist = py{27,34,35,36,37,38,39}{,-setup}, pypy{,3}, pep8 skipsdist = True [pytest] addopts = -vv -r a -s --color=yes norecursedirs = testdata testpaths = tests markers = regression: mark test as a regression test. [flake8] exclude = .git,.idea,__pycache__,.tox,tests/*,docs/*,test_load_asc_bench.py ignore = E201,E202,E221,E251,E265,F403,F821,N805 max-line-length = 160 [testenv] passenv = HOME ARCHFLAGS LDFLAGS CFLAGS INCLUDE LIB LD_LIBRARY_PATH PATH deps = cryptography>=2.6 enum34 gpg==1.10.0 pyasn1 six>=1.9.0 singledispatch pytest pytest-cov pytest-ordering install_command = pip install {opts} --no-cache-dir {packages} commands = py.test --cov pgpy --cov-report term-missing tests/ [testenv:py{27,34,35,36,37,38,39}-setup] recreate = True allowlist_externals = /usr/bin/rm /bin/rm deps = commands = pip install -e . rm -rf PGPy.egg-info [testenv:pep8] basepython = python3.6 deps = flake8 pep8-naming commands = flake8 PGPy-0.5.4/tox.sh000077500000000000000000000005131403641706600135160ustar00rootroot00000000000000#!/bin/bash # homebrew is installed and so is a brewed openssl if [[ $(uname) == "Darwin" ]] && command -v brew &>/dev/null && brew list openssl@1.1 &>/dev/null; then export ARCHFLAGS="-arch x86_64" export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib" export CFLAGS="-I/usr/local/opt/openssl@1.1/include" fi exec tox $*