| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | # | 
					
						
							|  |  |  | #  Signature/DSS.py : DSS.py | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # =================================================================== | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2014-06-23 22:20:10 +02:00
										 |  |  | # 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. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | # =================================================================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from Crypto.Util.asn1 import DerSequence | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  | from Crypto.Util.number import long_to_bytes | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  | from Crypto.Math.Numbers import Integer | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-17 08:21:04 +02:00
										 |  |  | from Crypto.Hash import HMAC | 
					
						
							| 
									
										
										
										
											2019-03-01 22:54:31 +01:00
										 |  |  | from Crypto.PublicKey.ECC import EccKey | 
					
						
							| 
									
										
										
										
											2021-01-02 00:52:11 +01:00
										 |  |  | from Crypto.PublicKey.DSA import DsaKey | 
					
						
							| 
									
										
										
										
											2013-07-17 08:21:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  | __all__ = ['DssSigScheme', 'new'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-31 23:27:55 +01:00
										 |  |  | class DssSigScheme(object): | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |     """A (EC)DSA signature object.
 | 
					
						
							|  |  |  |     Do not instantiate directly. | 
					
						
							|  |  |  |     Use :func:`Crypto.Signature.DSS.new`. | 
					
						
							| 
									
										
										
										
											2016-02-07 13:01:09 +01:00
										 |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |     def __init__(self, key, encoding, order): | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |         """Create a new Digital Signature Standard (DSS) object.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Do not instantiate this object directly, | 
					
						
							|  |  |  |         use `Crypto.Signature.DSS.new` instead. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         self._key = key | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         self._encoding = encoding | 
					
						
							|  |  |  |         self._order = order | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         self._order_bits = self._order.size_in_bits() | 
					
						
							|  |  |  |         self._order_bytes = (self._order_bits - 1) // 8 + 1 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def can_sign(self): | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |         """Return ``True`` if this signature object can be used
 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |         for signing messages."""
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return self._key.has_private() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     def _compute_nonce(self, msg_hash): | 
					
						
							|  |  |  |         raise NotImplementedError("To be provided by subclasses") | 
					
						
							| 
									
										
										
										
											2013-07-17 08:21:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     def _valid_hash(self, msg_hash): | 
					
						
							|  |  |  |         raise NotImplementedError("To be provided by subclasses") | 
					
						
							| 
									
										
										
										
											2013-07-17 08:21:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-07 21:00:50 +02:00
										 |  |  |     def sign(self, msg_hash): | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |         """Compute the DSA/ECDSA signature of a message.
 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |         Args: | 
					
						
							|  |  |  |           msg_hash (hash object): | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |             The hash that was carried out over the message. | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |             The object belongs to the :mod:`Crypto.Hash` package. | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |             Under mode ``'fips-186-3'``, the hash must be a FIPS | 
					
						
							|  |  |  |             approved secure hash (SHA-1 or a member of the SHA-2/SHA-3 families), | 
					
						
							|  |  |  |             of cryptographic strength appropriate for the (EC)DSA key. | 
					
						
							|  |  |  |             For instance, a P-521 ECC key can only be used | 
					
						
							|  |  |  |             in combination with SHA2-512. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |         :return: The signature as ``bytes`` | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |         :raise ValueError: if the hash algorithm is incompatible to the (EC)DSA key | 
					
						
							|  |  |  |         :raise TypeError: if the (EC)DSA key has no private half | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         if not self._valid_hash(msg_hash): | 
					
						
							|  |  |  |             raise ValueError("Hash is not sufficiently strong") | 
					
						
							| 
									
										
										
										
											2013-07-17 08:21:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         # Generate the nonce k (critical!) | 
					
						
							|  |  |  |         nonce = self._compute_nonce(msg_hash) | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-16 21:42:39 +02:00
										 |  |  |         # Perform signature using the raw API | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) | 
					
						
							| 
									
										
										
										
											2014-06-16 21:42:39 +02:00
										 |  |  |         sig_pair = self._key._sign(z, nonce) | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Encode the signature into a single byte string | 
					
						
							|  |  |  |         if self._encoding == 'binary': | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |             output = b"".join([long_to_bytes(x, self._order_bytes) | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |                                for x in sig_pair]) | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |         else: | 
					
						
							|  |  |  |             # Dss-sig  ::=  SEQUENCE  { | 
					
						
							| 
									
										
										
										
											2020-04-18 16:23:45 +02:00
										 |  |  |             #   r   INTEGER, | 
					
						
							|  |  |  |             #   s   INTEGER | 
					
						
							|  |  |  |             # } | 
					
						
							|  |  |  |             # Ecdsa-Sig-Value  ::=  SEQUENCE  { | 
					
						
							|  |  |  |             #   r   INTEGER, | 
					
						
							|  |  |  |             #   s   INTEGER | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |             # } | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |             output = DerSequence(sig_pair).encode() | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return output | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-07 21:00:50 +02:00
										 |  |  |     def verify(self, msg_hash, signature): | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |         """Check if a certain (EC)DSA signature is authentic.
 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |         Args: | 
					
						
							|  |  |  |           msg_hash (hash object): | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |             The hash that was carried out over the message. | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |             This is an object belonging to the :mod:`Crypto.Hash` module. | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |             Under mode ``'fips-186-3'``, the hash must be a FIPS | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |             approved secure hash (SHA-1 or a member of the SHA-2 family), | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |             of cryptographic strength appropriate for the (EC)DSA key. | 
					
						
							|  |  |  |             For instance, a P-521 ECC key can only be used | 
					
						
							|  |  |  |             in combination with SHA2-512. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |           signature (``bytes``): | 
					
						
							|  |  |  |             The signature that needs to be validated. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |         :raise ValueError: if the signature is not authentic | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         if not self._valid_hash(msg_hash): | 
					
						
							| 
									
										
										
										
											2019-03-09 11:12:05 +01:00
										 |  |  |             raise ValueError("Hash is not sufficiently strong") | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if self._encoding == 'binary': | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |             if len(signature) != (2 * self._order_bytes): | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |                 raise ValueError("The signature is not authentic (length)") | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |             r_prime, s_prime = [Integer.from_bytes(x) | 
					
						
							|  |  |  |                                 for x in (signature[:self._order_bytes], | 
					
						
							|  |  |  |                                           signature[self._order_bytes:])] | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							| 
									
										
										
										
											2018-04-12 14:13:12 +02:00
										 |  |  |                 der_seq = DerSequence().decode(signature, strict=True) | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |             except (ValueError, IndexError): | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |                 raise ValueError("The signature is not authentic (DER)") | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |             if len(der_seq) != 2 or not der_seq.hasOnlyInts(): | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |                 raise ValueError("The signature is not authentic (DER content)") | 
					
						
							| 
									
										
										
										
											2017-11-06 16:22:03 +00:00
										 |  |  |             r_prime, s_prime = Integer(der_seq[0]), Integer(der_seq[1]) | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         if not (0 < r_prime < self._order) or not (0 < s_prime < self._order): | 
					
						
							| 
									
										
										
										
											2016-01-07 23:46:02 +01:00
										 |  |  |             raise ValueError("The signature is not authentic (d)") | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         z = Integer.from_bytes(msg_hash.digest()[:self._order_bytes]) | 
					
						
							| 
									
										
										
										
											2014-06-16 21:42:39 +02:00
										 |  |  |         result = self._key._verify(z, (r_prime, s_prime)) | 
					
						
							| 
									
										
										
										
											2014-06-07 21:00:50 +02:00
										 |  |  |         if not result: | 
					
						
							|  |  |  |             raise ValueError("The signature is not authentic") | 
					
						
							|  |  |  |         # Make PyCrypto code to fail | 
					
						
							|  |  |  |         return False | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-31 23:27:55 +01:00
										 |  |  | class DeterministicDsaSigScheme(DssSigScheme): | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |     # Also applicable to ECDSA | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |     def __init__(self, key, encoding, order, private_key): | 
					
						
							|  |  |  |         super(DeterministicDsaSigScheme, self).__init__(key, encoding, order) | 
					
						
							|  |  |  |         self._private_key = private_key | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     def _bits2int(self, bstr): | 
					
						
							|  |  |  |         """See 2.3.2 in RFC6979""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         result = Integer.from_bytes(bstr) | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         q_len = self._order.size_in_bits() | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         b_len = len(bstr) * 8 | 
					
						
							|  |  |  |         if b_len > q_len: | 
					
						
							| 
									
										
										
										
											2019-03-09 11:12:16 +01:00
										 |  |  |             # Only keep leftmost q_len bits | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |             result >>= (b_len - q_len) | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _int2octets(self, int_mod_q): | 
					
						
							|  |  |  |         """See 2.3.3 in RFC6979""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         assert 0 < int_mod_q < self._order | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         return long_to_bytes(int_mod_q, self._order_bytes) | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def _bits2octets(self, bstr): | 
					
						
							|  |  |  |         """See 2.3.4 in RFC6979""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         z1 = self._bits2int(bstr) | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         if z1 < self._order: | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |             z2 = z1 | 
					
						
							|  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |             z2 = z1 - self._order | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         return self._int2octets(z2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _compute_nonce(self, mhash): | 
					
						
							|  |  |  |         """Generate k in a deterministic way""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # See section 3.2 in RFC6979.txt | 
					
						
							|  |  |  |         # Step a | 
					
						
							|  |  |  |         h1 = mhash.digest() | 
					
						
							|  |  |  |         # Step b | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |         mask_v = b'\x01' * mhash.digest_size | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         # Step c | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |         nonce_k = b'\x00' * mhash.digest_size | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |         for int_oct in (b'\x00', b'\x01'): | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |             # Step d/f | 
					
						
							|  |  |  |             nonce_k = HMAC.new(nonce_k, | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |                                mask_v + int_oct + | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |                                self._int2octets(self._private_key) + | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |                                self._bits2octets(h1), mhash).digest() | 
					
						
							|  |  |  |             # Step e/g | 
					
						
							|  |  |  |             mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         nonce = -1 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         while not (0 < nonce < self._order): | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |             # Step h.C (second part) | 
					
						
							|  |  |  |             if nonce != -1: | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |                 nonce_k = HMAC.new(nonce_k, mask_v + b'\x00', | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |                                    mhash).digest() | 
					
						
							|  |  |  |                 mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Step h.A | 
					
						
							| 
									
										
										
										
											2018-11-04 11:31:40 +01:00
										 |  |  |             mask_t = b"" | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # Step h.B | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |             while len(mask_t) < self._order_bytes: | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |                 mask_v = HMAC.new(nonce_k, mask_v, mhash).digest() | 
					
						
							|  |  |  |                 mask_t += mask_v | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # Step h.C (first part) | 
					
						
							|  |  |  |             nonce = self._bits2int(mask_t) | 
					
						
							|  |  |  |         return nonce | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _valid_hash(self, msg_hash): | 
					
						
							|  |  |  |         return True | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-31 23:27:55 +01:00
										 |  |  | class FipsDsaSigScheme(DssSigScheme): | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     #: List of L (bit length of p) and N (bit length of q) combinations | 
					
						
							|  |  |  |     #: that are allowed by FIPS 186-3. The security level is provided in | 
					
						
							|  |  |  |     #: Table 2 of FIPS 800-57 (rev3). | 
					
						
							|  |  |  |     _fips_186_3_L_N = ( | 
					
						
							|  |  |  |                         (1024, 160),    # 80 bits  (SHA-1 or stronger) | 
					
						
							|  |  |  |                         (2048, 224),    # 112 bits (SHA-224 or stronger) | 
					
						
							|  |  |  |                         (2048, 256),    # 128 bits (SHA-256 or stronger) | 
					
						
							|  |  |  |                         (3072, 256)     # 256 bits (SHA-512) | 
					
						
							|  |  |  |                       ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |     def __init__(self, key, encoding, order, randfunc): | 
					
						
							|  |  |  |         super(FipsDsaSigScheme, self).__init__(key, encoding, order) | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         self._randfunc = randfunc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         L = Integer(key.p).size_in_bits() | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         if (L, self._order_bits) not in self._fips_186_3_L_N: | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |             error = ("L/N (%d, %d) is not compliant to FIPS 186-3" | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |                      % (L, self._order_bits)) | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |             raise ValueError(error) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _compute_nonce(self, msg_hash): | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         # hash is not used | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         return Integer.random_range(min_inclusive=1, | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |                                     max_exclusive=self._order, | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |                                     randfunc=self._randfunc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _valid_hash(self, msg_hash): | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         """Verify that SHA-1, SHA-2 or SHA-3 are used""" | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |         return (msg_hash.oid == "1.3.14.3.2.26" or | 
					
						
							|  |  |  |                 msg_hash.oid.startswith("2.16.840.1.101.3.4.2.")) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-31 23:27:55 +01:00
										 |  |  | class FipsEcDsaSigScheme(DssSigScheme): | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |     def __init__(self, key, encoding, order, randfunc): | 
					
						
							|  |  |  |         super(FipsEcDsaSigScheme, self).__init__(key, encoding, order) | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         self._randfunc = randfunc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _compute_nonce(self, msg_hash): | 
					
						
							|  |  |  |         return Integer.random_range(min_inclusive=1, | 
					
						
							| 
									
										
										
										
											2019-03-01 22:54:31 +01:00
										 |  |  |                                     max_exclusive=self._key._curve.order, | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |                                     randfunc=self._randfunc) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def _valid_hash(self, msg_hash): | 
					
						
							| 
									
										
										
										
											2022-01-21 23:11:15 +01:00
										 |  |  |         """Verify that the strength of the hash matches or exceeds
 | 
					
						
							|  |  |  |         the strength of the EC. We fail if the hash is too weak."""
 | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-07 23:15:17 +01:00
										 |  |  |         modulus_bits = self._key.pointQ.size_in_bits() | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-21 23:11:15 +01:00
										 |  |  |         sha224 = ("2.16.840.1.101.3.4.2.4", "2.16.840.1.101.3.4.2.7") | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |         sha256 = ("2.16.840.1.101.3.4.2.1", "2.16.840.1.101.3.4.2.8") | 
					
						
							|  |  |  |         sha384 = ("2.16.840.1.101.3.4.2.2", "2.16.840.1.101.3.4.2.9") | 
					
						
							|  |  |  |         sha512 = ("2.16.840.1.101.3.4.2.3", "2.16.840.1.101.3.4.2.10") | 
					
						
							| 
									
										
										
										
											2019-03-07 23:15:17 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-21 23:11:15 +01:00
										 |  |  |         if msg_hash.oid in sha224: | 
					
						
							|  |  |  |             result = modulus_bits <= 224 | 
					
						
							|  |  |  |         elif msg_hash.oid in sha256: | 
					
						
							|  |  |  |             result = modulus_bits <= 256 | 
					
						
							| 
									
										
										
										
											2019-03-07 23:15:17 +01:00
										 |  |  |         elif msg_hash.oid in sha384: | 
					
						
							| 
									
										
										
										
											2022-01-21 23:11:15 +01:00
										 |  |  |             result = modulus_bits <= 384 | 
					
						
							| 
									
										
										
										
											2019-03-07 23:15:17 +01:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2022-01-21 23:11:15 +01:00
										 |  |  |             result = msg_hash.oid in sha512 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return result | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | def new(key, mode, encoding='binary', randfunc=None): | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |     """Create a signature object :class:`DssSigScheme` that
 | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |     can perform (EC)DSA signature or verification. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  |     .. note:: | 
					
						
							|  |  |  |         Refer to `NIST SP 800 Part 1 Rev 4`_ (or newer release) for an | 
					
						
							|  |  |  |         overview of the recommended key lengths. | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-20 23:35:13 +01:00
										 |  |  |     Args: | 
					
						
							|  |  |  |         key (:class:`Crypto.PublicKey.DSA` or :class:`Crypto.PublicKey.ECC`): | 
					
						
							|  |  |  |             The key to use for computing the signature (*private* keys only) | 
					
						
							|  |  |  |             or for verifying one. | 
					
						
							|  |  |  |             For DSA keys, let ``L`` and ``N`` be the bit lengths of the modulus ``p`` | 
					
						
							|  |  |  |             and of ``q``: the pair ``(L,N)`` must appear in the following list, | 
					
						
							|  |  |  |             in compliance to section 4.2 of `FIPS 186-4`_: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             - (1024, 160) *legacy only; do not create new signatures with this* | 
					
						
							|  |  |  |             - (2048, 224) *deprecated; do not create new signatures with this* | 
					
						
							|  |  |  |             - (2048, 256) | 
					
						
							|  |  |  |             - (3072, 256) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             For ECC, only keys over P-256, P-384, and P-521 are accepted. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         mode (string): | 
					
						
							|  |  |  |             The parameter can take these values: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             - ``'fips-186-3'``. The signature generation is randomized and carried out | 
					
						
							|  |  |  |               according to `FIPS 186-3`_: the nonce ``k`` is taken from the RNG. | 
					
						
							|  |  |  |             - ``'deterministic-rfc6979'``. The signature generation is not | 
					
						
							|  |  |  |               randomized. See RFC6979_. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         encoding (string): | 
					
						
							|  |  |  |             How the signature is encoded. This value determines the output of | 
					
						
							|  |  |  |             :meth:`sign` and the input to :meth:`verify`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             The following values are accepted: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             - ``'binary'`` (default), the signature is the raw concatenation | 
					
						
							|  |  |  |               of ``r`` and ``s``. It is defined in the IEEE P.1363 standard. | 
					
						
							|  |  |  |               For DSA, the size in bytes of the signature is ``N/4`` bytes | 
					
						
							|  |  |  |               (e.g. 64 for ``N=256``). | 
					
						
							|  |  |  |               For ECDSA, the signature is always twice the length of a point | 
					
						
							|  |  |  |               coordinate (e.g. 64 bytes for P-256). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             - ``'der'``, the signature is a ASN.1 DER SEQUENCE | 
					
						
							|  |  |  |               with two INTEGERs (``r`` and ``s``). It is defined in RFC3279_. | 
					
						
							|  |  |  |               The size of the signature is variable. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         randfunc (callable): | 
					
						
							|  |  |  |             A function that returns random ``bytes``, of a given length. | 
					
						
							|  |  |  |             If omitted, the internal RNG is used. | 
					
						
							|  |  |  |             Only applicable for the *'fips-186-3'* mode. | 
					
						
							| 
									
										
										
										
											2017-08-04 22:54:43 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     .. _FIPS 186-3: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf | 
					
						
							|  |  |  |     .. _FIPS 186-4: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf | 
					
						
							|  |  |  |     .. _NIST SP 800 Part 1 Rev 4: http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r4.pdf | 
					
						
							| 
									
										
										
										
											2013-08-09 21:58:51 +02:00
										 |  |  |     .. _RFC6979: http://tools.ietf.org/html/rfc6979 | 
					
						
							| 
									
										
										
										
											2020-04-18 16:34:25 +02:00
										 |  |  |     .. _RFC3279: https://tools.ietf.org/html/rfc3279#section-2.2.2 | 
					
						
							| 
									
										
										
										
											2013-07-08 22:40:07 +02:00
										 |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     # The goal of the 'mode' parameter is to avoid to | 
					
						
							|  |  |  |     # have the current version of the standard as default. | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # Over time, such version will be superseded by (for instance) | 
					
						
							|  |  |  |     # FIPS 186-4 and it will be odd to have -3 as default. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if encoding not in ('binary', 'der'): | 
					
						
							|  |  |  |         raise ValueError("Unknown encoding '%s'" % encoding) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |     if isinstance(key, EccKey): | 
					
						
							| 
									
										
										
										
											2019-03-01 22:54:31 +01:00
										 |  |  |         order = key._curve.order | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         private_key_attr = 'd' | 
					
						
							| 
									
										
										
										
											2021-01-02 00:52:11 +01:00
										 |  |  |     elif isinstance(key, DsaKey): | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         order = Integer(key.q) | 
					
						
							|  |  |  |         private_key_attr = 'x' | 
					
						
							| 
									
										
										
										
											2021-01-02 00:52:11 +01:00
										 |  |  |     else: | 
					
						
							|  |  |  |         raise ValueError("Unsupported key type " + str(type(key))) | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if key.has_private(): | 
					
						
							|  |  |  |         private_key = getattr(key, private_key_attr) | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         private_key = None | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     if mode == 'deterministic-rfc6979': | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |         return DeterministicDsaSigScheme(key, encoding, order, private_key) | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     elif mode == 'fips-186-3': | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         if isinstance(key, EccKey): | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |             return FipsEcDsaSigScheme(key, encoding, order, randfunc) | 
					
						
							| 
									
										
										
										
											2016-01-09 14:48:37 +01:00
										 |  |  |         else: | 
					
						
							| 
									
										
										
										
											2016-01-09 23:37:24 +01:00
										 |  |  |             return FipsDsaSigScheme(key, encoding, order, randfunc) | 
					
						
							| 
									
										
										
										
											2016-01-08 22:36:27 +01:00
										 |  |  |     else: | 
					
						
							|  |  |  |         raise ValueError("Unknown DSS mode '%s'" % mode) |