def sign(self, msg_hash): """Create the PKCS#1 v1.5 signature of a message. This function is also called ``RSASSA-PKCS1-V1_5-SIGN`` and it is specified in `section 8.2.1 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-36>`_. :parameter msg_hash: This is an object from the :mod:`Cryptodome.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. """ # See 8.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes # Step 1 em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) # Step 2a (OS2IP) em_int = bytes_to_long(em) # Step 2b (RSASP1) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
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:`Cryptodome.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 getrandbits(self, k): """Return an integer with k random bits.""" if self._randfunc is None: self._randfunc = Random.new().read mask = (1 << k) - 1 return mask & bytes_to_long(self._randfunc(ceil_div(k, 8)))
def randrange(self, *args): """randrange([start,] stop[, step]): Return a randomly-selected element from range(start, stop, step).""" if len(args) == 3: (start, stop, step) = args elif len(args) == 2: (start, stop) = args step = 1 elif len(args) == 1: (stop, ) = args start = 0 step = 1 else: raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args), )) if (not is_native_int(start) or not is_native_int(stop) or not is_native_int(step)): raise TypeError("randrange requires integer arguments") if step == 0: raise ValueError("randrange step argument must not be zero") num_choices = ceil_div(stop - start, step) if num_choices < 0: num_choices = 0 if num_choices < 1: raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) # Pick a random number in the range of possible numbers r = num_choices while r >= num_choices: r = self.getrandbits(size(num_choices)) return start + (step * r)
def sign(self, msg_hash): """Produce the PKCS#1 v1.5 signature of a message. This function is named ``RSASSA-PKCS1-V1_5-SIGN``; it is specified in section 8.2.1 of RFC3447. :Parameters: msg_hash : hash object This is an object created with to the `Cryptodome.Hash` module. It was used used to hash the message to sign. :Return: The signature encoded as a byte string. :Raise ValueError: If the RSA key is not long enough when combined with the given hash algorithm. :Raise TypeError: If the RSA key has no private half. """ # See 8.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes # Step 1 em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) # Step 2a (OS2IP) em_int = bytes_to_long(em) # Step 2b (RSASP1) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
def _encrypt(key, message): mod_bits = size(key.n) k = ceil_div(mod_bits, 8) m_len = len(message) # Step 1 if m_len > k - 11: raise ValueError("Plaintext is too long.") # Step 2a ps = [] while len(ps) != k - m_len - 3: new_byte = bchr(0xFF) if bord(new_byte[0]) == 0x00: continue ps.append(new_byte) ps = b("").join(ps) assert (len(ps) == k - m_len - 3) # Step 2b em = b('\x00\x01') + ps + bchr(0x00) + message # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) if not 0 < em_int < key._n: raise ValueError("Plaintext too large") m_int = int(pow(Integer(em_int), key._d, key._n)) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def sign(self, msg_hash): """Produce the PKCS#1 v1.5 signature of a message. This function is named ``RSASSA-PKCS1-V1_5-SIGN``; it is specified in section 8.2.1 of RFC3447. :Parameters: msg_hash : hash object This is an object created with to the `Cryptodome.Hash` module. It was used used to hash the message to sign. :Return: The signature encoded as a byte string. :Raise ValueError: If the RSA key is not long enough when combined with the given hash algorithm. :Raise TypeError: If the RSA key has no private half. """ # See 8.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes # Step 1 em = _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k) # Step 2a (OS2IP) em_int = bytes_to_long(em) # Step 2b (RSASP1) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
def randrange(self, *args): """randrange([start,] stop[, step]): Return a randomly-selected element from range(start, stop, step).""" if len(args) == 3: (start, stop, step) = args elif len(args) == 2: (start, stop) = args step = 1 elif len(args) == 1: (stop,) = args start = 0 step = 1 else: raise TypeError("randrange expected at most 3 arguments, got %d" % (len(args),)) if (not isinstance(start, (int, long)) or not isinstance(stop, (int, long)) or not isinstance(step, (int, long))): raise TypeError("randrange requires integer arguments") if step == 0: raise ValueError("randrange step argument must not be zero") num_choices = ceil_div(stop - start, step) if num_choices < 0: num_choices = 0 if num_choices < 1: raise ValueError("empty range for randrange(%r, %r, %r)" % (start, stop, step)) # Pick a random number in the range of possible numbers r = num_choices while r >= num_choices: r = self.getrandbits(size(num_choices)) return start + (step * r)
def verify(self, msg_hash, signature): """Verify that a certain PKCS#1 PSS signature is authentic. This function checks if the party holding the private half of the given RSA key has really signed the message. This function is called ``RSASSA-PSS-VERIFY``, and is specified in section 8.1.2 of RFC3447. :Parameters: msg_hash : hash object The cryptographic hash computed over the message. This is an object belonging to the `Cryptodome.Hash` module. signature : byte string The signature that needs to be validated. :Raise ValueError: if the signature is incorrect. """ # 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 = Cryptodome.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 verify(self, msg_hash, signature): """Verify that a certain PKCS#1 PSS signature is authentic. This function checks if the party holding the private half of the given RSA key has really signed the message. This function is called ``RSASSA-PSS-VERIFY``, and is specified in section 8.1.2 of RFC3447. :Parameters: msg_hash : hash object The cryptographic hash computed over the message. This is an object belonging to the `Cryptodome.Hash` module. signature : byte string The signature that needs to be validated. :Raise ValueError: if the signature is incorrect. """ # 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 = Cryptodome.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 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:`Cryptodome.Hash` module. :type parameter: hash object :parameter signature: The signature that needs to be validated. :type signature: byte string :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 = Cryptodome.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 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:`Cryptodome.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 = Cryptodome.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 sign(self, msg_digest): modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes ps = b'\xFF' * (k - len(msg_digest) - 3) em = b'\x00\x01' + ps + b'\x00' + msg_digest em_int = bytes_to_long(em) m_int = self._key._decrypt(em_int) signature = long_to_bytes(m_int, k) return signature
def MGF1(mgfSeed, maskLen, hash): """Mask Generation Function, described in B.2.1""" T = b("") for counter in xrange(ceil_div(maskLen, hash.digest_size)): c = long_to_bytes(counter, 4) hobj = hash.new() hobj.update(mgfSeed + c) T = T + hobj.digest() assert(len(T) >= maskLen) return T[:maskLen]
def MGF1(mgfSeed, maskLen, hash): """Mask Generation Function, described in B.2.1""" T = b("") for counter in xrange(ceil_div(maskLen, hash.digest_size)): c = long_to_bytes(counter, 4) hobj = hash.new() hobj.update(mgfSeed + c) T = T + hobj.digest() assert (len(T) >= maskLen) return T[:maskLen]
def verify(self, msg_hash, signature): """Verify that a certain PKCS#1 v1.5 signature is valid. This method checks if the message really originates from someone that holds the RSA private key. really signed the message. This function is named ``RSASSA-PKCS1-V1_5-VERIFY``; it is specified in section 8.2.2 of RFC3447. :Parameters: msg_hash : hash object The hash that was carried out over the message. This is an object belonging to the `Cryptodome.Hash` module. signature : byte string The signature that needs to be validated. :Raise ValueError: if the signature is not valid. """ # See 8.2.2 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes # Step 1 if len(signature) != k: raise ValueError("Invalid signature") # Step 2a (O2SIP) signature_int = bytes_to_long(signature) # Step 2b (RSAVP1) em_int = self._key._encrypt(signature_int) # Step 2c (I2OSP) em1 = long_to_bytes(em_int, k) # Step 3 try: possible_em1 = [_EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, True)] # MD2/4/5 hashes always require NULL params in AlgorithmIdentifier. # For all others, it is optional. try: algorithm_is_md = msg_hash.oid.startswith('1.2.840.113549.2.') except AttributeError: algorithm_is_md = False if not algorithm_is_md: # MD2/MD4/MD5 possible_em1.append(_EMSA_PKCS1_V1_5_ENCODE( msg_hash, k, False)) except ValueError: raise ValueError("Invalid signature") # Step 4 # By comparing the full encodings (as opposed to checking each # of its components one at a time) we avoid attacks to the padding # scheme like Bleichenbacher's (see http://www.mail-archive.com/[email protected]/msg06537). # if em1 not in possible_em1: raise ValueError("Invalid signature") pass
def encrypt(self, message): """Produce the PKCS#1 OAEP encryption of a message. This function is named ``RSAES-OAEP-ENCRYPT``, and is specified in section 7.1.1 of RFC3447. :Parameters: message : byte string The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 2, minus twice the hash output size. :Return: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raise ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # TODO: Verify the key is RSA # See 7.1.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes hLen = self._hashObj.digest_size mLen = len(message) # Step 1b ps_len = k - mLen - 2 * hLen - 2 if ps_len < 0: raise ValueError("Plaintext is too long.") # Step 2a lHash = self._hashObj.new(self._label).digest() # Step 2b ps = bchr(0x00) * ps_len # Step 2c db = lHash + ps + bchr(0x01) + message # Step 2d ros = self._randfunc(hLen) # Step 2e dbMask = self._mgf(ros, k - hLen - 1) # Step 2f maskedDB = strxor(db, dbMask) # Step 2g seedMask = self._mgf(maskedDB, hLen) # Step 2h maskedSeed = strxor(ros, seedMask) # Step 2i em = bchr(0x00) + maskedSeed + maskedDB # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def encrypt(self, message): """Produce the PKCS#1 OAEP encryption of a message. This function is named ``RSAES-OAEP-ENCRYPT``, and is specified in section 7.1.1 of RFC3447. :Parameters: message : byte string The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 2, minus twice the hash output size. :Return: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raise ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # TODO: Verify the key is RSA # See 7.1.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes hLen = self._hashObj.digest_size mLen = len(message) # Step 1b ps_len = k-mLen-2*hLen-2 if ps_len<0: raise ValueError("Plaintext is too long.") # Step 2a lHash = self._hashObj.new(self._label).digest() # Step 2b ps = bchr(0x00)*ps_len # Step 2c db = lHash + ps + bchr(0x01) + message # Step 2d ros = self._randfunc(hLen) # Step 2e dbMask = self._mgf(ros, k-hLen-1) # Step 2f maskedDB = strxor(db, dbMask) # Step 2g seedMask = self._mgf(maskedDB, hLen) # Step 2h maskedSeed = strxor(ros, seedMask) # Step 2i em = bchr(0x00) + maskedSeed + maskedDB # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def verify(self, msg_hash, signature): """Verify that a certain PKCS#1 v1.5 signature is valid. This method checks if the message really originates from someone that holds the RSA private key. really signed the message. This function is named ``RSASSA-PKCS1-V1_5-VERIFY``; it is specified in section 8.2.2 of RFC3447. :Parameters: msg_hash : hash object The hash that was carried out over the message. This is an object belonging to the `Cryptodome.Hash` module. signature : byte string The signature that needs to be validated. :Raise ValueError: if the signature is not valid. """ # See 8.2.2 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes # Step 1 if len(signature) != k: raise ValueError("Invalid signature") # Step 2a (O2SIP) signature_int = bytes_to_long(signature) # Step 2b (RSAVP1) em_int = self._key._encrypt(signature_int) # Step 2c (I2OSP) em1 = long_to_bytes(em_int, k) # Step 3 try: possible_em1 = [ _EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, True) ] # MD2/4/5 hashes always require NULL params in AlgorithmIdentifier. # For all others, it is optional. try: algorithm_is_md = msg_hash.oid.startswith('1.2.840.113549.2.') except AttributeError: algorithm_is_md = False if not algorithm_is_md: # MD2/MD4/MD5 possible_em1.append(_EMSA_PKCS1_V1_5_ENCODE(msg_hash, k, False)) except ValueError: raise ValueError("Invalid signature") # Step 4 # By comparing the full encodings (as opposed to checking each # of its components one at a time) we avoid attacks to the padding # scheme like Bleichenbacher's (see http://www.mail-archive.com/[email protected]/msg06537). # if em1 not in possible_em1: raise ValueError("Invalid signature") pass
def encrypt(self, message): """Encrypt a message with PKCS#1 OAEP. :param message: The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 2, minus twice the hash output size. For instance, if you use RSA 2048 and SHA-256, the longest message you can encrypt is 190 byte long. :type message: byte string :returns: The ciphertext, as large as the RSA modulus. :rtype: byte string :raises ValueError: if the message is too long. """ # TODO: Verify the key is RSA # See 7.1.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes hLen = self._hashObj.digest_size mLen = len(message) # Step 1b ps_len = k-mLen-2*hLen-2 if ps_len<0: raise ValueError("Plaintext is too long.") # Step 2a lHash = self._hashObj.new(self._label).digest() # Step 2b ps = bchr(0x00)*ps_len # Step 2c db = lHash + ps + bchr(0x01) + message # Step 2d ros = self._randfunc(hLen) # Step 2e dbMask = self._mgf(ros, k-hLen-1) # Step 2f maskedDB = strxor(db, dbMask) # Step 2g seedMask = self._mgf(maskedDB, hLen) # Step 2h maskedSeed = strxor(ros, seedMask) # Step 2i em = bchr(0x00) + maskedSeed + maskedDB # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def attack(c: bytes): e, n = K B = 1 << (8 * (k - 2)) # Init. print('Step 1......', end=' ', flush=True) if oracle(c): # m was already padded before encryption s0 = 1 else: # Step 1 s0 = random.randint(0, n - 1) while not oracle(c * pow(s0, e, n)): s0 = random.randint(0, n - 1) M = [(2 * B, 3 * B - 1)] c0 = (c * pow(s0, e, n)) % n i = 1 print('ok') # Step 2.a print('Step 2a.....', end=' ', flush=True) s = ceil_div(n, 3 * B) while not oracle(c0 * pow(s, e, n)): s += 1 print('ok') while True: print(f'Steps 2b-4... {i}', end='\r', flush=True) if len(M) > 1: # Step 2.b s += 1 while not oracle(c0 * pow(s, e, n)): s += 1 else: # Step 2.c a, b = M[0] r = ceil_div(2 * (b * s - 2 * B), n) # as in the article, #r = ceil_div(2*(b*s-B), n) # or corrected typo? s = ceil_div(2 * B + r * n, b) while not oracle(c0 * pow(s, e, n)): s += 1 if a * s >= 3 * B + r * n: r += 1 s = ceil_div(2 * B + r * n, b) # Step 3 Mupd = [] for a, b in M: r = ceil_div(a * s - 3 * B + 1, n) while n * r <= b * s - 2 * B: a1 = max(a, ceil_div(2 * B + r * n, s)) b1 = min(b, (3 * B - 1 + r * n) // s) if a1 <= b1: Mupd.append((a1, b1)) r += 1 M = merge_intervals(Mupd) # Step 4 if len(M) == 1 and M[0][0] == M[0][1]: return (M[0][0] * inverse(s0, n)) % n i += 1
def sign(self, msg_hash): """Produce the PKCS#1 PSS signature of a message. This function is named ``RSASSA-PSS-SIGN``, and is specified in section 8.1.1 of RFC3447. :Parameters: msg_hash : hash object The hash that was carried out over the message. This is an object belonging to the `Cryptodome.Hash` module. :Return: The PSS signature encoded as a byte string. :Raise ValueError: If the RSA key length is not sufficiently long to deal with the given hash algorithm. :Raise TypeError: If the RSA key has no private half. :attention: Modify the salt length and the mask generation function only if you know what you are doing. The receiver must use the same parameters too. """ # 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 = Cryptodome.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) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
def sign(self, msg_hash): """Produce the PKCS#1 PSS signature of a message. This function is named ``RSASSA-PSS-SIGN``, and is specified in section 8.1.1 of RFC3447. :Parameters: msg_hash : hash object The hash that was carried out over the message. This is an object belonging to the `Cryptodome.Hash` module. :Return: The PSS signature encoded as a byte string. :Raise ValueError: If the RSA key length is not sufficiently long to deal with the given hash algorithm. :Raise TypeError: If the RSA key has no private half. :attention: Modify the salt length and the mask generation function only if you know what you are doing. The receiver must use the same parameters too. """ # 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 = Cryptodome.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) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
def _decrypt(key, ciphertext): modBits = size(key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes # Step 1 if len(ciphertext) != k: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(bstr(ciphertext)) # Step 2b (RSADP) m_int = pow(Integer(ct_int), key._e, key._n) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3 sep = em.find(bchr(0x00), 2) # Step 4 return em[sep + 1:]
def encrypt(self, message): """Produce the PKCS#1 v1.5 encryption of a message. This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in `section 7.2.1 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-28>`_. :param message: The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 11. :type message: byte string/array :Returns: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raises ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # See 7.2.1 in RFC8017 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes mLen = len(message) # Step 1 if mLen > k - 11: raise ValueError("Plaintext is too long.") # Step 2a ps = [] while len(ps) != k - mLen - 3: new_byte = self._randfunc(1) if bord(new_byte[0]) == 0x00: continue ps.append(new_byte) ps = b("").join(ps) assert (len(ps) == k - mLen - 3) # Step 2b em = b('\x00\x02') + ps + bchr(0x00) + bstr(message) # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def encrypt(self, message): """Produce the PKCS#1 v1.5 encryption of a message. This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and it is specified in `section 7.2.1 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-28>`_. :param message: The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 11. :type message: bytes/bytearray/memoryview :Returns: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raises ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # See 7.2.1 in RFC8017 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes mLen = len(message) # Step 1 if mLen > k - 11: raise ValueError("Plaintext is too long.") # Step 2a ps = [] while len(ps) != k - mLen - 3: new_byte = self._randfunc(1) if bord(new_byte[0]) == 0x00: continue ps.append(new_byte) ps = b"".join(ps) assert(len(ps) == k - mLen - 3) # Step 2b em = b'\x00\x02' + ps + b'\x00' + _copy_bytes(None, None, message) # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
def encrypt(self, message): """Produce the PKCS#1 v1.5 encryption of a message. This function is named ``RSAES-PKCS1-V1_5-ENCRYPT``, and is specified in section 7.2.1 of RFC3447. For a complete example see `Cryptodome.Cipher.PKCS1_v1_5`. :Parameters: message : byte string The message to encrypt, also known as plaintext. It can be of variable length, but not longer than the RSA modulus (in bytes) minus 11. :Return: A byte string, the ciphertext in which the message is encrypted. It is as long as the RSA modulus (in bytes). :Raise ValueError: If the RSA key length is not sufficiently long to deal with the given message. """ # See 7.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes mLen = len(message) # Step 1 if mLen > k-11: raise ValueError("Plaintext is too long.") # Step 2a ps = [] while len(ps) != k - mLen - 3: new_byte = self._randfunc(1) if bord(new_byte[0]) == 0x00: continue ps.append(new_byte) ps = b("").join(ps) assert(len(ps) == k - mLen - 3) # Step 2b em = b('\x00\x02') + ps + bchr(0x00) + message # Step 3a (OS2IP) em_int = bytes_to_long(em) # Step 3b (RSAEP) m_int = self._key._encrypt(em_int) # Step 3c (I2OSP) c = long_to_bytes(m_int, k) return c
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:`Cryptodome.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 = Cryptodome.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) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
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:`Cryptodome.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 = Cryptodome.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) m_int = self._key._decrypt(em_int) # Step 2c (I2OSP) signature = long_to_bytes(m_int, k) return signature
def decrypt(self, ciphertext, sentinel): # See 7.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes # Step 1 if len(ciphertext) != k: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ciphertext) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3 sep = em.find(b'\x00', 2) # pkcs#1_v115 是 x00x02 if not (em.startswith(b'\x00\x02') or em.startswith(b'\x00\x01')) or sep < 10: return sentinel # Step 4 return em[sep + 1:]
def decrypt(self, ciphertext, sentinel): """Decrypt a PKCS#1 v1.5 ciphertext. This function is named ``RSAES-PKCS1-V1_5-DECRYPT``, and is specified in `section 7.2.2 of RFC8017 <https://tools.ietf.org/html/rfc8017#page-29>`_. :param ciphertext: The ciphertext that contains the message to recover. :type ciphertext: byte string/array :param sentinel: The object to return whenever an error is detected. :type sentinel: any type :Returns: A byte string. It is either the original message or the ``sentinel`` (in case of an error). :Raises ValueError: If the ciphertext length is incorrect :Raises TypeError: If the RSA key has no private half (i.e. it cannot be used for decyption). .. warning:: You should **never** let the party who submitted the ciphertext know that this function returned the ``sentinel`` value. Armed with such knowledge (for a fair amount of carefully crafted but invalid ciphertexts), an attacker is able to recontruct the plaintext of any other encryption that were carried out with the same RSA public key (see `Bleichenbacher's`__ attack). In general, it should not be possible for the other party to distinguish whether processing at the server side failed because the value returned was a ``sentinel`` as opposed to a random, invalid message. In fact, the second option is not that unlikely: encryption done according to PKCS#1 v1.5 embeds no good integrity check. There is roughly one chance in 2\ :sup:`16` for a random ciphertext to be returned as a valid message (although random looking). It is therefore advisabled to: 1. Select as ``sentinel`` a value that resembles a plausable random, invalid message. 2. Not report back an error as soon as you detect a ``sentinel`` value. Put differently, you should not explicitly check if the returned value is the ``sentinel`` or not. 3. Cover all possible errors with a single, generic error indicator. 4. Embed into the definition of ``message`` (at the protocol level) a digest (e.g. ``SHA-1``). It is recommended for it to be the rightmost part ``message``. 5. Where possible, monitor the number of errors due to ciphertexts originating from the same party, and slow down the rate of the requests from such party (or even blacklist it altogether). **If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.** .. __: http://www.bell-labs.com/user/bleichen/papers/pkcs.ps """ # See 7.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes # Step 1 if len(ciphertext) != k: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(bstr(ciphertext)) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3 sep = em.find(bchr(0x00), 2) if not em.startswith(b('\x00\x02')) or sep < 10: return sentinel # Step 4 return em[sep + 1:]
def decrypt(self, ciphertext): """Decrypt a message with PKCS#1 OAEP. :param ciphertext: The encrypted message. :type ciphertext: bytes/bytearray/memoryview :returns: The original message (plaintext). :rtype: bytes :raises ValueError: if the ciphertext has the wrong length, or if decryption fails the integrity check (in which case, the decryption key is probably wrong). :raises TypeError: if the RSA key has no private half (i.e. you are trying to decrypt using a public key). """ # See 7.1.2 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes hLen = self._hashObj.digest_size # Step 1b and 1c if len(ciphertext) != k or k<hLen+2: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ciphertext) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3a lHash = self._hashObj.new(self._label).digest() # Step 3b y = em[0] # y must be 0, but we MUST NOT check it here in order not to # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) maskedSeed = em[1:hLen+1] maskedDB = em[hLen+1:] # Step 3c seedMask = self._mgf(maskedDB, hLen) # Step 3d seed = strxor(maskedSeed, seedMask) # Step 3e dbMask = self._mgf(seed, k-hLen-1) # Step 3f db = strxor(maskedDB, dbMask) # Step 3g one_pos = hLen + db[hLen:].find(b'\x01') lHash1 = db[:hLen] invalid = bord(y) | int(one_pos < hLen) hash_compare = strxor(lHash1, lHash) for x in hash_compare: invalid |= bord(x) for x in db[hLen:one_pos]: invalid |= bord(x) if invalid != 0: raise ValueError("Incorrect decryption.") # Step 4 return db[one_pos + 1:]
def decrypt(self, ct): """Decrypt a PKCS#1 OAEP ciphertext. This function is named ``RSAES-OAEP-DECRYPT``, and is specified in section 7.1.2 of RFC3447. :Parameters: ct : byte string The ciphertext that contains the message to recover. :Return: A byte string, the original message. :Raise ValueError: If the ciphertext length is incorrect, or if the decryption does not succeed. :Raise TypeError: If the RSA key has no private half. """ # See 7.1.2 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits, 8) # Convert from bits to bytes hLen = self._hashObj.digest_size # Step 1b and 1c if len(ct) != k or k < hLen + 2: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ct) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3a lHash = self._hashObj.new(self._label).digest() # Step 3b y = em[0] # y must be 0, but we MUST NOT check it here in order not to # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) maskedSeed = em[1:hLen + 1] maskedDB = em[hLen + 1:] # Step 3c seedMask = self._mgf(maskedDB, hLen) # Step 3d seed = strxor(maskedSeed, seedMask) # Step 3e dbMask = self._mgf(seed, k - hLen - 1) # Step 3f db = strxor(maskedDB, dbMask) # Step 3g valid = 1 one = db[hLen:].find(bchr(0x01)) lHash1 = db[:hLen] if lHash1 != lHash: valid = 0 if one < 0: valid = 0 if bord(y) != 0: valid = 0 if not valid: raise ValueError("Incorrect decryption.") # Step 4 return db[hLen + one + 1:]
def decrypt(self, ct): """Decrypt a PKCS#1 OAEP ciphertext. This function is named ``RSAES-OAEP-DECRYPT``, and is specified in section 7.1.2 of RFC3447. :Parameters: ct : byte string The ciphertext that contains the message to recover. :Return: A byte string, the original message. :Raise ValueError: If the ciphertext length is incorrect, or if the decryption does not succeed. :Raise TypeError: If the RSA key has no private half. """ # See 7.1.2 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes hLen = self._hashObj.digest_size # Step 1b and 1c if len(ct) != k or k<hLen+2: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ct) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3a lHash = self._hashObj.new(self._label).digest() # Step 3b y = em[0] # y must be 0, but we MUST NOT check it here in order not to # allow attacks like Manger's (http://dl.acm.org/citation.cfm?id=704143) maskedSeed = em[1:hLen+1] maskedDB = em[hLen+1:] # Step 3c seedMask = self._mgf(maskedDB, hLen) # Step 3d seed = strxor(maskedSeed, seedMask) # Step 3e dbMask = self._mgf(seed, k-hLen-1) # Step 3f db = strxor(maskedDB, dbMask) # Step 3g valid = 1 one = db[hLen:].find(bchr(0x01)) lHash1 = db[:hLen] if lHash1!=lHash: valid = 0 if one<0: valid = 0 if bord(y)!=0: valid = 0 if not valid: raise ValueError("Incorrect decryption.") # Step 4 return db[hLen+one+1:]
def test_ceil_div(self): """Util.number.ceil_div""" self.assertRaises(TypeError, number.ceil_div, "1", 1) self.assertRaises(ZeroDivisionError, number.ceil_div, 1, 0) self.assertRaises(ZeroDivisionError, number.ceil_div, -1, 0) # b = 1 self.assertEqual(0, number.ceil_div(0, 1)) self.assertEqual(1, number.ceil_div(1, 1)) self.assertEqual(2, number.ceil_div(2, 1)) self.assertEqual(3, number.ceil_div(3, 1)) # b = 2 self.assertEqual(0, number.ceil_div(0, 2)) self.assertEqual(1, number.ceil_div(1, 2)) self.assertEqual(1, number.ceil_div(2, 2)) self.assertEqual(2, number.ceil_div(3, 2)) self.assertEqual(2, number.ceil_div(4, 2)) self.assertEqual(3, number.ceil_div(5, 2)) # b = 3 self.assertEqual(0, number.ceil_div(0, 3)) self.assertEqual(1, number.ceil_div(1, 3)) self.assertEqual(1, number.ceil_div(2, 3)) self.assertEqual(1, number.ceil_div(3, 3)) self.assertEqual(2, number.ceil_div(4, 3)) self.assertEqual(2, number.ceil_div(5, 3)) self.assertEqual(2, number.ceil_div(6, 3)) self.assertEqual(3, number.ceil_div(7, 3)) # b = 4 self.assertEqual(0, number.ceil_div(0, 4)) self.assertEqual(1, number.ceil_div(1, 4)) self.assertEqual(1, number.ceil_div(2, 4)) self.assertEqual(1, number.ceil_div(3, 4)) self.assertEqual(1, number.ceil_div(4, 4)) self.assertEqual(2, number.ceil_div(5, 4)) self.assertEqual(2, number.ceil_div(6, 4)) self.assertEqual(2, number.ceil_div(7, 4)) self.assertEqual(2, number.ceil_div(8, 4)) self.assertEqual(3, number.ceil_div(9, 4))
def test_ceil_div(self): """Util.number.ceil_div""" self.assertRaises(TypeError, number.ceil_div, "1", 1) self.assertRaises(ZeroDivisionError, number.ceil_div, 1, 0) self.assertRaises(ZeroDivisionError, number.ceil_div, -1, 0) # b = -1 self.assertEqual(0, number.ceil_div(0, -1)) self.assertEqual(-1, number.ceil_div(1, -1)) self.assertEqual(-2, number.ceil_div(2, -1)) self.assertEqual(-3, number.ceil_div(3, -1)) # b = 1 self.assertEqual(0, number.ceil_div(0, 1)) self.assertEqual(1, number.ceil_div(1, 1)) self.assertEqual(2, number.ceil_div(2, 1)) self.assertEqual(3, number.ceil_div(3, 1)) # b = 2 self.assertEqual(0, number.ceil_div(0, 2)) self.assertEqual(1, number.ceil_div(1, 2)) self.assertEqual(1, number.ceil_div(2, 2)) self.assertEqual(2, number.ceil_div(3, 2)) self.assertEqual(2, number.ceil_div(4, 2)) self.assertEqual(3, number.ceil_div(5, 2)) # b = 3 self.assertEqual(0, number.ceil_div(0, 3)) self.assertEqual(1, number.ceil_div(1, 3)) self.assertEqual(1, number.ceil_div(2, 3)) self.assertEqual(1, number.ceil_div(3, 3)) self.assertEqual(2, number.ceil_div(4, 3)) self.assertEqual(2, number.ceil_div(5, 3)) self.assertEqual(2, number.ceil_div(6, 3)) self.assertEqual(3, number.ceil_div(7, 3)) # b = 4 self.assertEqual(0, number.ceil_div(0, 4)) self.assertEqual(1, number.ceil_div(1, 4)) self.assertEqual(1, number.ceil_div(2, 4)) self.assertEqual(1, number.ceil_div(3, 4)) self.assertEqual(1, number.ceil_div(4, 4)) self.assertEqual(2, number.ceil_div(5, 4)) self.assertEqual(2, number.ceil_div(6, 4)) self.assertEqual(2, number.ceil_div(7, 4)) self.assertEqual(2, number.ceil_div(8, 4)) self.assertEqual(3, number.ceil_div(9, 4)) # b = -4 self.assertEqual(3, number.ceil_div(-9, -4)) self.assertEqual(2, number.ceil_div(-8, -4)) self.assertEqual(2, number.ceil_div(-7, -4)) self.assertEqual(2, number.ceil_div(-6, -4)) self.assertEqual(2, number.ceil_div(-5, -4)) self.assertEqual(1, number.ceil_div(-4, -4)) self.assertEqual(1, number.ceil_div(-3, -4)) self.assertEqual(1, number.ceil_div(-2, -4)) self.assertEqual(1, number.ceil_div(-1, -4)) self.assertEqual(0, number.ceil_div(0, -4)) self.assertEqual(0, number.ceil_div(1, -4)) self.assertEqual(0, number.ceil_div(2, -4)) self.assertEqual(0, number.ceil_div(3, -4)) self.assertEqual(-1, number.ceil_div(4, -4)) self.assertEqual(-1, number.ceil_div(5, -4)) self.assertEqual(-1, number.ceil_div(6, -4)) self.assertEqual(-1, number.ceil_div(7, -4)) self.assertEqual(-2, number.ceil_div(8, -4)) self.assertEqual(-2, number.ceil_div(9, -4))
def decrypt(self, ct, sentinel): """Decrypt a PKCS#1 v1.5 ciphertext. This function is named ``RSAES-PKCS1-V1_5-DECRYPT``, and is specified in section 7.2.2 of RFC3447. For a complete example see `Cryptodome.Cipher.PKCS1_v1_5`. :Parameters: ct : byte string The ciphertext that contains the message to recover. sentinel : any type The object to return to indicate that an error was detected during decryption. :Return: A byte string. It is either the original message or the ``sentinel`` (in case of an error). :Raise ValueError: If the ciphertext length is incorrect :Raise TypeError: If the RSA key has no private half. :attention: You should **never** let the party who submitted the ciphertext know that this function returned the ``sentinel`` value. Armed with such knowledge (for a fair amount of carefully crafted but invalid ciphertexts), an attacker is able to recontruct the plaintext of any other encryption that were carried out with the same RSA public key (see `Bleichenbacher's`__ attack). In general, it should not be possible for the other party to distinguish whether processing at the server side failed because the value returned was a ``sentinel`` as opposed to a random, invalid message. In fact, the second option is not that unlikely: encryption done according to PKCS#1 v1.5 embeds no good integrity check. There is roughly one chance in 2^16 for a random ciphertext to be returned as a valid message (although random looking). It is therefore advisabled to: 1. Select as ``sentinel`` a value that resembles a plausable random, invalid message. 2. Not report back an error as soon as you detect a ``sentinel`` value. Put differently, you should not explicitly check if the returned value is the ``sentinel`` or not. 3. Cover all possible errors with a single, generic error indicator. 4. Embed into the definition of ``message`` (at the protocol level) a digest (e.g. ``SHA-1``). It is recommended for it to be the rightmost part ``message``. 5. Where possible, monitor the number of errors due to ciphertexts originating from the same party, and slow down the rate of the requests from such party (or even blacklist it altogether). **If you are designing a new protocol, consider using the more robust PKCS#1 OAEP.** .. __: http://www.bell-labs.com/user/bleichen/papers/pkcs.ps """ # See 7.2.1 in RFC3447 modBits = Cryptodome.Util.number.size(self._key.n) k = ceil_div(modBits,8) # Convert from bits to bytes # Step 1 if len(ct) != k: raise ValueError("Ciphertext with incorrect length.") # Step 2a (O2SIP) ct_int = bytes_to_long(ct) # Step 2b (RSADP) m_int = self._key._decrypt(ct_int) # Complete step 2c (I2OSP) em = long_to_bytes(m_int, k) # Step 3 sep = em.find(bchr(0x00),2) if not em.startswith(b('\x00\x02')) or sep<10: return sentinel # Step 4 return em[sep+1:]
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 _EMSA_PSS_ENCODE(mhash, emBits, randFunc, mgf, sLen): """ 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_ENCODE(mhash, emBits, randFunc, mgf, sLen): """ 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: return False # 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")