From cd59bd275ecc484b1662c86ae9ef0a64eb17d00f Mon Sep 17 00:00:00 2001 From: Jeff Yang Date: Mon, 8 Jul 2019 16:44:11 -0400 Subject: add class methods for poly1305 sign verify operations (#4932) --- CHANGELOG.rst | 7 ++++ docs/hazmat/primitives/mac/poly1305.rst | 45 ++++++++++++++++++++++++++ src/cryptography/hazmat/primitives/poly1305.py | 12 +++++++ tests/hazmat/primitives/test_poly1305.py | 27 ++++++++++++++++ 4 files changed, 91 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9ece6d1d..2421efee 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -8,6 +8,13 @@ Changelog .. note:: This version is not yet released and is under active development. +* Added class methods + :meth:`Poly1305.generate_tag + ` + and + :meth:`Poly1305.verify_tag + ` + for Poly1305 sign and verify operations. * Deprecated support for OpenSSL 1.0.1. Support will be removed in ``cryptography`` 2.9. * We now ship ``manylinux2010`` wheels in addition to our ``manylinux1`` diff --git a/docs/hazmat/primitives/mac/poly1305.rst b/docs/hazmat/primitives/mac/poly1305.rst index 1d0753c6..7504a076 100644 --- a/docs/hazmat/primitives/mac/poly1305.rst +++ b/docs/hazmat/primitives/mac/poly1305.rst @@ -85,3 +85,48 @@ messages allows an attacker to forge tags. Poly1305 is described in :return bytes: The message authentication code as bytes. :raises cryptography.exceptions.AlreadyFinalized: + + .. classmethod:: generate_tag(key, data) + + A single step alternative to do sign operations. Returns the message + authentication code as ``bytes`` for the given ``key`` and ``data``. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :return bytes: The message authentication code as bytes. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + :raises TypeError: This exception is raised if ``key`` or ``data`` are + not ``bytes``. + + .. doctest:: + + >>> poly1305.Poly1305.generate_tag(key, b"message to authenticate") + b'T\xae\xff3\xbdW\xef\xd5r\x01\xe2n=\xb7\xd2h' + + .. classmethod:: verify_tag(key, data, tag) + + A single step alternative to do verify operations. Securely compares the + MAC to ``tag``, using the given ``key`` and ``data``. + + :param key: Secret key as ``bytes``. + :type key: :term:`bytes-like` + :param data: The bytes to hash and authenticate. + :type data: :term:`bytes-like` + :param bytes tag: The bytes to compare against. + :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if + the version of OpenSSL ``cryptography`` is compiled against does not + support this algorithm. + :raises TypeError: This exception is raised if ``key``, ``data`` or + ``tag`` are not ``bytes``. + :raises cryptography.exceptions.InvalidSignature: If tag does not match. + + .. doctest:: + + >>> poly1305.Poly1305.verify_tag(key, b"message to authenticate", b"an incorrect tag") + Traceback (most recent call last): + ... + cryptography.exceptions.InvalidSignature: Value did not match computed tag. diff --git a/src/cryptography/hazmat/primitives/poly1305.py b/src/cryptography/hazmat/primitives/poly1305.py index 02b6629d..d92f62ad 100644 --- a/src/cryptography/hazmat/primitives/poly1305.py +++ b/src/cryptography/hazmat/primitives/poly1305.py @@ -41,3 +41,15 @@ class Poly1305(object): ctx, self._ctx = self._ctx, None ctx.verify(tag) + + @classmethod + def generate_tag(cls, key, data): + p = Poly1305(key) + p.update(data) + return p.finalize() + + @classmethod + def verify_tag(cls, key, data, tag): + p = Poly1305(key) + p.update(data) + p.verify(tag) diff --git a/tests/hazmat/primitives/test_poly1305.py b/tests/hazmat/primitives/test_poly1305.py index 71495ff7..edca4623 100644 --- a/tests/hazmat/primitives/test_poly1305.py +++ b/tests/hazmat/primitives/test_poly1305.py @@ -47,6 +47,9 @@ class TestPoly1305(object): poly.update(msg) assert poly.finalize() == tag + assert Poly1305.generate_tag(key, msg) == tag + Poly1305.verify_tag(key, msg, tag) + def test_key_with_no_additional_references(self, backend): poly = Poly1305(os.urandom(32)) assert len(poly.finalize()) == 16 @@ -66,6 +69,9 @@ class TestPoly1305(object): with pytest.raises(TypeError): poly.update(u'') + with pytest.raises(TypeError): + Poly1305.generate_tag(b"0" * 32, u'') + def test_verify(self, backend): poly = Poly1305(b"0" * 32) poly.update(b"msg") @@ -78,6 +84,8 @@ class TestPoly1305(object): poly2.update(b"msg") poly2.verify(tag) + Poly1305.verify_tag(b"0" * 32, b"msg", tag) + def test_invalid_verify(self, backend): poly = Poly1305(b"0" * 32) poly.update(b"msg") @@ -89,22 +97,37 @@ class TestPoly1305(object): with pytest.raises(InvalidSignature): p2.verify(b"\x00" * 16) + with pytest.raises(InvalidSignature): + Poly1305.verify_tag(b"0" * 32, b"msg", b"\x00" * 16) + def test_verify_reject_unicode(self, backend): poly = Poly1305(b"0" * 32) with pytest.raises(TypeError): poly.verify(u'') + with pytest.raises(TypeError): + Poly1305.verify_tag(b"0" * 32, b"msg", u'') + def test_invalid_key_type(self, backend): with pytest.raises(TypeError): Poly1305(object()) + with pytest.raises(TypeError): + Poly1305.generate_tag(object(), b"msg") + def test_invalid_key_length(self, backend): with pytest.raises(ValueError): Poly1305(b"0" * 31) + with pytest.raises(ValueError): + Poly1305.generate_tag(b"0" * 31, b"msg") + with pytest.raises(ValueError): Poly1305(b"0" * 33) + with pytest.raises(ValueError): + Poly1305.generate_tag(b"0" * 33, b"msg") + def test_buffer_protocol(self, backend): key = binascii.unhexlify( b"1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cb" @@ -123,3 +146,7 @@ class TestPoly1305(object): assert poly.finalize() == binascii.unhexlify( b"4541669a7eaaee61e708dc7cbcc5eb62" ) + + assert Poly1305.generate_tag(key, msg) == binascii.unhexlify( + b"4541669a7eaaee61e708dc7cbcc5eb62" + ) -- cgit v1.2.3