diff options
| author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-06-22 18:06:28 -0600 |
|---|---|---|
| committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2014-06-25 08:25:52 -0600 |
| commit | 0197ed8dedcd24d3b690d1b76eb6866df14f56dd (patch) | |
| tree | c773e0eb29ba4d16b5ce8dd1422dbff000711175 /cryptography | |
| parent | 42ee73b26e18fc9a03badd885a8a3847f3907cad (diff) | |
| download | cryptography-0197ed8dedcd24d3b690d1b76eb6866df14f56dd.tar.gz cryptography-0197ed8dedcd24d3b690d1b76eb6866df14f56dd.tar.bz2 cryptography-0197ed8dedcd24d3b690d1b76eb6866df14f56dd.zip | |
DSA opaque OpenSSL
Diffstat (limited to 'cryptography')
| -rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 90 | ||||
| -rw-r--r-- | cryptography/hazmat/backends/openssl/dsa.py | 121 | ||||
| -rw-r--r-- | cryptography/hazmat/primitives/asymmetric/dsa.py | 78 |
3 files changed, 233 insertions, 56 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index d08cd3e4..e895da83 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -32,6 +32,7 @@ from cryptography.hazmat.backends.openssl.ciphers import ( _AESCTRCipherContext, _CipherContext ) from cryptography.hazmat.backends.openssl.dsa import ( + _DSAParameters, _DSAPrivateKey, _DSAPublicKey, _DSASignatureContext, _DSAVerificationContext ) from cryptography.hazmat.backends.openssl.ec import ( @@ -467,19 +468,10 @@ class Backend(object): dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) assert dsa_cdata != self._ffi.NULL dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) - return self._dsa_cdata_to_private_key(dsa_cdata) + return _DSAPrivateKey(self, dsa_cdata) else: raise UnsupportedAlgorithm("Unsupported key type.") - def _dsa_cdata_to_private_key(self, cdata): - return dsa.DSAPrivateKey( - modulus=self._bn_to_int(cdata.p), - subgroup_order=self._bn_to_int(cdata.q), - generator=self._bn_to_int(cdata.g), - x=self._bn_to_int(cdata.priv_key), - y=self._bn_to_int(cdata.pub_key) - ) - def _pem_password_cb(self, password): """ Generate a pem_password_cb function pointer that copied the password to @@ -615,37 +607,79 @@ class Backend(object): assert res == 1 - return dsa.DSAParameters( - modulus=self._bn_to_int(ctx.p), - subgroup_order=self._bn_to_int(ctx.q), - generator=self._bn_to_int(ctx.g) - ) + return _DSAParameters(self, ctx) def generate_dsa_private_key(self, parameters): ctx = self._lib.DSA_new() assert ctx != self._ffi.NULL ctx = self._ffi.gc(ctx, self._lib.DSA_free) - ctx.p = self._int_to_bn(parameters.p) - ctx.q = self._int_to_bn(parameters.q) - ctx.g = self._int_to_bn(parameters.g) + if isinstance(parameters, dsa.DSAParameters): + ctx.p = self._int_to_bn(parameters.p) + ctx.q = self._int_to_bn(parameters.q) + ctx.g = self._int_to_bn(parameters.g) + else: + ctx.p = self._lib.BN_dup(parameters._dsa_cdata.p) + ctx.q = self._lib.BN_dup(parameters._dsa_cdata.q) + ctx.g = self._lib.BN_dup(parameters._dsa_cdata.g) self._lib.DSA_generate_key(ctx) - return dsa.DSAPrivateKey( - modulus=self._bn_to_int(ctx.p), - subgroup_order=self._bn_to_int(ctx.q), - generator=self._bn_to_int(ctx.g), - x=self._bn_to_int(ctx.priv_key), - y=self._bn_to_int(ctx.pub_key) - ) + return _DSAPrivateKey(self, ctx) def create_dsa_signature_ctx(self, private_key, algorithm): - return _DSASignatureContext(self, private_key, algorithm) + dsa_cdata = self._dsa_cdata_from_private_key(private_key) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + key = _DSAPrivateKey(self, dsa_cdata) + return _DSASignatureContext(self, key, algorithm) def create_dsa_verification_ctx(self, public_key, signature, algorithm): - return _DSAVerificationContext(self, public_key, signature, - algorithm) + dsa_cdata = self._dsa_cdata_from_public_key(public_key) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + key = _DSAPublicKey(self, dsa_cdata) + return _DSAVerificationContext(self, key, signature, algorithm) + + def load_dsa_private_numbers(self, numbers): + parameter_numbers = numbers.public_numbers.parameter_numbers + dsa._check_dsa_parameters(parameter_numbers) + dsa_cdata = self._lib.DSA_new() + assert dsa_cdata != self._ffi.NULL + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + dsa_cdata.p = self._int_to_bn(parameter_numbers.p) + dsa_cdata.q = self._int_to_bn(parameter_numbers.q) + dsa_cdata.g = self._int_to_bn(parameter_numbers.g) + dsa_cdata.pub_key = self._int_to_bn(numbers.public_numbers.y) + dsa_cdata.priv_key = self._int_to_bn(numbers.x) + + return _DSAPrivateKey(self, dsa_cdata) + + def load_dsa_public_numbers(self, numbers): + dsa._check_dsa_parameters(numbers.parameter_numbers) + # TODO check more + dsa_cdata = self._lib.DSA_new() + assert dsa_cdata != self._ffi.NULL + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + dsa_cdata.p = self._int_to_bn(numbers.parameter_numbers.p) + dsa_cdata.q = self._int_to_bn(numbers.parameter_numbers.q) + dsa_cdata.g = self._int_to_bn(numbers.parameter_numbers.g) + dsa_cdata.pub_key = self._int_to_bn(numbers.y) + + return _DSAPublicKey(self, dsa_cdata) + + def load_dsa_parameter_numbers(self, numbers): + dsa._check_dsa_parameters(numbers) + # TODO check more + dsa_cdata = self._lib.DSA_new() + assert dsa_cdata != self._ffi.NULL + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + dsa_cdata.p = self._int_to_bn(numbers.p) + dsa_cdata.q = self._int_to_bn(numbers.q) + dsa_cdata.g = self._int_to_bn(numbers.g) + + return _DSAParameters(self, dsa_cdata) def _dsa_cdata_from_public_key(self, public_key): # Does not GC the DSA cdata. You *must* make sure it's freed diff --git a/cryptography/hazmat/backends/openssl/dsa.py b/cryptography/hazmat/backends/openssl/dsa.py index ec05c3aa..d492372f 100644 --- a/cryptography/hazmat/backends/openssl/dsa.py +++ b/cryptography/hazmat/backends/openssl/dsa.py @@ -16,6 +16,10 @@ from __future__ import absolute_import, division, print_function from cryptography import utils from cryptography.exceptions import InvalidSignature from cryptography.hazmat.primitives import hashes, interfaces +from cryptography.hazmat.primitives.asymmetric import dsa +from cryptography.hazmat.primitives.interfaces import ( + DSAParametersWithNumbers, DSAPrivateKeyWithNumbers, DSAPublicKeyWithNumbers +) @utils.register_interface(interfaces.AsymmetricVerificationContext) @@ -32,9 +36,7 @@ class _DSAVerificationContext(object): self._hash_ctx.update(data) def verify(self): - self._dsa_cdata = self._backend._dsa_cdata_from_public_key( - self._public_key) - self._dsa_cdata = self._backend._ffi.gc(self._dsa_cdata, + self._dsa_cdata = self._backend._ffi.gc(self._public_key._dsa_cdata, self._backend._lib.DSA_free) data_to_verify = self._hash_ctx.finalize() @@ -43,7 +45,7 @@ class _DSAVerificationContext(object): # must be an integer. res = self._backend._lib.DSA_verify( 0, data_to_verify, len(data_to_verify), self._signature, - len(self._signature), self._dsa_cdata) + len(self._signature), self._public_key._dsa_cdata) if res != 1: errors = self._backend._consume_errors() @@ -61,17 +63,13 @@ class _DSASignatureContext(object): self._private_key = private_key self._algorithm = algorithm self._hash_ctx = hashes.Hash(self._algorithm, self._backend) - self._dsa_cdata = self._backend._dsa_cdata_from_private_key( - self._private_key) - self._dsa_cdata = self._backend._ffi.gc(self._dsa_cdata, - self._backend._lib.DSA_free) def update(self, data): self._hash_ctx.update(data) def finalize(self): data_to_sign = self._hash_ctx.finalize() - sig_buf_len = self._backend._lib.DSA_size(self._dsa_cdata) + sig_buf_len = self._backend._lib.DSA_size(self._private_key._dsa_cdata) sig_buf = self._backend._ffi.new("unsigned char[]", sig_buf_len) buflen = self._backend._ffi.new("unsigned int *") @@ -79,8 +77,111 @@ class _DSASignatureContext(object): # must be an integer. res = self._backend._lib.DSA_sign( 0, data_to_sign, len(data_to_sign), sig_buf, - buflen, self._dsa_cdata) + buflen, self._private_key._dsa_cdata) assert res == 1 assert buflen[0] return self._backend._ffi.buffer(sig_buf)[:buflen[0]] + + +@utils.register_interface(DSAParametersWithNumbers) +class _DSAParameters(object): + def __init__(self, backend, dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + + def parameter_numbers(self): + return dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(self._dsa_cdata.p), + q=self._backend._bn_to_int(self._dsa_cdata.q), + g=self._backend._bn_to_int(self._dsa_cdata.g) + ) + + +@utils.register_interface(DSAPrivateKeyWithNumbers) +class _DSAPrivateKey(object): + def __init__(self, backend, dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p) + + @property + def key_size(self): + return self._key_size + + def signer(self, algorithm): + return _DSASignatureContext(self._backend, self, algorithm) + + def private_numbers(self): + return dsa.DSAPrivateNumbers( + public_numbers=dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(self._dsa_cdata.p), + q=self._backend._bn_to_int(self._dsa_cdata.q), + g=self._backend._bn_to_int(self._dsa_cdata.g) + ), + y=self._backend._bn_to_int(self._dsa_cdata.pub_key) + ), + x=self._backend._bn_to_int(self._dsa_cdata.priv_key) + ) + + def public_key(self): + dsa_cdata = self._backend._lib.DSA_new() + assert dsa_cdata != self._backend._ffi.NULL + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + dsa_cdata.p = self._backend._lib.BN_dup(self._dsa_cdata.p) + dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q) + dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) + dsa_cdata.pub_key = self._backend._lib.BN_dup(self._dsa_cdata.pub_key) + return _DSAPublicKey(self._backend, dsa_cdata) + + def parameters(self): + dsa_cdata = self._backend._lib.DSA_new() + assert dsa_cdata != self._backend._ffi.NULL + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + dsa_cdata.p = self._backend._lib.BN_dup(self._dsa_cdata.p) + dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q) + dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) + return _DSAParameters(self._backend, dsa_cdata) + + +@utils.register_interface(DSAPublicKeyWithNumbers) +class _DSAPublicKey(object): + def __init__(self, backend, dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p) + + @property + def key_size(self): + return self._key_size + + def verifier(self, signature, algorithm): + return _DSAVerificationContext( + self._backend, self, signature, algorithm + ) + + def public_numbers(self): + return dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(self._dsa_cdata.p), + q=self._backend._bn_to_int(self._dsa_cdata.q), + g=self._backend._bn_to_int(self._dsa_cdata.g) + ), + y=self._backend._bn_to_int(self._dsa_cdata.pub_key) + ) + + def parameters(self): + dsa_cdata = self._backend._lib.DSA_new() + assert dsa_cdata != self._backend._ffi.NULL + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + dsa_cdata.p = self._backend._lib.BN_dup(self._dsa_cdata.p) + dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q) + dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) + return _DSAParameters(self._backend, dsa_cdata) diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py index 4d78679e..4675bd0a 100644 --- a/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -21,31 +21,38 @@ from cryptography.hazmat.backends.interfaces import DSABackend from cryptography.hazmat.primitives import interfaces -def _check_dsa_parameters(modulus, subgroup_order, generator): - if ( - not isinstance(modulus, six.integer_types) or - not isinstance(subgroup_order, six.integer_types) or - not isinstance(generator, six.integer_types) - ): - raise TypeError("DSA parameters must be integers.") - - if (utils.bit_length(modulus), - utils.bit_length(subgroup_order)) not in ( +def generate_parameters(key_size, backend): + return backend.generate_dsa_parameters(key_size) + + +def generate_private_key(parameters): + return parameters._backend.generate_dsa_private_key(parameters) + + +def _check_dsa_parameters(parameters): + if (utils.bit_length(parameters.p), + utils.bit_length(parameters.q)) not in ( (1024, 160), (2048, 256), (3072, 256)): - raise ValueError("modulus and subgroup_order lengths must be " + raise ValueError("p and q lengths must be " "one of these pairs (1024, 160) or (2048, 256) " "or (3072, 256).") - if generator <= 1 or generator >= modulus: - raise ValueError("generator must be > 1 and < modulus.") + if parameters.g <= 1 or parameters.g >= parameters.p: + raise ValueError("g must be > 1 and < p.") @utils.register_interface(interfaces.DSAParameters) class DSAParameters(object): def __init__(self, modulus, subgroup_order, generator): - _check_dsa_parameters(modulus, subgroup_order, generator) + _check_dsa_parameters( + DSAParameterNumbers( + p=modulus, + q=subgroup_order, + g=generator + ) + ) self._modulus = modulus self._subgroup_order = subgroup_order @@ -59,7 +66,13 @@ class DSAParameters(object): _Reasons.BACKEND_MISSING_INTERFACE ) - return backend.generate_dsa_parameters(key_size) + parameters = backend.generate_dsa_parameters(key_size) + numbers = parameters.parameter_numbers() + return cls( + modulus=numbers.p, + subgroup_order=numbers.q, + generator=numbers.g + ) @property def modulus(self): @@ -89,7 +102,13 @@ class DSAParameters(object): @utils.register_interface(interfaces.DSAPrivateKey) class DSAPrivateKey(object): def __init__(self, modulus, subgroup_order, generator, x, y): - _check_dsa_parameters(modulus, subgroup_order, generator) + _check_dsa_parameters( + DSAParameterNumbers( + p=modulus, + q=subgroup_order, + g=generator + ) + ) if ( not isinstance(x, six.integer_types) or not isinstance(y, six.integer_types) @@ -116,7 +135,15 @@ class DSAPrivateKey(object): _Reasons.BACKEND_MISSING_INTERFACE ) - return backend.generate_dsa_private_key(parameters) + key = backend.generate_dsa_private_key(parameters) + private_numbers = key.private_numbers() + return cls( + modulus=private_numbers.public_numbers.parameter_numbers.p, + subgroup_order=private_numbers.public_numbers.parameter_numbers.q, + generator=private_numbers.public_numbers.parameter_numbers.g, + x=private_numbers.x, + y=private_numbers.public_numbers.y + ) def signer(self, algorithm, backend): if not isinstance(backend, DSABackend): @@ -151,7 +178,13 @@ class DSAPrivateKey(object): @utils.register_interface(interfaces.DSAPublicKey) class DSAPublicKey(object): def __init__(self, modulus, subgroup_order, generator, y): - _check_dsa_parameters(modulus, subgroup_order, generator) + _check_dsa_parameters( + DSAParameterNumbers( + p=modulus, + q=subgroup_order, + g=generator + ) + ) if not isinstance(y, six.integer_types): raise TypeError("y must be an integer.") @@ -210,6 +243,9 @@ class DSAParameterNumbers(object): def g(self): return self._g + def parameters(self, backend): + return backend.load_dsa_parameter_numbers(self) + class DSAPublicNumbers(object): def __init__(self, y, parameter_numbers): @@ -232,6 +268,9 @@ class DSAPublicNumbers(object): def parameter_numbers(self): return self._parameter_numbers + def public_key(self, backend): + return backend.load_dsa_public_numbers(self) + class DSAPrivateNumbers(object): def __init__(self, x, public_numbers): @@ -252,3 +291,6 @@ class DSAPrivateNumbers(object): @property def public_numbers(self): return self._public_numbers + + def private_key(self, backend): + return backend.load_dsa_private_numbers(self) |
