Spaces:
Paused
Paused
| # =================================================================== | |
| # | |
| # Copyright (c) 2014, Legrandin <helderijs@gmail.com> | |
| # All rights reserved. | |
| # | |
| # Redistribution and use in source and binary forms, with or without | |
| # modification, are permitted provided that the following conditions | |
| # are met: | |
| # | |
| # 1. Redistributions of source code must retain the above copyright | |
| # notice, this list of conditions and the following disclaimer. | |
| # 2. 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. | |
| # | |
| # 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. | |
| # =================================================================== | |
| from Crypto.Util.py3compat import bchr, bord, iter_range | |
| import Crypto.Util.number | |
| from Crypto.Util.number import (ceil_div, | |
| long_to_bytes, | |
| bytes_to_long | |
| ) | |
| from Crypto.Util.strxor import strxor | |
| from Crypto import Random | |
| class PSS_SigScheme: | |
| """A signature object for ``RSASSA-PSS``. | |
| Do not instantiate directly. | |
| Use :func:`Crypto.Signature.pss.new`. | |
| """ | |
| def __init__(self, key, mgfunc, saltLen, randfunc): | |
| """Initialize this PKCS#1 PSS signature scheme object. | |
| :Parameters: | |
| key : an RSA key object | |
| If a private half is given, both signature and | |
| verification are possible. | |
| If a public half is given, only verification is possible. | |
| mgfunc : callable | |
| A mask generation function that accepts two parameters: | |
| a string to use as seed, and the lenth of the mask to | |
| generate, in bytes. | |
| saltLen : integer | |
| Length of the salt, in bytes. | |
| randfunc : callable | |
| A function that returns random bytes. | |
| """ | |
| self._key = key | |
| self._saltLen = saltLen | |
| self._mgfunc = mgfunc | |
| self._randfunc = randfunc | |
| def can_sign(self): | |
| """Return ``True`` if this object can be used to sign messages.""" | |
| return self._key.has_private() | |
| def sign(self, msg_hash): | |
| """Create the PKCS#1 PSS signature of a message. | |
| This function is also called ``RSASSA-PSS-SIGN`` and | |
| it is specified in | |
| `section 8.1.1 of RFC8017 <https://tools.ietf.org/html/rfc8017#section-8.1.1>`_. | |
| :parameter msg_hash: | |
| This is an object from the :mod:`Crypto.Hash` package. | |
| It has been used to digest the message to sign. | |
| :type msg_hash: hash object | |
| :return: the signature encoded as a *byte string*. | |
| :raise ValueError: if the RSA key is not long enough for the given hash algorithm. | |
| :raise TypeError: if the RSA key has no private half. | |
| """ | |
| # Set defaults for salt length and mask generation function | |
| if self._saltLen is None: | |
| sLen = msg_hash.digest_size | |
| else: | |
| sLen = self._saltLen | |
| if self._mgfunc is None: | |
| mgf = lambda x, y: MGF1(x, y, msg_hash) | |
| else: | |
| mgf = self._mgfunc | |
| modBits = Crypto.Util.number.size(self._key.n) | |
| # See 8.1.1 in RFC3447 | |
| k = ceil_div(modBits, 8) # k is length in bytes of the modulus | |
| # Step 1 | |
| em = _EMSA_PSS_ENCODE(msg_hash, modBits-1, self._randfunc, mgf, sLen) | |
| # Step 2a (OS2IP) | |
| em_int = bytes_to_long(em) | |
| # Step 2b (RSASP1) and Step 2c (I2OSP) | |
| signature = self._key._decrypt_to_bytes(em_int) | |
| # Verify no faults occurred | |
| if em_int != pow(bytes_to_long(signature), self._key.e, self._key.n): | |
| raise ValueError("Fault detected in RSA private key operation") | |
| return signature | |
| def verify(self, msg_hash, signature): | |
| """Check if the PKCS#1 PSS signature over a message is valid. | |
| This function is also called ``RSASSA-PSS-VERIFY`` and | |
| it is specified in | |
| `section 8.1.2 of RFC8037 <https://tools.ietf.org/html/rfc8017#section-8.1.2>`_. | |
| :parameter msg_hash: | |
| The hash that was carried out over the message. This is an object | |
| belonging to the :mod:`Crypto.Hash` module. | |
| :type parameter: hash object | |
| :parameter signature: | |
| The signature that needs to be validated. | |
| :type signature: bytes | |
| :raise ValueError: if the signature is not valid. | |
| """ | |
| # Set defaults for salt length and mask generation function | |
| if self._saltLen is None: | |
| sLen = msg_hash.digest_size | |
| else: | |
| sLen = self._saltLen | |
| if self._mgfunc: | |
| mgf = self._mgfunc | |
| else: | |
| mgf = lambda x, y: MGF1(x, y, msg_hash) | |
| modBits = Crypto.Util.number.size(self._key.n) | |
| # See 8.1.2 in RFC3447 | |
| k = ceil_div(modBits, 8) # Convert from bits to bytes | |
| # Step 1 | |
| if len(signature) != k: | |
| raise ValueError("Incorrect signature") | |
| # Step 2a (O2SIP) | |
| signature_int = bytes_to_long(signature) | |
| # Step 2b (RSAVP1) | |
| em_int = self._key._encrypt(signature_int) | |
| # Step 2c (I2OSP) | |
| emLen = ceil_div(modBits - 1, 8) | |
| em = long_to_bytes(em_int, emLen) | |
| # Step 3/4 | |
| _EMSA_PSS_VERIFY(msg_hash, em, modBits-1, mgf, sLen) | |
| def MGF1(mgfSeed, maskLen, hash_gen): | |
| """Mask Generation Function, described in `B.2.1 of RFC8017 | |
| <https://tools.ietf.org/html/rfc8017>`_. | |
| :param mfgSeed: | |
| seed from which the mask is generated | |
| :type mfgSeed: byte string | |
| :param maskLen: | |
| intended length in bytes of the mask | |
| :type maskLen: integer | |
| :param hash_gen: | |
| A module or a hash object from :mod:`Crypto.Hash` | |
| :type hash_object: | |
| :return: the mask, as a *byte string* | |
| """ | |
| T = b"" | |
| for counter in iter_range(ceil_div(maskLen, hash_gen.digest_size)): | |
| c = long_to_bytes(counter, 4) | |
| hobj = hash_gen.new() | |
| hobj.update(mgfSeed + c) | |
| T = T + hobj.digest() | |
| assert(len(T) >= maskLen) | |
| return T[:maskLen] | |
| def _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): | |
| r""" | |
| Implement the ``EMSA-PSS-ENCODE`` function, as defined | |
| in PKCS#1 v2.1 (RFC3447, 9.1.1). | |
| The original ``EMSA-PSS-ENCODE`` actually accepts the message ``M`` | |
| as input, and hash it internally. Here, we expect that the message | |
| has already been hashed instead. | |
| :Parameters: | |
| mhash : hash object | |
| The hash object that holds the digest of the message being signed. | |
| emBits : int | |
| Maximum length of the final encoding, in bits. | |
| randFunc : callable | |
| An RNG function that accepts as only parameter an int, and returns | |
| a string of random bytes, to be used as salt. | |
| mgf : callable | |
| A mask generation function that accepts two parameters: a string to | |
| use as seed, and the lenth of the mask to generate, in bytes. | |
| sLen : int | |
| Length of the salt, in bytes. | |
| :Return: An ``emLen`` byte long string that encodes the hash | |
| (with ``emLen = \ceil(emBits/8)``). | |
| :Raise ValueError: | |
| When digest or salt length are too big. | |
| """ | |
| emLen = ceil_div(emBits, 8) | |
| # Bitmask of digits that fill up | |
| lmask = 0 | |
| for i in iter_range(8*emLen-emBits): | |
| lmask = lmask >> 1 | 0x80 | |
| # Step 1 and 2 have been already done | |
| # Step 3 | |
| if emLen < mhash.digest_size+sLen+2: | |
| raise ValueError("Digest or salt length are too long" | |
| " for given key size.") | |
| # Step 4 | |
| salt = randFunc(sLen) | |
| # Step 5 | |
| m_prime = bchr(0)*8 + mhash.digest() + salt | |
| # Step 6 | |
| h = mhash.new() | |
| h.update(m_prime) | |
| # Step 7 | |
| ps = bchr(0)*(emLen-sLen-mhash.digest_size-2) | |
| # Step 8 | |
| db = ps + bchr(1) + salt | |
| # Step 9 | |
| dbMask = mgf(h.digest(), emLen-mhash.digest_size-1) | |
| # Step 10 | |
| maskedDB = strxor(db, dbMask) | |
| # Step 11 | |
| maskedDB = bchr(bord(maskedDB[0]) & ~lmask) + maskedDB[1:] | |
| # Step 12 | |
| em = maskedDB + h.digest() + bchr(0xBC) | |
| return em | |
| def _EMSA_PSS_VERIFY(mhash, em, emBits, mgf, sLen): | |
| """ | |
| Implement the ``EMSA-PSS-VERIFY`` function, as defined | |
| in PKCS#1 v2.1 (RFC3447, 9.1.2). | |
| ``EMSA-PSS-VERIFY`` actually accepts the message ``M`` as input, | |
| and hash it internally. Here, we expect that the message has already | |
| been hashed instead. | |
| :Parameters: | |
| mhash : hash object | |
| The hash object that holds the digest of the message to be verified. | |
| em : string | |
| The signature to verify, therefore proving that the sender really | |
| signed the message that was received. | |
| emBits : int | |
| Length of the final encoding (em), in bits. | |
| mgf : callable | |
| A mask generation function that accepts two parameters: a string to | |
| use as seed, and the lenth of the mask to generate, in bytes. | |
| sLen : int | |
| Length of the salt, in bytes. | |
| :Raise ValueError: | |
| When the encoding is inconsistent, or the digest or salt lengths | |
| are too big. | |
| """ | |
| emLen = ceil_div(emBits, 8) | |
| # Bitmask of digits that fill up | |
| lmask = 0 | |
| for i in iter_range(8*emLen-emBits): | |
| lmask = lmask >> 1 | 0x80 | |
| # Step 1 and 2 have been already done | |
| # Step 3 | |
| if emLen < mhash.digest_size+sLen+2: | |
| raise ValueError("Incorrect signature") | |
| # Step 4 | |
| if ord(em[-1:]) != 0xBC: | |
| raise ValueError("Incorrect signature") | |
| # Step 5 | |
| maskedDB = em[:emLen-mhash.digest_size-1] | |
| h = em[emLen-mhash.digest_size-1:-1] | |
| # Step 6 | |
| if lmask & bord(em[0]): | |
| raise ValueError("Incorrect signature") | |
| # Step 7 | |
| dbMask = mgf(h, emLen-mhash.digest_size-1) | |
| # Step 8 | |
| db = strxor(maskedDB, dbMask) | |
| # Step 9 | |
| db = bchr(bord(db[0]) & ~lmask) + db[1:] | |
| # Step 10 | |
| if not db.startswith(bchr(0)*(emLen-mhash.digest_size-sLen-2) + bchr(1)): | |
| raise ValueError("Incorrect signature") | |
| # Step 11 | |
| if sLen > 0: | |
| salt = db[-sLen:] | |
| else: | |
| salt = b"" | |
| # Step 12 | |
| m_prime = bchr(0)*8 + mhash.digest() + salt | |
| # Step 13 | |
| hobj = mhash.new() | |
| hobj.update(m_prime) | |
| hp = hobj.digest() | |
| # Step 14 | |
| if h != hp: | |
| raise ValueError("Incorrect signature") | |
| def new(rsa_key, **kwargs): | |
| """Create an object for making or verifying PKCS#1 PSS signatures. | |
| :parameter rsa_key: | |
| The RSA key to use for signing or verifying the message. | |
| This is a :class:`Crypto.PublicKey.RSA` object. | |
| Signing is only possible when ``rsa_key`` is a **private** RSA key. | |
| :type rsa_key: RSA object | |
| :Keyword Arguments: | |
| * *mask_func* (``callable``) -- | |
| A function that returns the mask (as `bytes`). | |
| It must accept two parameters: a seed (as `bytes`) | |
| and the length of the data to return. | |
| If not specified, it will be the function :func:`MGF1` defined in | |
| `RFC8017 <https://tools.ietf.org/html/rfc8017#page-67>`_ and | |
| combined with the same hash algorithm applied to the | |
| message to sign or verify. | |
| If you want to use a different function, for instance still :func:`MGF1` | |
| but together with another hash, you can do:: | |
| from Crypto.Hash import SHA256 | |
| from Crypto.Signature.pss import MGF1 | |
| mgf = lambda x, y: MGF1(x, y, SHA256) | |
| * *salt_bytes* (``integer``) -- | |
| Length of the salt, in bytes. | |
| It is a value between 0 and ``emLen - hLen - 2``, where ``emLen`` | |
| is the size of the RSA modulus and ``hLen`` is the size of the digest | |
| applied to the message to sign or verify. | |
| The salt is generated internally, you don't need to provide it. | |
| If not specified, the salt length will be ``hLen``. | |
| If it is zero, the signature scheme becomes deterministic. | |
| Note that in some implementations such as OpenSSL the default | |
| salt length is ``emLen - hLen - 2`` (even though it is not more | |
| secure than ``hLen``). | |
| * *rand_func* (``callable``) -- | |
| A function that returns random ``bytes``, of the desired length. | |
| The default is :func:`Crypto.Random.get_random_bytes`. | |
| :return: a :class:`PSS_SigScheme` signature object | |
| """ | |
| mask_func = kwargs.pop("mask_func", None) | |
| salt_len = kwargs.pop("salt_bytes", None) | |
| rand_func = kwargs.pop("rand_func", None) | |
| if rand_func is None: | |
| rand_func = Random.get_random_bytes | |
| if kwargs: | |
| raise ValueError("Unknown keywords: " + str(kwargs.keys())) | |
| return PSS_SigScheme(rsa_key, mask_func, salt_len, rand_func) | |