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
|
|
|
# ===================================================================
|
|
|
|
|
2016-01-31 23:27:55 +01:00
|
|
|
__all__ = ['new', 'DssSigScheme']
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2016-01-07 23:46:02 +01:00
|
|
|
from Crypto.Util.py3compat import bchr, b
|
|
|
|
|
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
|
2016-01-09 14:48:37 +01:00
|
|
|
from Crypto.PublicKey.ECC import _curve, EccKey
|
2013-07-17 08:21:04 +02:00
|
|
|
|
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):
|
2017-08-04 22:54:43 +02:00
|
|
|
"""Produce the DSA/ECDSA signature of a message.
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
:parameter msg_hash:
|
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.
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2013-07-17 08:21:04 +02: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),
|
|
|
|
of cryptographic strength appropriate for the DSA key.
|
|
|
|
For instance, a 3072/256 DSA key can only be used
|
|
|
|
in combination with SHA-512.
|
2017-08-04 22:54:43 +02:00
|
|
|
:type msg_hash: hash object
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
:return: The signature as a *byte string*
|
|
|
|
: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':
|
2016-01-09 14:48:37 +01:00
|
|
|
output = b("").join([long_to_bytes(x, self._order_bytes)
|
2013-07-08 22:40:07 +02:00
|
|
|
for x in sig_pair])
|
|
|
|
else:
|
|
|
|
# Dss-sig ::= SEQUENCE {
|
|
|
|
# r OCTET STRING,
|
|
|
|
# s OCTET STRING
|
|
|
|
# }
|
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
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
:parameter msg_hash:
|
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.
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2013-07-17 08:21:04 +02: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),
|
|
|
|
of cryptographic strength appropriate for the DSA key.
|
|
|
|
For instance, a 3072/256 DSA key can only be used in
|
|
|
|
combination with SHA-512.
|
2017-08-04 22:54:43 +02:00
|
|
|
:type msg_hash: hash object
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
:parameter signature:
|
|
|
|
The signature that needs to be validated
|
|
|
|
:type signature: byte string
|
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):
|
|
|
|
raise ValueError("Hash does not belong to SHS")
|
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:
|
2016-01-07 23:46:02 +01:00
|
|
|
der_seq = DerSequence().decode(signature)
|
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:
|
|
|
|
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
|
|
|
|
mask_v = bchr(1) * mhash.digest_size
|
|
|
|
# Step c
|
|
|
|
nonce_k = bchr(0) * mhash.digest_size
|
|
|
|
|
|
|
|
for int_oct in 0, 1:
|
|
|
|
# Step d/f
|
|
|
|
nonce_k = HMAC.new(nonce_k,
|
|
|
|
mask_v + bchr(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:
|
|
|
|
nonce_k = HMAC.new(nonce_k, mask_v + bchr(0),
|
|
|
|
mhash).digest()
|
|
|
|
mask_v = HMAC.new(nonce_k, mask_v, mhash).digest()
|
|
|
|
|
|
|
|
# Step h.A
|
|
|
|
mask_t = b("")
|
|
|
|
|
|
|
|
# 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,
|
|
|
|
max_exclusive=_curve.order,
|
|
|
|
randfunc=self._randfunc)
|
|
|
|
|
|
|
|
def _valid_hash(self, msg_hash):
|
|
|
|
"""Verify that SHA-[23] (256|384|512) bits are used to
|
|
|
|
match the 128-bit security of P-256"""
|
|
|
|
|
|
|
|
approved = ("2.16.840.1.101.3.4.2.1",
|
|
|
|
"2.16.840.1.101.3.4.2.2",
|
|
|
|
"2.16.840.1.101.3.4.2.3",
|
|
|
|
"2.16.840.1.101.3.4.2.8",
|
|
|
|
"2.16.840.1.101.3.4.2.9",
|
|
|
|
"2.16.840.1.101.3.4.2.10")
|
|
|
|
|
|
|
|
return msg_hash.oid in approved
|
|
|
|
|
|
|
|
|
2013-07-08 22:40:07 +02:00
|
|
|
def new(key, mode, encoding='binary', randfunc=None):
|
2017-08-04 22:54:43 +02:00
|
|
|
"""Create a signature object :class:`DSS_SigScheme` that
|
|
|
|
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
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
:parameter key:
|
|
|
|
The key to use for computing the signature (*private* keys only)
|
|
|
|
or verifying one: it must be either
|
|
|
|
:class:`Crypto.PublicKey.DSA` or :class:`Crypto.PublicKey.ECC`.
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
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`_:
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
- (1024, 160) *legacy only; do not create new signatures with this*
|
|
|
|
- (2048, 224) *deprecated; do not create new signatures with this*
|
2013-07-08 22:40:07 +02:00
|
|
|
- (2048, 256)
|
|
|
|
- (3072, 256)
|
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
For ECC, only keys over P-256 are accepted.
|
|
|
|
:type key:
|
|
|
|
a key object
|
|
|
|
|
|
|
|
:parameter mode:
|
2013-07-17 08:21:04 +02:00
|
|
|
The parameter can take these values:
|
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
- *'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_.
|
|
|
|
:type mode:
|
|
|
|
string
|
2013-07-08 22:40:07 +02:00
|
|
|
|
2017-08-04 22:54:43 +02:00
|
|
|
:parameter encoding:
|
2013-07-08 22:40:07 +02:00
|
|
|
How the signature is encoded. This value determines the output of
|
2017-08-04 22:54:43 +02:00
|
|
|
:meth:`sign` and the input to :meth:`verify`.
|
2013-07-08 22:40:07 +02:00
|
|
|
|
|
|
|
The following values are accepted:
|
|
|
|
|
2016-01-08 22:36:27 +01:00
|
|
|
- *'binary'* (default), the signature is the raw concatenation
|
2017-08-04 22:54:43 +02:00
|
|
|
of ``r`` and ``s``.
|
|
|
|
For DSA, the size in bytes of the signature is ``N/4``
|
|
|
|
(e.g. 64 bytes for ``N=256``).
|
|
|
|
For ECDSA (over P-256), the signature is always 64 bytes long.
|
|
|
|
|
|
|
|
- *'der'*, the signature is an ASN.1 SEQUENCE with two
|
|
|
|
INTEGERs (``r`` and ``s``) encoded with DER.
|
|
|
|
The size of the signature is variable.
|
|
|
|
:type encoding: string
|
|
|
|
|
|
|
|
:parameter randfunc:
|
|
|
|
A function that returns random *byte strings*, of a given length.
|
|
|
|
If omitted, the internal RNG is used.
|
|
|
|
Only applicable for the *'fips-186-3'* mode.
|
|
|
|
:type randfunc: callable
|
|
|
|
|
|
|
|
.. _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
|
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):
|
|
|
|
order = _curve.order
|
|
|
|
private_key_attr = 'd'
|
|
|
|
else:
|
|
|
|
order = Integer(key.q)
|
|
|
|
private_key_attr = 'x'
|
|
|
|
|
|
|
|
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)
|