DSA¶
DSA is a widespread public key signature algorithm. Its security is based on the discrete logarithm problem (DLP). Given a cyclic group, a generator g, and an element h, it is hard to find an integer x such that \(g^x = h\). The problem is believed to be difficult, and it has been proved such (and therefore secure) for more than 30 years.
The group is actually a sub-group over the integers modulo p, with p prime. The sub-group order is q, which is prime too; it always holds that (p-1) is a multiple of q. The cryptographic strength is linked to the magnitude of p and q. The signer holds a value x (0<x<q-1) as private key, and its public key (y where \(y=g^x \text{ mod } p\)) is distributed.
In 2017, a sufficient size is deemed to be 2048 bits for p and 256 bits for q. For more information, see the most recent ECRYPT report.
The algorithm can only be used for authentication (digital signature). DSA cannot be used for confidentiality (encryption).
The values (p,q,g) are called domain parameters; they are not sensitive but must be shared by both parties (the signer and the verifier). Different signers can share the same domain parameters with no security concerns.
The DSA signature is twice as big as the size of q (64 bytes if q is 256 bit long).
This module provides facilities for generating new DSA keys and for constructing them from known components.
As an example, this is how you generate a new DSA key pair, save the public
key in a file called public_key.pem, sign a message (with
Crypto.Signature.DSS), and verify it:
>>> from Crypto.PublicKey import DSA
>>> from Crypto.Signature import DSS
>>> from Crypto.Hash import SHA256
>>>
>>> # Create a new DSA key
>>> key = DSA.generate(2048)
>>> f = open("public_key.pem", "w")
>>> f.write(key.publickey().export_key())
>>> f.close()
>>>
>>> # Sign a message
>>> message = b"Hello"
>>> hash_obj = SHA256.new(message)
>>> signer = DSS.new(key, 'fips-186-3')
>>> signature = signer.sign(hash_obj)
>>>
>>> # Load the public key
>>> f = open("public_key.pem", "r")
>>> hash_obj = SHA256.new(message)
>>> pub_key = DSA.import_key(f.read())
>>> verifier = DSS.new(pub_key, 'fips-186-3')
>>>
>>> # Verify the authenticity of the message
>>> try:
... verifier.verify(hash_obj, signature)
... print("The message is authentic.")
... except ValueError:
... print("The message is not authentic.")
- class Crypto.PublicKey.DSA.DsaKey(key_dict)¶
Class defining an actual DSA key. Do not instantiate directly. Use
generate(),construct()orimport_key()instead.- Variables:
p (integer) – DSA modulus
q (integer) – Order of the subgroup
g (integer) – Generator
y (integer) – Public key
x (integer) – Private key
- Undocumented:
exportKey, publickey
- exportKey(format='PEM', pkcs8=None, passphrase=None, protection=None, randfunc=None, prot_params=None)¶
Export this DSA key.
- Parameters:
format (string) –
The encoding for the output:
passphrase (string) – Private keys only. The pass phrase to protect the output.
pkcs8 (boolean) – Private keys only. If
True(default), the key is encoded with PKCS#8. IfFalse, it is encoded in the custom OpenSSL/OpenSSH container.protection (string) –
Only in combination with a pass phrase. The encryption scheme to use to protect the output.
If
pkcs8takes valueTrue, this is the PKCS#8 algorithm to use for deriving the secret and encrypting the private DSA key. The default is'PBKDF2WithHMAC-SHA256AndAES256-CBC'. For a complete list of algorithms, see the encryption parameters of PKCS#8.If
pkcs8isFalse, the obsolete PEM encryption scheme is used, andprotectionis not allowed. It derives the key with a single round of MD5, and is therefore easy to brute force: use it only with a high-entropy passphrase (like 16 random bytes), for compatibility with old software.The combination
format='DER'andpkcs8=Falseis not allowed if a passphrase is present.randfunc (callable) – A function that returns random bytes. By default it is
Crypto.Random.get_random_bytes().prot_params (dict) – Only with PKCS#8 and a pass phrase. The parameters to use to derive the encryption key from the passphrase. For all possible values, refer to the encryption parameters of PKCS#8.
- Returns:
the encoded key
- Return type:
byte string
- Raises:
ValueError – when the format is unknown, when you try to encrypt a private key with DER format and OpenSSL/OpenSSH, when you pass
protectionorprot_paramswithpkcs8=Falseor without a passphrase, or when the passphrase is empty.
Warning
If you don’t provide a pass phrase, the private key will be exported in the clear!
- export_key(format='PEM', pkcs8=None, passphrase=None, protection=None, randfunc=None, prot_params=None)¶
Export this DSA key.
- Parameters:
format (string) –
The encoding for the output:
passphrase (string) – Private keys only. The pass phrase to protect the output.
pkcs8 (boolean) – Private keys only. If
True(default), the key is encoded with PKCS#8. IfFalse, it is encoded in the custom OpenSSL/OpenSSH container.protection (string) –
Only in combination with a pass phrase. The encryption scheme to use to protect the output.
If
pkcs8takes valueTrue, this is the PKCS#8 algorithm to use for deriving the secret and encrypting the private DSA key. The default is'PBKDF2WithHMAC-SHA256AndAES256-CBC'. For a complete list of algorithms, see the encryption parameters of PKCS#8.If
pkcs8isFalse, the obsolete PEM encryption scheme is used, andprotectionis not allowed. It derives the key with a single round of MD5, and is therefore easy to brute force: use it only with a high-entropy passphrase (like 16 random bytes), for compatibility with old software.The combination
format='DER'andpkcs8=Falseis not allowed if a passphrase is present.randfunc (callable) – A function that returns random bytes. By default it is
Crypto.Random.get_random_bytes().prot_params (dict) – Only with PKCS#8 and a pass phrase. The parameters to use to derive the encryption key from the passphrase. For all possible values, refer to the encryption parameters of PKCS#8.
- Returns:
the encoded key
- Return type:
byte string
- Raises:
ValueError – when the format is unknown, when you try to encrypt a private key with DER format and OpenSSL/OpenSSH, when you pass
protectionorprot_paramswithpkcs8=Falseor without a passphrase, or when the passphrase is empty.
Warning
If you don’t provide a pass phrase, the private key will be exported in the clear!
- Crypto.PublicKey.DSA.construct(tup, consistency_check=True)¶
Construct a DSA key from a tuple of valid DSA components.
- Parameters:
tup (tuple) –
A tuple of long integers, with 4 or 5 items in the following order:
Public key (y).
Sub-group generator (g).
Modulus, finite field order (p).
Sub-group order (q).
Private key (x). Optional.
consistency_check (boolean) – If
True, the library will verify that the provided components fulfil the main DSA properties.
- Raises:
ValueError – when the key being imported fails the most basic DSA validity checks.
- Returns:
a DSA key object
- Return type:
- Crypto.PublicKey.DSA.generate(bits, randfunc=None, domain=None)¶
Generate a new DSA key pair.
The algorithm follows Appendix A.1/A.2 and B.1 of FIPS 186-4, respectively for domain generation and key pair generation.
- Parameters:
bits (integer) – Key length, or size (in bits) of the DSA modulus p. It must be 1024, 2048 or 3072.
randfunc (callable) – Random number generation function; it accepts a single integer N and return a string of random data N bytes long. If not specified,
Crypto.Random.get_random_bytes()is used.domain (tuple) – The DSA domain parameters p, q and g as a list of 3 integers. Size of p and q must comply to FIPS 186-4. If not specified, the parameters are created anew.
- Returns:
a new DSA key object
- Return type:
- Raises:
ValueError – when bits is too little, too big, or not a multiple of 64.
- Crypto.PublicKey.DSA.import_key(extern_key, passphrase=None, *, max_iteration_count=None, threads=1, max_memory=None)¶
Import a DSA key.
- Parameters:
extern_key (string or byte string) –
The DSA key to import.
The following formats are supported for a DSA public key:
X.509 certificate (binary DER or PEM)
X.509
subjectPublicKeyInfo(binary DER or PEM)OpenSSH (ASCII one-liner, see RFC4253)
The following formats are supported for a DSA private key:
PKCS#8
PrivateKeyInfoorEncryptedPrivateKeyInfoDER SEQUENCE (binary or PEM)OpenSSL/OpenSSH custom format (binary or PEM)
passphrase (string) –
In case of an encrypted private key, this is the pass phrase from which the decryption key is derived.
Encryption may be applied either at the PKCS#8 or at the PEM level.
max_iteration_count (integer) – The maximum value allowed for the PBKDF2 iteration count or the scrypt cost N·r·p/8 (that is, N for the usual r=8 and p=1) of a PKCS#8 encrypted key. A malicious key could require an extremely high number of iterations, tying up the CPU for hours. The default value is None: a limit for each KDF, which keeps the key derivation to about one minute at most (see the limits for decryption). Set it to
0to disable the check.threads (integer) – The maximum number of threads used to derive the decryption key with scrypt (default: 1, no extra threads; 0 for all CPU cores). Only a PKCS#8 key protected with scrypt and a parallelization parameter larger than 1 can use them.
max_memory (integer) – The maximum memory (in bytes) for the key derivation of a PKCS#8 encrypted key, as a limit on the total of all threads together (not on each thread). Only scrypt uses a significant amount: 128 · (N + 2) · r bytes for each thread, plus 256 · r · p bytes for all the flows together. If the requested threads do not fit, fewer are used (down to one); if a single thread does not fit, the key is rejected. The default value is None (a limit of 256 MiB). Set it to
0to disable the check.
- Returns:
a DSA key object
- Return type:
- Raises:
PassphraseRequiredError – (a
ValueError) when the private key is encrypted, but no passphrase was provided.IncorrectPassphraseError – (a
ValueError) when the private key cannot be decrypted with the passphrase (most likely, the passphrase is wrong).ValueError – when the given key cannot be parsed.