update Linux i686
This commit is contained in:
parent
7f55398eed
commit
89ee84c73e
1390 changed files with 4932 additions and 433509 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -22,10 +22,10 @@ __summary__ = ("cryptography is a package which provides cryptographic recipes"
|
|||
" and primitives to Python developers.")
|
||||
__uri__ = "https://github.com/pyca/cryptography"
|
||||
|
||||
__version__ = "0.4"
|
||||
__version__ = "0.5.4"
|
||||
|
||||
__author__ = "The cryptography developers"
|
||||
__email__ = "cryptography-dev@python.org"
|
||||
|
||||
__license__ = "Apache License, Version 2.0"
|
||||
__copyright__ = "Copyright 2013-2014 %s" % __author__
|
||||
__copyright__ = "Copyright 2013-2014 {0}".format(__author__)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ class _Reasons(object):
|
|||
UNSUPPORTED_PADDING = object()
|
||||
UNSUPPORTED_MGF = object()
|
||||
UNSUPPORTED_PUBLIC_KEY_ALGORITHM = object()
|
||||
UNSUPPORTED_ELLIPTIC_CURVE = object()
|
||||
UNSUPPORTED_SERIALIZATION = object()
|
||||
|
||||
|
||||
class UnsupportedAlgorithm(Exception):
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class Fernet(object):
|
|||
key = base64.urlsafe_b64decode(key)
|
||||
if len(key) != 32:
|
||||
raise ValueError(
|
||||
"Fernet key must be 32 url-safe base64-encoded bytes"
|
||||
"Fernet key must be 32 url-safe base64-encoded bytes."
|
||||
)
|
||||
|
||||
self._signing_key = key[:16]
|
||||
|
|
@ -60,10 +60,8 @@ class Fernet(object):
|
|||
return self._encrypt_from_parts(data, current_time, iv)
|
||||
|
||||
def _encrypt_from_parts(self, data, current_time, iv):
|
||||
if isinstance(data, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before encryption"
|
||||
)
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("data must be bytes.")
|
||||
|
||||
padder = padding.PKCS7(algorithms.AES.block_size).padder()
|
||||
padded_data = padder.update(data) + padder.finalize()
|
||||
|
|
@ -82,10 +80,8 @@ class Fernet(object):
|
|||
return base64.urlsafe_b64encode(basic_parts + hmac)
|
||||
|
||||
def decrypt(self, token, ttl=None):
|
||||
if isinstance(token, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before decryption"
|
||||
)
|
||||
if not isinstance(token, bytes):
|
||||
raise TypeError("token must be bytes.")
|
||||
|
||||
current_time = int(time.time())
|
||||
|
||||
|
|
|
|||
|
|
@ -16,19 +16,21 @@ from __future__ import absolute_import, division, print_function
|
|||
from collections import namedtuple
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
InternalError, InvalidTag, UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.exceptions import InternalError
|
||||
from cryptography.hazmat.backends.commoncrypto.ciphers import (
|
||||
_CipherContext, _GCMCipherContext
|
||||
)
|
||||
from cryptography.hazmat.backends.commoncrypto.hashes import _HashContext
|
||||
from cryptography.hazmat.backends.commoncrypto.hmac import _HMACContext
|
||||
from cryptography.hazmat.backends.interfaces import (
|
||||
CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend
|
||||
)
|
||||
from cryptography.hazmat.bindings.commoncrypto.binding import Binding
|
||||
from cryptography.hazmat.primitives import constant_time, interfaces
|
||||
from cryptography.hazmat.primitives.ciphers.algorithms import (
|
||||
AES, ARC4, Blowfish, CAST5, TripleDES
|
||||
)
|
||||
from cryptography.hazmat.primitives.ciphers.modes import (
|
||||
CBC, CFB, CTR, ECB, GCM, OFB
|
||||
CBC, CFB, CFB8, CTR, ECB, GCM, OFB
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -147,14 +149,14 @@ class Backend(object):
|
|||
buf,
|
||||
length
|
||||
)
|
||||
self._check_response(res)
|
||||
self._check_cipher_response(res)
|
||||
|
||||
return self._ffi.buffer(buf)[:]
|
||||
|
||||
def _register_cipher_adapter(self, cipher_cls, cipher_const, mode_cls,
|
||||
mode_const):
|
||||
if (cipher_cls, mode_cls) in self._cipher_registry:
|
||||
raise ValueError("Duplicate registration for: {0} {1}".format(
|
||||
raise ValueError("Duplicate registration for: {0} {1}.".format(
|
||||
cipher_cls, mode_cls)
|
||||
)
|
||||
self._cipher_registry[cipher_cls, mode_cls] = (cipher_const,
|
||||
|
|
@ -165,6 +167,7 @@ class Backend(object):
|
|||
(CBC, self._lib.kCCModeCBC),
|
||||
(ECB, self._lib.kCCModeECB),
|
||||
(CFB, self._lib.kCCModeCFB),
|
||||
(CFB8, self._lib.kCCModeCFB8),
|
||||
(OFB, self._lib.kCCModeOFB),
|
||||
(CTR, self._lib.kCCModeCTR),
|
||||
(GCM, self._lib.kCCModeGCM),
|
||||
|
|
@ -177,7 +180,9 @@ class Backend(object):
|
|||
)
|
||||
for mode_cls, mode_const in [
|
||||
(CBC, self._lib.kCCModeCBC),
|
||||
(ECB, self._lib.kCCModeECB),
|
||||
(CFB, self._lib.kCCModeCFB),
|
||||
(CFB8, self._lib.kCCModeCFB8),
|
||||
(OFB, self._lib.kCCModeOFB),
|
||||
]:
|
||||
self._register_cipher_adapter(
|
||||
|
|
@ -218,7 +223,7 @@ class Backend(object):
|
|||
self._lib.kCCModeRC4
|
||||
)
|
||||
|
||||
def _check_response(self, response):
|
||||
def _check_cipher_response(self, response):
|
||||
if response == self._lib.kCCSuccess:
|
||||
return
|
||||
elif response == self._lib.kCCAlignmentError:
|
||||
|
|
@ -226,7 +231,7 @@ class Backend(object):
|
|||
# rdar://15589470
|
||||
raise ValueError(
|
||||
"The length of the provided data is not a multiple of "
|
||||
"the block length"
|
||||
"the block length."
|
||||
)
|
||||
else:
|
||||
raise InternalError(
|
||||
|
|
@ -234,266 +239,15 @@ class Backend(object):
|
|||
" Code: {0}.".format(response)
|
||||
)
|
||||
|
||||
|
||||
def _release_cipher_ctx(ctx):
|
||||
"""
|
||||
Called by the garbage collector and used to safely dereference and
|
||||
release the context.
|
||||
"""
|
||||
if ctx[0] != backend._ffi.NULL:
|
||||
res = backend._lib.CCCryptorRelease(ctx[0])
|
||||
backend._check_response(res)
|
||||
ctx[0] = backend._ffi.NULL
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.CipherContext)
|
||||
class _CipherContext(object):
|
||||
def __init__(self, backend, cipher, mode, operation):
|
||||
self._backend = backend
|
||||
self._cipher = cipher
|
||||
self._mode = mode
|
||||
self._operation = operation
|
||||
# There is a bug in CommonCrypto where block ciphers do not raise
|
||||
# kCCAlignmentError when finalizing if you supply non-block aligned
|
||||
# data. To work around this we need to keep track of the block
|
||||
# alignment ourselves, but only for alg+mode combos that require
|
||||
# block alignment. OFB, CFB, and CTR make a block cipher algorithm
|
||||
# into a stream cipher so we don't need to track them (and thus their
|
||||
# block size is effectively 1 byte just like OpenSSL/CommonCrypto
|
||||
# treat RC4 and other stream cipher block sizes).
|
||||
# This bug has been filed as rdar://15589470
|
||||
self._bytes_processed = 0
|
||||
if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not
|
||||
isinstance(mode, (OFB, CFB, CTR))):
|
||||
self._byte_block_size = cipher.block_size // 8
|
||||
else:
|
||||
self._byte_block_size = 1
|
||||
|
||||
registry = self._backend._cipher_registry
|
||||
try:
|
||||
cipher_enum, mode_enum = registry[type(cipher), type(mode)]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported "
|
||||
"by this backend".format(
|
||||
cipher.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
||||
ctx = self._backend._ffi.new("CCCryptorRef *")
|
||||
ctx = self._backend._ffi.gc(ctx, _release_cipher_ctx)
|
||||
|
||||
if isinstance(mode, interfaces.ModeWithInitializationVector):
|
||||
iv_nonce = mode.initialization_vector
|
||||
elif isinstance(mode, interfaces.ModeWithNonce):
|
||||
iv_nonce = mode.nonce
|
||||
else:
|
||||
iv_nonce = self._backend._ffi.NULL
|
||||
|
||||
if isinstance(mode, CTR):
|
||||
mode_option = self._backend._lib.kCCModeOptionCTR_BE
|
||||
else:
|
||||
mode_option = 0
|
||||
|
||||
res = self._backend._lib.CCCryptorCreateWithMode(
|
||||
operation,
|
||||
mode_enum, cipher_enum,
|
||||
self._backend._lib.ccNoPadding, iv_nonce,
|
||||
cipher.key, len(cipher.key),
|
||||
self._backend._ffi.NULL, 0, 0, mode_option, ctx)
|
||||
self._backend._check_response(res)
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
def update(self, data):
|
||||
# Count bytes processed to handle block alignment.
|
||||
self._bytes_processed += len(data)
|
||||
buf = self._backend._ffi.new(
|
||||
"unsigned char[]", len(data) + self._byte_block_size - 1)
|
||||
outlen = self._backend._ffi.new("size_t *")
|
||||
res = self._backend._lib.CCCryptorUpdate(
|
||||
self._ctx[0], data, len(data), buf,
|
||||
len(data) + self._byte_block_size - 1, outlen)
|
||||
self._backend._check_response(res)
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
def finalize(self):
|
||||
# Raise error if block alignment is wrong.
|
||||
if self._bytes_processed % self._byte_block_size:
|
||||
raise ValueError(
|
||||
"The length of the provided data is not a multiple of "
|
||||
"the block length"
|
||||
)
|
||||
buf = self._backend._ffi.new("unsigned char[]", self._byte_block_size)
|
||||
outlen = self._backend._ffi.new("size_t *")
|
||||
res = self._backend._lib.CCCryptorFinal(
|
||||
self._ctx[0], buf, len(buf), outlen)
|
||||
self._backend._check_response(res)
|
||||
_release_cipher_ctx(self._ctx)
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AEADCipherContext)
|
||||
@utils.register_interface(interfaces.AEADEncryptionContext)
|
||||
class _GCMCipherContext(object):
|
||||
def __init__(self, backend, cipher, mode, operation):
|
||||
self._backend = backend
|
||||
self._cipher = cipher
|
||||
self._mode = mode
|
||||
self._operation = operation
|
||||
self._tag = None
|
||||
|
||||
registry = self._backend._cipher_registry
|
||||
try:
|
||||
cipher_enum, mode_enum = registry[type(cipher), type(mode)]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported "
|
||||
"by this backend".format(
|
||||
cipher.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
||||
ctx = self._backend._ffi.new("CCCryptorRef *")
|
||||
ctx = self._backend._ffi.gc(ctx, _release_cipher_ctx)
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
res = self._backend._lib.CCCryptorCreateWithMode(
|
||||
operation,
|
||||
mode_enum, cipher_enum,
|
||||
self._backend._lib.ccNoPadding,
|
||||
self._backend._ffi.NULL,
|
||||
cipher.key, len(cipher.key),
|
||||
self._backend._ffi.NULL, 0, 0, 0, self._ctx)
|
||||
self._backend._check_response(res)
|
||||
|
||||
res = self._backend._lib.CCCryptorGCMAddIV(
|
||||
self._ctx[0],
|
||||
mode.initialization_vector,
|
||||
len(mode.initialization_vector)
|
||||
)
|
||||
self._backend._check_response(res)
|
||||
|
||||
def update(self, data):
|
||||
buf = self._backend._ffi.new("unsigned char[]", len(data))
|
||||
args = (self._ctx[0], data, len(data), buf)
|
||||
if self._operation == self._backend._lib.kCCEncrypt:
|
||||
res = self._backend._lib.CCCryptorGCMEncrypt(*args)
|
||||
else:
|
||||
res = self._backend._lib.CCCryptorGCMDecrypt(*args)
|
||||
|
||||
self._backend._check_response(res)
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
||||
def finalize(self):
|
||||
tag_size = self._cipher.block_size // 8
|
||||
tag_buf = self._backend._ffi.new("unsigned char[]", tag_size)
|
||||
tag_len = self._backend._ffi.new("size_t *", tag_size)
|
||||
res = backend._lib.CCCryptorGCMFinal(self._ctx[0], tag_buf, tag_len)
|
||||
self._backend._check_response(res)
|
||||
_release_cipher_ctx(self._ctx)
|
||||
self._tag = self._backend._ffi.buffer(tag_buf)[:]
|
||||
if (self._operation == self._backend._lib.kCCDecrypt and
|
||||
not constant_time.bytes_eq(
|
||||
self._tag[:len(self._mode.tag)], self._mode.tag
|
||||
)):
|
||||
raise InvalidTag
|
||||
return b""
|
||||
|
||||
def authenticate_additional_data(self, data):
|
||||
res = self._backend._lib.CCCryptorGCMAddAAD(
|
||||
self._ctx[0], data, len(data)
|
||||
)
|
||||
self._backend._check_response(res)
|
||||
|
||||
@property
|
||||
def tag(self):
|
||||
return self._tag
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.HashContext)
|
||||
class _HashContext(object):
|
||||
def __init__(self, backend, algorithm, ctx=None):
|
||||
self.algorithm = algorithm
|
||||
self._backend = backend
|
||||
|
||||
if ctx is None:
|
||||
try:
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
ctx = self._backend._ffi.new(methods.ctx)
|
||||
res = methods.hash_init(ctx)
|
||||
assert res == 1
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
def copy(self):
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
new_ctx = self._backend._ffi.new(methods.ctx)
|
||||
# CommonCrypto has no APIs for copying hashes, so we have to copy the
|
||||
# underlying struct.
|
||||
new_ctx[0] = self._ctx[0]
|
||||
|
||||
return _HashContext(self._backend, self.algorithm, ctx=new_ctx)
|
||||
|
||||
def update(self, data):
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
res = methods.hash_update(self._ctx, data, len(data))
|
||||
assert res == 1
|
||||
|
||||
def finalize(self):
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
self.algorithm.digest_size)
|
||||
res = methods.hash_final(buf, self._ctx)
|
||||
assert res == 1
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.HashContext)
|
||||
class _HMACContext(object):
|
||||
def __init__(self, backend, key, algorithm, ctx=None):
|
||||
self.algorithm = algorithm
|
||||
self._backend = backend
|
||||
if ctx is None:
|
||||
ctx = self._backend._ffi.new("CCHmacContext *")
|
||||
try:
|
||||
alg = self._backend._supported_hmac_algorithms[algorithm.name]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported HMAC hash on this backend".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
||||
self._backend._lib.CCHmacInit(ctx, alg, key, len(key))
|
||||
|
||||
self._ctx = ctx
|
||||
self._key = key
|
||||
|
||||
def copy(self):
|
||||
copied_ctx = self._backend._ffi.new("CCHmacContext *")
|
||||
# CommonCrypto has no APIs for copying HMACs, so we have to copy the
|
||||
# underlying struct.
|
||||
copied_ctx[0] = self._ctx[0]
|
||||
return _HMACContext(
|
||||
self._backend, self._key, self.algorithm, ctx=copied_ctx
|
||||
)
|
||||
|
||||
def update(self, data):
|
||||
self._backend._lib.CCHmacUpdate(self._ctx, data, len(data))
|
||||
|
||||
def finalize(self):
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
self.algorithm.digest_size)
|
||||
self._backend._lib.CCHmacFinal(self._ctx, buf)
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
def _release_cipher_ctx(self, ctx):
|
||||
"""
|
||||
Called by the garbage collector and used to safely dereference and
|
||||
release the context.
|
||||
"""
|
||||
if ctx[0] != self._ffi.NULL:
|
||||
res = self._lib.CCCryptorRelease(ctx[0])
|
||||
self._check_cipher_response(res)
|
||||
ctx[0] = self._ffi.NULL
|
||||
|
||||
|
||||
backend = Backend()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
InvalidTag, UnsupportedAlgorithm, _Reasons
|
||||
)
|
||||
from cryptography.hazmat.primitives import constant_time, interfaces
|
||||
from cryptography.hazmat.primitives.ciphers.modes import (
|
||||
CFB, CFB8, CTR, OFB
|
||||
)
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.CipherContext)
|
||||
class _CipherContext(object):
|
||||
def __init__(self, backend, cipher, mode, operation):
|
||||
self._backend = backend
|
||||
self._cipher = cipher
|
||||
self._mode = mode
|
||||
self._operation = operation
|
||||
# There is a bug in CommonCrypto where block ciphers do not raise
|
||||
# kCCAlignmentError when finalizing if you supply non-block aligned
|
||||
# data. To work around this we need to keep track of the block
|
||||
# alignment ourselves, but only for alg+mode combos that require
|
||||
# block alignment. OFB, CFB, and CTR make a block cipher algorithm
|
||||
# into a stream cipher so we don't need to track them (and thus their
|
||||
# block size is effectively 1 byte just like OpenSSL/CommonCrypto
|
||||
# treat RC4 and other stream cipher block sizes).
|
||||
# This bug has been filed as rdar://15589470
|
||||
self._bytes_processed = 0
|
||||
if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not
|
||||
isinstance(mode, (OFB, CFB, CFB8, CTR))):
|
||||
self._byte_block_size = cipher.block_size // 8
|
||||
else:
|
||||
self._byte_block_size = 1
|
||||
|
||||
registry = self._backend._cipher_registry
|
||||
try:
|
||||
cipher_enum, mode_enum = registry[type(cipher), type(mode)]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported "
|
||||
"by this backend.".format(
|
||||
cipher.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
||||
ctx = self._backend._ffi.new("CCCryptorRef *")
|
||||
ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
|
||||
|
||||
if isinstance(mode, interfaces.ModeWithInitializationVector):
|
||||
iv_nonce = mode.initialization_vector
|
||||
elif isinstance(mode, interfaces.ModeWithNonce):
|
||||
iv_nonce = mode.nonce
|
||||
else:
|
||||
iv_nonce = self._backend._ffi.NULL
|
||||
|
||||
if isinstance(mode, CTR):
|
||||
mode_option = self._backend._lib.kCCModeOptionCTR_BE
|
||||
else:
|
||||
mode_option = 0
|
||||
|
||||
res = self._backend._lib.CCCryptorCreateWithMode(
|
||||
operation,
|
||||
mode_enum, cipher_enum,
|
||||
self._backend._lib.ccNoPadding, iv_nonce,
|
||||
cipher.key, len(cipher.key),
|
||||
self._backend._ffi.NULL, 0, 0, mode_option, ctx)
|
||||
self._backend._check_cipher_response(res)
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
def update(self, data):
|
||||
# Count bytes processed to handle block alignment.
|
||||
self._bytes_processed += len(data)
|
||||
buf = self._backend._ffi.new(
|
||||
"unsigned char[]", len(data) + self._byte_block_size - 1)
|
||||
outlen = self._backend._ffi.new("size_t *")
|
||||
res = self._backend._lib.CCCryptorUpdate(
|
||||
self._ctx[0], data, len(data), buf,
|
||||
len(data) + self._byte_block_size - 1, outlen)
|
||||
self._backend._check_cipher_response(res)
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
def finalize(self):
|
||||
# Raise error if block alignment is wrong.
|
||||
if self._bytes_processed % self._byte_block_size:
|
||||
raise ValueError(
|
||||
"The length of the provided data is not a multiple of "
|
||||
"the block length."
|
||||
)
|
||||
buf = self._backend._ffi.new("unsigned char[]", self._byte_block_size)
|
||||
outlen = self._backend._ffi.new("size_t *")
|
||||
res = self._backend._lib.CCCryptorFinal(
|
||||
self._ctx[0], buf, len(buf), outlen)
|
||||
self._backend._check_cipher_response(res)
|
||||
self._backend._release_cipher_ctx(self._ctx)
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AEADCipherContext)
|
||||
@utils.register_interface(interfaces.AEADEncryptionContext)
|
||||
class _GCMCipherContext(object):
|
||||
def __init__(self, backend, cipher, mode, operation):
|
||||
self._backend = backend
|
||||
self._cipher = cipher
|
||||
self._mode = mode
|
||||
self._operation = operation
|
||||
self._tag = None
|
||||
|
||||
registry = self._backend._cipher_registry
|
||||
try:
|
||||
cipher_enum, mode_enum = registry[type(cipher), type(mode)]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported "
|
||||
"by this backend.".format(
|
||||
cipher.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
||||
ctx = self._backend._ffi.new("CCCryptorRef *")
|
||||
ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
res = self._backend._lib.CCCryptorCreateWithMode(
|
||||
operation,
|
||||
mode_enum, cipher_enum,
|
||||
self._backend._lib.ccNoPadding,
|
||||
self._backend._ffi.NULL,
|
||||
cipher.key, len(cipher.key),
|
||||
self._backend._ffi.NULL, 0, 0, 0, self._ctx)
|
||||
self._backend._check_cipher_response(res)
|
||||
|
||||
res = self._backend._lib.CCCryptorGCMAddIV(
|
||||
self._ctx[0],
|
||||
mode.initialization_vector,
|
||||
len(mode.initialization_vector)
|
||||
)
|
||||
self._backend._check_cipher_response(res)
|
||||
|
||||
def update(self, data):
|
||||
buf = self._backend._ffi.new("unsigned char[]", len(data))
|
||||
args = (self._ctx[0], data, len(data), buf)
|
||||
if self._operation == self._backend._lib.kCCEncrypt:
|
||||
res = self._backend._lib.CCCryptorGCMEncrypt(*args)
|
||||
else:
|
||||
res = self._backend._lib.CCCryptorGCMDecrypt(*args)
|
||||
|
||||
self._backend._check_cipher_response(res)
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
||||
def finalize(self):
|
||||
tag_size = self._cipher.block_size // 8
|
||||
tag_buf = self._backend._ffi.new("unsigned char[]", tag_size)
|
||||
tag_len = self._backend._ffi.new("size_t *", tag_size)
|
||||
res = self._backend._lib.CCCryptorGCMFinal(
|
||||
self._ctx[0], tag_buf, tag_len
|
||||
)
|
||||
self._backend._check_cipher_response(res)
|
||||
self._backend._release_cipher_ctx(self._ctx)
|
||||
self._tag = self._backend._ffi.buffer(tag_buf)[:]
|
||||
if (self._operation == self._backend._lib.kCCDecrypt and
|
||||
not constant_time.bytes_eq(
|
||||
self._tag[:len(self._mode.tag)], self._mode.tag
|
||||
)):
|
||||
raise InvalidTag
|
||||
return b""
|
||||
|
||||
def authenticate_additional_data(self, data):
|
||||
res = self._backend._lib.CCCryptorGCMAddAAD(
|
||||
self._ctx[0], data, len(data)
|
||||
)
|
||||
self._backend._check_cipher_response(res)
|
||||
|
||||
@property
|
||||
def tag(self):
|
||||
return self._tag
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.HashContext)
|
||||
class _HashContext(object):
|
||||
def __init__(self, backend, algorithm, ctx=None):
|
||||
self.algorithm = algorithm
|
||||
self._backend = backend
|
||||
|
||||
if ctx is None:
|
||||
try:
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
ctx = self._backend._ffi.new(methods.ctx)
|
||||
res = methods.hash_init(ctx)
|
||||
assert res == 1
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
def copy(self):
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
new_ctx = self._backend._ffi.new(methods.ctx)
|
||||
# CommonCrypto has no APIs for copying hashes, so we have to copy the
|
||||
# underlying struct.
|
||||
new_ctx[0] = self._ctx[0]
|
||||
|
||||
return _HashContext(self._backend, self.algorithm, ctx=new_ctx)
|
||||
|
||||
def update(self, data):
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
res = methods.hash_update(self._ctx, data, len(data))
|
||||
assert res == 1
|
||||
|
||||
def finalize(self):
|
||||
methods = self._backend._hash_mapping[self.algorithm.name]
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
self.algorithm.digest_size)
|
||||
res = methods.hash_final(buf, self._ctx)
|
||||
assert res == 1
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.HashContext)
|
||||
class _HMACContext(object):
|
||||
def __init__(self, backend, key, algorithm, ctx=None):
|
||||
self.algorithm = algorithm
|
||||
self._backend = backend
|
||||
if ctx is None:
|
||||
ctx = self._backend._ffi.new("CCHmacContext *")
|
||||
try:
|
||||
alg = self._backend._supported_hmac_algorithms[algorithm.name]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported HMAC hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
||||
self._backend._lib.CCHmacInit(ctx, alg, key, len(key))
|
||||
|
||||
self._ctx = ctx
|
||||
self._key = key
|
||||
|
||||
def copy(self):
|
||||
copied_ctx = self._backend._ffi.new("CCHmacContext *")
|
||||
# CommonCrypto has no APIs for copying HMACs, so we have to copy the
|
||||
# underlying struct.
|
||||
copied_ctx[0] = self._ctx[0]
|
||||
return _HMACContext(
|
||||
self._backend, self._key, self.algorithm, ctx=copied_ctx
|
||||
)
|
||||
|
||||
def update(self, data):
|
||||
self._backend._lib.CCHmacUpdate(self._ctx, data, len(data))
|
||||
|
||||
def finalize(self):
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
self.algorithm.digest_size)
|
||||
self._backend._lib.CCHmacFinal(self._ctx, buf)
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
|
@ -129,6 +129,31 @@ class RSABackend(object):
|
|||
Returns encrypted bytes.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def rsa_padding_supported(self, padding):
|
||||
"""
|
||||
Returns True if the backend supports the given padding options.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def generate_rsa_parameters_supported(self, public_exponent, key_size):
|
||||
"""
|
||||
Returns True if the backend supports the given parameters for key
|
||||
generation.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def load_rsa_private_numbers(self, numbers):
|
||||
"""
|
||||
Returns an RSAPrivateKey provider.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def load_rsa_public_numbers(self, numbers):
|
||||
"""
|
||||
Returns an RSAPublicKey provider.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DSABackend(object):
|
||||
|
|
@ -141,8 +166,14 @@ class DSABackend(object):
|
|||
@abc.abstractmethod
|
||||
def generate_dsa_private_key(self, parameters):
|
||||
"""
|
||||
Generate an DSAPrivateKey instance with parameters as
|
||||
a DSAParameters object.
|
||||
Generate a DSAPrivateKey instance with parameters as a DSAParameters
|
||||
object.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def generate_dsa_private_key_and_parameters(self, key_size):
|
||||
"""
|
||||
Generate a DSAPrivateKey instance using key size only.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
|
|
@ -171,6 +202,24 @@ class DSABackend(object):
|
|||
Return True if the parameters are supported by the backend for DSA.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def load_dsa_private_numbers(self, numbers):
|
||||
"""
|
||||
Returns a DSAPrivateKey provider.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def load_dsa_public_numbers(self, numbers):
|
||||
"""
|
||||
Returns a DSAPublicKey provider.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def load_dsa_parameter_numbers(self, numbers):
|
||||
"""
|
||||
Returns a DSAParameters provider.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class TraditionalOpenSSLSerializationBackend(object):
|
||||
|
|
@ -182,6 +231,16 @@ class TraditionalOpenSSLSerializationBackend(object):
|
|||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class PKCS8SerializationBackend(object):
|
||||
@abc.abstractmethod
|
||||
def load_pkcs8_pem_private_key(self, data, password):
|
||||
"""
|
||||
Load a private key from PEM encoded data, using password if the data
|
||||
is encrypted.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class CMACBackend(object):
|
||||
@abc.abstractmethod
|
||||
|
|
@ -195,3 +254,39 @@ class CMACBackend(object):
|
|||
"""
|
||||
Create a CMACContext for calculating a message authentication code.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class EllipticCurveBackend(object):
|
||||
@abc.abstractmethod
|
||||
def elliptic_curve_signature_algorithm_supported(
|
||||
self, signature_algorithm, curve
|
||||
):
|
||||
"""
|
||||
Returns True if the backend supports the named elliptic curve with the
|
||||
specified signature algorithm.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def elliptic_curve_supported(self, curve):
|
||||
"""
|
||||
Returns True if the backend supports the named elliptic curve.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def generate_elliptic_curve_private_key(self, curve):
|
||||
"""
|
||||
Return an object conforming to the EllipticCurvePrivateKey interface.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def elliptic_curve_public_key_from_numbers(self, numbers):
|
||||
"""
|
||||
Return an EllipticCurvePublicKey provider using the given numbers.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def elliptic_curve_private_key_from_numbers(self, numbers):
|
||||
"""
|
||||
Return an EllipticCurvePublicKey provider using the given numbers.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ from __future__ import absolute_import, division, print_function
|
|||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.backends.interfaces import (
|
||||
CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
|
||||
PBKDF2HMACBackend, RSABackend
|
||||
CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
|
||||
HashBackend, PBKDF2HMACBackend, PKCS8SerializationBackend,
|
||||
RSABackend, TraditionalOpenSSLSerializationBackend
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -26,8 +27,11 @@ from cryptography.hazmat.backends.interfaces import (
|
|||
@utils.register_interface(HashBackend)
|
||||
@utils.register_interface(HMACBackend)
|
||||
@utils.register_interface(PBKDF2HMACBackend)
|
||||
@utils.register_interface(PKCS8SerializationBackend)
|
||||
@utils.register_interface(RSABackend)
|
||||
@utils.register_interface(TraditionalOpenSSLSerializationBackend)
|
||||
@utils.register_interface(DSABackend)
|
||||
@utils.register_interface(EllipticCurveBackend)
|
||||
class MultiBackend(object):
|
||||
name = "multibackend"
|
||||
|
||||
|
|
@ -52,7 +56,7 @@ class MultiBackend(object):
|
|||
except UnsupportedAlgorithm:
|
||||
pass
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported by this backend".format(
|
||||
"cipher {0} in {1} mode is not supported by this backend.".format(
|
||||
algorithm.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
|
@ -64,7 +68,7 @@ class MultiBackend(object):
|
|||
except UnsupportedAlgorithm:
|
||||
pass
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported by this backend".format(
|
||||
"cipher {0} in {1} mode is not supported by this backend.".format(
|
||||
algorithm.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
|
@ -82,7 +86,7 @@ class MultiBackend(object):
|
|||
except UnsupportedAlgorithm:
|
||||
pass
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend".format(
|
||||
"{0} is not a supported hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
|
@ -100,7 +104,7 @@ class MultiBackend(object):
|
|||
except UnsupportedAlgorithm:
|
||||
pass
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend".format(
|
||||
"{0} is not a supported hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
|
@ -121,7 +125,7 @@ class MultiBackend(object):
|
|||
except UnsupportedAlgorithm:
|
||||
pass
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend".format(
|
||||
"{0} is not a supported hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
|
@ -129,13 +133,21 @@ class MultiBackend(object):
|
|||
def generate_rsa_private_key(self, public_exponent, key_size):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.generate_rsa_private_key(public_exponent, key_size)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def generate_rsa_parameters_supported(self, public_exponent, key_size):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.generate_rsa_parameters_supported(
|
||||
public_exponent, key_size
|
||||
)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def create_rsa_signature_ctx(self, private_key, padding, algorithm):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.create_rsa_signature_ctx(private_key, padding, algorithm)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def create_rsa_verification_ctx(self, public_key, signature, padding,
|
||||
|
|
@ -143,44 +155,88 @@ class MultiBackend(object):
|
|||
for b in self._filtered_backends(RSABackend):
|
||||
return b.create_rsa_verification_ctx(public_key, signature,
|
||||
padding, algorithm)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def mgf1_hash_supported(self, algorithm):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.mgf1_hash_supported(algorithm)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def decrypt_rsa(self, private_key, ciphertext, padding):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.decrypt_rsa(private_key, ciphertext, padding)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def encrypt_rsa(self, public_key, plaintext, padding):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.encrypt_rsa(public_key, plaintext, padding)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def rsa_padding_supported(self, padding):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.rsa_padding_supported(padding)
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def load_rsa_private_numbers(self, numbers):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.load_rsa_private_numbers(numbers)
|
||||
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def load_rsa_public_numbers(self, numbers):
|
||||
for b in self._filtered_backends(RSABackend):
|
||||
return b.load_rsa_public_numbers(numbers)
|
||||
|
||||
raise UnsupportedAlgorithm("RSA is not supported by the backend",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def generate_dsa_parameters(self, key_size):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.generate_dsa_parameters(key_size)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def generate_dsa_private_key(self, parameters):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.generate_dsa_private_key(parameters)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def generate_dsa_private_key_and_parameters(self, key_size):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.generate_dsa_private_key_and_parameters(key_size)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def create_dsa_verification_ctx(self, public_key, signature, algorithm):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.create_dsa_verification_ctx(public_key, signature,
|
||||
algorithm)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def create_dsa_signature_ctx(self, private_key, algorithm):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.create_dsa_signature_ctx(private_key, algorithm)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def dsa_hash_supported(self, algorithm):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.dsa_hash_supported(algorithm)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def dsa_parameters_supported(self, p, q, g):
|
||||
for b in self._filtered_backends(DSABackend):
|
||||
return b.dsa_parameters_supported(p, q, g)
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend",
|
||||
raise UnsupportedAlgorithm("DSA is not supported by the backend.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def cmac_algorithm_supported(self, algorithm):
|
||||
|
|
@ -195,5 +251,77 @@ class MultiBackend(object):
|
|||
return b.create_cmac_ctx(algorithm)
|
||||
except UnsupportedAlgorithm:
|
||||
pass
|
||||
raise UnsupportedAlgorithm("This backend does not support CMAC",
|
||||
raise UnsupportedAlgorithm("This backend does not support CMAC.",
|
||||
_Reasons.UNSUPPORTED_CIPHER)
|
||||
|
||||
def elliptic_curve_supported(self, curve):
|
||||
return any(
|
||||
b.elliptic_curve_supported(curve)
|
||||
for b in self._filtered_backends(EllipticCurveBackend)
|
||||
)
|
||||
|
||||
def elliptic_curve_signature_algorithm_supported(
|
||||
self, signature_algorithm, curve
|
||||
):
|
||||
return any(
|
||||
b.elliptic_curve_signature_algorithm_supported(
|
||||
signature_algorithm, curve
|
||||
)
|
||||
for b in self._filtered_backends(EllipticCurveBackend)
|
||||
)
|
||||
|
||||
def generate_elliptic_curve_private_key(self, curve):
|
||||
for b in self._filtered_backends(EllipticCurveBackend):
|
||||
try:
|
||||
return b.generate_elliptic_curve_private_key(curve)
|
||||
except UnsupportedAlgorithm:
|
||||
continue
|
||||
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend does not support this elliptic curve.",
|
||||
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
|
||||
)
|
||||
|
||||
def elliptic_curve_private_key_from_numbers(self, numbers):
|
||||
for b in self._filtered_backends(EllipticCurveBackend):
|
||||
try:
|
||||
return b.elliptic_curve_private_key_from_numbers(numbers)
|
||||
except UnsupportedAlgorithm:
|
||||
continue
|
||||
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend does not support this elliptic curve.",
|
||||
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
|
||||
)
|
||||
|
||||
def elliptic_curve_public_key_from_numbers(self, numbers):
|
||||
for b in self._filtered_backends(EllipticCurveBackend):
|
||||
try:
|
||||
return b.elliptic_curve_public_key_from_numbers(numbers)
|
||||
except UnsupportedAlgorithm:
|
||||
continue
|
||||
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend does not support this elliptic curve.",
|
||||
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
|
||||
)
|
||||
|
||||
def load_pkcs8_pem_private_key(self, data, password):
|
||||
for b in self._filtered_backends(PKCS8SerializationBackend):
|
||||
return b.load_pkcs8_pem_private_key(data, password)
|
||||
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend does not support this key serialization.",
|
||||
_Reasons.UNSUPPORTED_SERIALIZATION
|
||||
)
|
||||
|
||||
def load_traditional_openssl_pem_private_key(self, data, password):
|
||||
for b in self._filtered_backends(
|
||||
TraditionalOpenSSLSerializationBackend
|
||||
):
|
||||
return b.load_traditional_openssl_pem_private_key(data, password)
|
||||
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend does not support this key serialization.",
|
||||
_Reasons.UNSUPPORTED_SERIALIZATION
|
||||
)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,219 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
from cryptography.hazmat.primitives.ciphers.modes import GCM
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.CipherContext)
|
||||
@utils.register_interface(interfaces.AEADCipherContext)
|
||||
@utils.register_interface(interfaces.AEADEncryptionContext)
|
||||
class _CipherContext(object):
|
||||
_ENCRYPT = 1
|
||||
_DECRYPT = 0
|
||||
|
||||
def __init__(self, backend, cipher, mode, operation):
|
||||
self._backend = backend
|
||||
self._cipher = cipher
|
||||
self._mode = mode
|
||||
self._operation = operation
|
||||
self._tag = None
|
||||
|
||||
if isinstance(self._cipher, interfaces.BlockCipherAlgorithm):
|
||||
self._block_size = self._cipher.block_size
|
||||
else:
|
||||
self._block_size = 1
|
||||
|
||||
ctx = self._backend._lib.EVP_CIPHER_CTX_new()
|
||||
ctx = self._backend._ffi.gc(
|
||||
ctx, self._backend._lib.EVP_CIPHER_CTX_free
|
||||
)
|
||||
|
||||
registry = self._backend._cipher_registry
|
||||
try:
|
||||
adapter = registry[type(cipher), type(mode)]
|
||||
except KeyError:
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported "
|
||||
"by this backend.".format(
|
||||
cipher.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
||||
evp_cipher = adapter(self._backend, cipher, mode)
|
||||
if evp_cipher == self._backend._ffi.NULL:
|
||||
raise UnsupportedAlgorithm(
|
||||
"cipher {0} in {1} mode is not supported "
|
||||
"by this backend.".format(
|
||||
cipher.name, mode.name if mode else mode),
|
||||
_Reasons.UNSUPPORTED_CIPHER
|
||||
)
|
||||
|
||||
if isinstance(mode, interfaces.ModeWithInitializationVector):
|
||||
iv_nonce = mode.initialization_vector
|
||||
elif isinstance(mode, interfaces.ModeWithNonce):
|
||||
iv_nonce = mode.nonce
|
||||
else:
|
||||
iv_nonce = self._backend._ffi.NULL
|
||||
# begin init with cipher and operation type
|
||||
res = self._backend._lib.EVP_CipherInit_ex(ctx, evp_cipher,
|
||||
self._backend._ffi.NULL,
|
||||
self._backend._ffi.NULL,
|
||||
self._backend._ffi.NULL,
|
||||
operation)
|
||||
assert res != 0
|
||||
# set the key length to handle variable key ciphers
|
||||
res = self._backend._lib.EVP_CIPHER_CTX_set_key_length(
|
||||
ctx, len(cipher.key)
|
||||
)
|
||||
assert res != 0
|
||||
if isinstance(mode, GCM):
|
||||
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
|
||||
ctx, self._backend._lib.EVP_CTRL_GCM_SET_IVLEN,
|
||||
len(iv_nonce), self._backend._ffi.NULL
|
||||
)
|
||||
assert res != 0
|
||||
if operation == self._DECRYPT:
|
||||
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
|
||||
ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG,
|
||||
len(mode.tag), mode.tag
|
||||
)
|
||||
assert res != 0
|
||||
|
||||
# pass key/iv
|
||||
res = self._backend._lib.EVP_CipherInit_ex(
|
||||
ctx,
|
||||
self._backend._ffi.NULL,
|
||||
self._backend._ffi.NULL,
|
||||
cipher.key,
|
||||
iv_nonce,
|
||||
operation
|
||||
)
|
||||
assert res != 0
|
||||
# We purposely disable padding here as it's handled higher up in the
|
||||
# API.
|
||||
self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0)
|
||||
self._ctx = ctx
|
||||
|
||||
def update(self, data):
|
||||
# OpenSSL 0.9.8e has an assertion in its EVP code that causes it
|
||||
# to SIGABRT if you call update with an empty byte string. This can be
|
||||
# removed when we drop support for 0.9.8e (CentOS/RHEL 5). This branch
|
||||
# should be taken only when length is zero and mode is not GCM because
|
||||
# AES GCM can return improper tag values if you don't call update
|
||||
# with empty plaintext when authenticating AAD for ...reasons.
|
||||
if len(data) == 0 and not isinstance(self._mode, GCM):
|
||||
return b""
|
||||
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
len(data) + self._block_size - 1)
|
||||
outlen = self._backend._ffi.new("int *")
|
||||
res = self._backend._lib.EVP_CipherUpdate(self._ctx, buf, outlen, data,
|
||||
len(data))
|
||||
assert res != 0
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
def finalize(self):
|
||||
buf = self._backend._ffi.new("unsigned char[]", self._block_size)
|
||||
outlen = self._backend._ffi.new("int *")
|
||||
res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
|
||||
if res == 0:
|
||||
errors = self._backend._consume_errors()
|
||||
|
||||
if not errors and isinstance(self._mode, GCM):
|
||||
raise InvalidTag
|
||||
|
||||
assert errors
|
||||
|
||||
if errors[0][1:] == (
|
||||
self._backend._lib.ERR_LIB_EVP,
|
||||
self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
|
||||
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
|
||||
) or errors[0][1:] == (
|
||||
self._backend._lib.ERR_LIB_EVP,
|
||||
self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
|
||||
self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
|
||||
):
|
||||
raise ValueError(
|
||||
"The length of the provided data is not a multiple of "
|
||||
"the block length."
|
||||
)
|
||||
else:
|
||||
raise self._backend._unknown_error(errors[0])
|
||||
|
||||
if (isinstance(self._mode, GCM) and
|
||||
self._operation == self._ENCRYPT):
|
||||
block_byte_size = self._block_size // 8
|
||||
tag_buf = self._backend._ffi.new(
|
||||
"unsigned char[]", block_byte_size
|
||||
)
|
||||
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
|
||||
self._ctx, self._backend._lib.EVP_CTRL_GCM_GET_TAG,
|
||||
block_byte_size, tag_buf
|
||||
)
|
||||
assert res != 0
|
||||
self._tag = self._backend._ffi.buffer(tag_buf)[:]
|
||||
|
||||
res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx)
|
||||
assert res == 1
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
def authenticate_additional_data(self, data):
|
||||
outlen = self._backend._ffi.new("int *")
|
||||
res = self._backend._lib.EVP_CipherUpdate(
|
||||
self._ctx, self._backend._ffi.NULL, outlen, data, len(data)
|
||||
)
|
||||
assert res != 0
|
||||
|
||||
@property
|
||||
def tag(self):
|
||||
return self._tag
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.CipherContext)
|
||||
class _AESCTRCipherContext(object):
|
||||
"""
|
||||
This is needed to provide support for AES CTR mode in OpenSSL 0.9.8. It can
|
||||
be removed when we drop 0.9.8 support (RHEL5 extended life ends 2020).
|
||||
"""
|
||||
def __init__(self, backend, cipher, mode):
|
||||
self._backend = backend
|
||||
|
||||
self._key = self._backend._ffi.new("AES_KEY *")
|
||||
assert self._key != self._backend._ffi.NULL
|
||||
res = self._backend._lib.AES_set_encrypt_key(
|
||||
cipher.key, len(cipher.key) * 8, self._key
|
||||
)
|
||||
assert res == 0
|
||||
self._ecount = self._backend._ffi.new("char[]", 16)
|
||||
self._nonce = self._backend._ffi.new("char[16]", mode.nonce)
|
||||
self._num = self._backend._ffi.new("unsigned int *", 0)
|
||||
|
||||
def update(self, data):
|
||||
buf = self._backend._ffi.new("unsigned char[]", len(data))
|
||||
self._backend._lib.AES_ctr128_encrypt(
|
||||
data, buf, len(data), self._key, self._nonce,
|
||||
self._ecount, self._num
|
||||
)
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
||||
def finalize(self):
|
||||
self._key = None
|
||||
self._ecount = None
|
||||
self._nonce = None
|
||||
self._num = None
|
||||
return b""
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
from cryptography.hazmat.primitives.ciphers.modes import CBC
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.CMACContext)
|
||||
class _CMACContext(object):
|
||||
def __init__(self, backend, algorithm, ctx=None):
|
||||
if not backend.cmac_algorithm_supported(algorithm):
|
||||
raise UnsupportedAlgorithm("This backend does not support CMAC.",
|
||||
_Reasons.UNSUPPORTED_CIPHER)
|
||||
|
||||
self._backend = backend
|
||||
self._key = algorithm.key
|
||||
self._algorithm = algorithm
|
||||
self._output_length = algorithm.block_size // 8
|
||||
|
||||
if ctx is None:
|
||||
registry = self._backend._cipher_registry
|
||||
adapter = registry[type(algorithm), CBC]
|
||||
|
||||
evp_cipher = adapter(self._backend, algorithm, CBC)
|
||||
|
||||
ctx = self._backend._lib.CMAC_CTX_new()
|
||||
|
||||
assert ctx != self._backend._ffi.NULL
|
||||
ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
|
||||
|
||||
self._backend._lib.CMAC_Init(
|
||||
ctx, self._key, len(self._key),
|
||||
evp_cipher, self._backend._ffi.NULL
|
||||
)
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
def update(self, data):
|
||||
res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
|
||||
assert res == 1
|
||||
|
||||
def finalize(self):
|
||||
buf = self._backend._ffi.new("unsigned char[]", self._output_length)
|
||||
length = self._backend._ffi.new("size_t *", self._output_length)
|
||||
res = self._backend._lib.CMAC_Final(
|
||||
self._ctx, buf, length
|
||||
)
|
||||
assert res == 1
|
||||
|
||||
self._ctx = None
|
||||
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
||||
def copy(self):
|
||||
copied_ctx = self._backend._lib.CMAC_CTX_new()
|
||||
copied_ctx = self._backend._ffi.gc(
|
||||
copied_ctx, self._backend._lib.CMAC_CTX_free
|
||||
)
|
||||
res = self._backend._lib.CMAC_CTX_copy(
|
||||
copied_ctx, self._ctx
|
||||
)
|
||||
assert res == 1
|
||||
return _CMACContext(
|
||||
self._backend, self._algorithm, ctx=copied_ctx
|
||||
)
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
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)
|
||||
class _DSAVerificationContext(object):
|
||||
def __init__(self, backend, public_key, signature, algorithm):
|
||||
self._backend = backend
|
||||
self._public_key = public_key
|
||||
self._signature = signature
|
||||
self._algorithm = algorithm
|
||||
|
||||
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
|
||||
|
||||
def update(self, data):
|
||||
self._hash_ctx.update(data)
|
||||
|
||||
def verify(self):
|
||||
self._dsa_cdata = self._backend._ffi.gc(self._public_key._dsa_cdata,
|
||||
self._backend._lib.DSA_free)
|
||||
|
||||
data_to_verify = self._hash_ctx.finalize()
|
||||
|
||||
# The first parameter passed to DSA_verify is unused by OpenSSL but
|
||||
# must be an integer.
|
||||
res = self._backend._lib.DSA_verify(
|
||||
0, data_to_verify, len(data_to_verify), self._signature,
|
||||
len(self._signature), self._public_key._dsa_cdata)
|
||||
|
||||
if res != 1:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors
|
||||
if res == -1:
|
||||
assert errors[0].lib == self._backend._lib.ERR_LIB_ASN1
|
||||
|
||||
raise InvalidSignature
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AsymmetricSignatureContext)
|
||||
class _DSASignatureContext(object):
|
||||
def __init__(self, backend, private_key, algorithm):
|
||||
self._backend = backend
|
||||
self._private_key = private_key
|
||||
self._algorithm = algorithm
|
||||
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
|
||||
|
||||
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._private_key._dsa_cdata)
|
||||
sig_buf = self._backend._ffi.new("unsigned char[]", sig_buf_len)
|
||||
buflen = self._backend._ffi.new("unsigned int *")
|
||||
|
||||
# The first parameter passed to DSA_sign is unused by OpenSSL but
|
||||
# must be an integer.
|
||||
res = self._backend._lib.DSA_sign(
|
||||
0, data_to_sign, len(data_to_sign), sig_buf,
|
||||
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)
|
||||
)
|
||||
|
||||
def generate_private_key(self):
|
||||
return self._backend.generate_dsa_private_key(self)
|
||||
|
||||
|
||||
@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)
|
||||
|
|
@ -0,0 +1,191 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
InvalidSignature, UnsupportedAlgorithm, _Reasons
|
||||
)
|
||||
from cryptography.hazmat.primitives import hashes, interfaces
|
||||
from cryptography.hazmat.primitives.asymmetric import ec
|
||||
|
||||
|
||||
def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
|
||||
_lib = backend._lib
|
||||
_ffi = backend._ffi
|
||||
|
||||
digest_len = len(digest)
|
||||
|
||||
group = _lib.EC_KEY_get0_group(ec_key_cdata)
|
||||
|
||||
bn_ctx = _lib.BN_CTX_new()
|
||||
assert bn_ctx != _ffi.NULL
|
||||
bn_ctx = _ffi.gc(bn_ctx, _lib.BN_CTX_free)
|
||||
|
||||
order = _lib.BN_CTX_get(bn_ctx)
|
||||
assert order != _ffi.NULL
|
||||
|
||||
res = _lib.EC_GROUP_get_order(group, order, bn_ctx)
|
||||
assert res == 1
|
||||
|
||||
order_bits = _lib.BN_num_bits(order)
|
||||
|
||||
if 8 * digest_len > order_bits:
|
||||
digest_len = (order_bits + 7) // 8
|
||||
digest = digest[:digest_len]
|
||||
|
||||
if 8 * digest_len > order_bits:
|
||||
rshift = 8 - (order_bits & 0x7)
|
||||
assert rshift > 0 and rshift < 8
|
||||
|
||||
mask = 0xFF >> rshift << rshift
|
||||
|
||||
# Set the bottom rshift bits to 0
|
||||
digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
|
||||
|
||||
return digest
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AsymmetricSignatureContext)
|
||||
class _ECDSASignatureContext(object):
|
||||
def __init__(self, backend, private_key, algorithm):
|
||||
self._backend = backend
|
||||
self._private_key = private_key
|
||||
self._digest = hashes.Hash(algorithm, backend)
|
||||
|
||||
def update(self, data):
|
||||
self._digest.update(data)
|
||||
|
||||
def finalize(self):
|
||||
ec_key = self._private_key._ec_key
|
||||
|
||||
digest = self._digest.finalize()
|
||||
|
||||
digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
|
||||
|
||||
max_size = self._backend._lib.ECDSA_size(ec_key)
|
||||
assert max_size > 0
|
||||
|
||||
sigbuf = self._backend._ffi.new("char[]", max_size)
|
||||
siglen_ptr = self._backend._ffi.new("unsigned int[]", 1)
|
||||
res = self._backend._lib.ECDSA_sign(
|
||||
0,
|
||||
digest,
|
||||
len(digest),
|
||||
sigbuf,
|
||||
siglen_ptr,
|
||||
ec_key
|
||||
)
|
||||
assert res == 1
|
||||
return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AsymmetricVerificationContext)
|
||||
class _ECDSAVerificationContext(object):
|
||||
def __init__(self, backend, public_key, signature, algorithm):
|
||||
self._backend = backend
|
||||
self._public_key = public_key
|
||||
self._signature = signature
|
||||
self._digest = hashes.Hash(algorithm, backend)
|
||||
|
||||
def update(self, data):
|
||||
self._digest.update(data)
|
||||
|
||||
def verify(self):
|
||||
ec_key = self._public_key._ec_key
|
||||
|
||||
digest = self._digest.finalize()
|
||||
|
||||
digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
|
||||
|
||||
res = self._backend._lib.ECDSA_verify(
|
||||
0,
|
||||
digest,
|
||||
len(digest),
|
||||
self._signature,
|
||||
len(self._signature),
|
||||
ec_key
|
||||
)
|
||||
if res != 1:
|
||||
self._backend._consume_errors()
|
||||
raise InvalidSignature
|
||||
return True
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurvePrivateKey)
|
||||
class _EllipticCurvePrivateKey(object):
|
||||
def __init__(self, backend, ec_key_cdata, curve):
|
||||
self._backend = backend
|
||||
self._ec_key = ec_key_cdata
|
||||
self._curve = curve
|
||||
|
||||
@property
|
||||
def curve(self):
|
||||
return self._curve
|
||||
|
||||
def signer(self, signature_algorithm):
|
||||
if isinstance(signature_algorithm, ec.ECDSA):
|
||||
return _ECDSASignatureContext(
|
||||
self._backend, self, signature_algorithm.algorithm
|
||||
)
|
||||
else:
|
||||
raise UnsupportedAlgorithm(
|
||||
"Unsupported elliptic curve signature algorithm.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
||||
def public_key(self):
|
||||
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
|
||||
assert group != self._backend._ffi.NULL
|
||||
|
||||
curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group)
|
||||
|
||||
public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid)
|
||||
assert public_ec_key != self._backend._ffi.NULL
|
||||
public_ec_key = self._backend._ffi.gc(
|
||||
public_ec_key, self._backend._lib.EC_KEY_free
|
||||
)
|
||||
|
||||
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
|
||||
assert point != self._backend._ffi.NULL
|
||||
|
||||
res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point)
|
||||
assert res == 1
|
||||
|
||||
return _EllipticCurvePublicKey(
|
||||
self._backend, public_ec_key, self._curve
|
||||
)
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurvePublicKey)
|
||||
class _EllipticCurvePublicKey(object):
|
||||
def __init__(self, backend, ec_key_cdata, curve):
|
||||
self._backend = backend
|
||||
self._ec_key = ec_key_cdata
|
||||
self._curve = curve
|
||||
|
||||
@property
|
||||
def curve(self):
|
||||
return self._curve
|
||||
|
||||
def verifier(self, signature, signature_algorithm):
|
||||
if isinstance(signature_algorithm, ec.ECDSA):
|
||||
return _ECDSAVerificationContext(
|
||||
self._backend, self, signature, signature_algorithm.algorithm
|
||||
)
|
||||
else:
|
||||
raise UnsupportedAlgorithm(
|
||||
"Unsupported elliptic curve signature algorithm.",
|
||||
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.HashContext)
|
||||
class _HashContext(object):
|
||||
def __init__(self, backend, algorithm, ctx=None):
|
||||
self.algorithm = algorithm
|
||||
|
||||
self._backend = backend
|
||||
|
||||
if ctx is None:
|
||||
ctx = self._backend._lib.EVP_MD_CTX_create()
|
||||
ctx = self._backend._ffi.gc(ctx,
|
||||
self._backend._lib.EVP_MD_CTX_destroy)
|
||||
evp_md = self._backend._lib.EVP_get_digestbyname(
|
||||
algorithm.name.encode("ascii"))
|
||||
if evp_md == self._backend._ffi.NULL:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
|
||||
self._backend._ffi.NULL)
|
||||
assert res != 0
|
||||
|
||||
self._ctx = ctx
|
||||
|
||||
def copy(self):
|
||||
copied_ctx = self._backend._lib.EVP_MD_CTX_create()
|
||||
copied_ctx = self._backend._ffi.gc(
|
||||
copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
|
||||
)
|
||||
res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
|
||||
assert res != 0
|
||||
return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
|
||||
|
||||
def update(self, data):
|
||||
res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data))
|
||||
assert res != 0
|
||||
|
||||
def finalize(self):
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
self._backend._lib.EVP_MAX_MD_SIZE)
|
||||
outlen = self._backend._ffi.new("unsigned int *")
|
||||
res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
|
||||
assert res != 0
|
||||
assert outlen[0] == self.algorithm.digest_size
|
||||
res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
|
||||
assert res == 1
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.HashContext)
|
||||
class _HMACContext(object):
|
||||
def __init__(self, backend, key, algorithm, ctx=None):
|
||||
self.algorithm = algorithm
|
||||
self._backend = backend
|
||||
|
||||
if ctx is None:
|
||||
ctx = self._backend._ffi.new("HMAC_CTX *")
|
||||
self._backend._lib.HMAC_CTX_init(ctx)
|
||||
ctx = self._backend._ffi.gc(
|
||||
ctx, self._backend._lib.HMAC_CTX_cleanup
|
||||
)
|
||||
evp_md = self._backend._lib.EVP_get_digestbyname(
|
||||
algorithm.name.encode('ascii'))
|
||||
if evp_md == self._backend._ffi.NULL:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not a supported hash on this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
res = self._backend._lib.Cryptography_HMAC_Init_ex(
|
||||
ctx, key, len(key), evp_md, self._backend._ffi.NULL
|
||||
)
|
||||
assert res != 0
|
||||
|
||||
self._ctx = ctx
|
||||
self._key = key
|
||||
|
||||
def copy(self):
|
||||
copied_ctx = self._backend._ffi.new("HMAC_CTX *")
|
||||
self._backend._lib.HMAC_CTX_init(copied_ctx)
|
||||
copied_ctx = self._backend._ffi.gc(
|
||||
copied_ctx, self._backend._lib.HMAC_CTX_cleanup
|
||||
)
|
||||
res = self._backend._lib.Cryptography_HMAC_CTX_copy(
|
||||
copied_ctx, self._ctx
|
||||
)
|
||||
assert res != 0
|
||||
return _HMACContext(
|
||||
self._backend, self._key, self.algorithm, ctx=copied_ctx
|
||||
)
|
||||
|
||||
def update(self, data):
|
||||
res = self._backend._lib.Cryptography_HMAC_Update(
|
||||
self._ctx, data, len(data)
|
||||
)
|
||||
assert res != 0
|
||||
|
||||
def finalize(self):
|
||||
buf = self._backend._ffi.new("unsigned char[]",
|
||||
self._backend._lib.EVP_MAX_MD_SIZE)
|
||||
outlen = self._backend._ffi.new("unsigned int *")
|
||||
res = self._backend._lib.Cryptography_HMAC_Final(
|
||||
self._ctx, buf, outlen
|
||||
)
|
||||
assert res != 0
|
||||
assert outlen[0] == self.algorithm.digest_size
|
||||
self._backend._lib.HMAC_CTX_cleanup(self._ctx)
|
||||
return self._backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
|
@ -0,0 +1,603 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import math
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
|
||||
)
|
||||
from cryptography.hazmat.primitives import hashes, interfaces
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
from cryptography.hazmat.primitives.asymmetric.padding import (
|
||||
MGF1, OAEP, PKCS1v15, PSS
|
||||
)
|
||||
from cryptography.hazmat.primitives.interfaces import (
|
||||
RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
|
||||
)
|
||||
|
||||
|
||||
def _get_rsa_pss_salt_length(pss, key_size, digest_size):
|
||||
if pss._mgf._salt_length is not None:
|
||||
salt = pss._mgf._salt_length
|
||||
else:
|
||||
salt = pss._salt_length
|
||||
|
||||
if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH:
|
||||
# bit length - 1 per RFC 3447
|
||||
emlen = int(math.ceil((key_size - 1) / 8.0))
|
||||
salt_length = emlen - digest_size - 2
|
||||
assert salt_length >= 0
|
||||
return salt_length
|
||||
else:
|
||||
return salt
|
||||
|
||||
|
||||
def _enc_dec_rsa(backend, key, data, padding):
|
||||
if isinstance(padding, PKCS1v15):
|
||||
padding_enum = backend._lib.RSA_PKCS1_PADDING
|
||||
elif isinstance(padding, OAEP):
|
||||
padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING
|
||||
if not isinstance(padding._mgf, MGF1):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Only MGF1 is supported by this backend.",
|
||||
_Reasons.UNSUPPORTED_MGF
|
||||
)
|
||||
|
||||
if not isinstance(padding._mgf._algorithm, hashes.SHA1):
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend supports only SHA1 inside MGF1 when "
|
||||
"using OAEP.",
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
||||
if padding._label is not None and padding._label != b"":
|
||||
raise ValueError("This backend does not support OAEP labels.")
|
||||
|
||||
if not isinstance(padding._algorithm, hashes.SHA1):
|
||||
raise UnsupportedAlgorithm(
|
||||
"This backend only supports SHA1 when using OAEP.",
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
else:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not supported by this backend.".format(
|
||||
padding.name
|
||||
),
|
||||
_Reasons.UNSUPPORTED_PADDING
|
||||
)
|
||||
|
||||
if backend._lib.Cryptography_HAS_PKEY_CTX:
|
||||
return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum)
|
||||
else:
|
||||
return _enc_dec_rsa_098(backend, key, data, padding_enum)
|
||||
|
||||
|
||||
def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum):
|
||||
if isinstance(key, _RSAPublicKey):
|
||||
init = backend._lib.EVP_PKEY_encrypt_init
|
||||
crypt = backend._lib.Cryptography_EVP_PKEY_encrypt
|
||||
else:
|
||||
init = backend._lib.EVP_PKEY_decrypt_init
|
||||
crypt = backend._lib.Cryptography_EVP_PKEY_decrypt
|
||||
|
||||
pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
|
||||
key._evp_pkey, backend._ffi.NULL
|
||||
)
|
||||
assert pkey_ctx != backend._ffi.NULL
|
||||
pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
|
||||
res = init(pkey_ctx)
|
||||
assert res == 1
|
||||
res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
|
||||
pkey_ctx, padding_enum)
|
||||
assert res > 0
|
||||
buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
|
||||
assert buf_size > 0
|
||||
outlen = backend._ffi.new("size_t *", buf_size)
|
||||
buf = backend._ffi.new("char[]", buf_size)
|
||||
res = crypt(pkey_ctx, buf, outlen, data, len(data))
|
||||
if res <= 0:
|
||||
_handle_rsa_enc_dec_error(backend, key)
|
||||
|
||||
return backend._ffi.buffer(buf)[:outlen[0]]
|
||||
|
||||
|
||||
def _enc_dec_rsa_098(backend, key, data, padding_enum):
|
||||
if isinstance(key, _RSAPublicKey):
|
||||
crypt = backend._lib.RSA_public_encrypt
|
||||
else:
|
||||
crypt = backend._lib.RSA_private_decrypt
|
||||
|
||||
key_size = backend._lib.RSA_size(key._rsa_cdata)
|
||||
assert key_size > 0
|
||||
buf = backend._ffi.new("unsigned char[]", key_size)
|
||||
res = crypt(len(data), data, buf, key._rsa_cdata, padding_enum)
|
||||
if res < 0:
|
||||
_handle_rsa_enc_dec_error(backend, key)
|
||||
|
||||
return backend._ffi.buffer(buf)[:res]
|
||||
|
||||
|
||||
def _handle_rsa_enc_dec_error(backend, key):
|
||||
errors = backend._consume_errors()
|
||||
assert errors
|
||||
assert errors[0].lib == backend._lib.ERR_LIB_RSA
|
||||
if isinstance(key, _RSAPublicKey):
|
||||
assert (errors[0].reason ==
|
||||
backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
|
||||
raise ValueError(
|
||||
"Data too long for key size. Encrypt less data or use a "
|
||||
"larger key size."
|
||||
)
|
||||
else:
|
||||
assert (
|
||||
errors[0].reason == backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
|
||||
errors[0].reason == backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
|
||||
)
|
||||
raise ValueError("Decryption failed.")
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AsymmetricSignatureContext)
|
||||
class _RSASignatureContext(object):
|
||||
def __init__(self, backend, private_key, padding, algorithm):
|
||||
self._backend = backend
|
||||
self._private_key = private_key
|
||||
|
||||
if not isinstance(padding, interfaces.AsymmetricPadding):
|
||||
raise TypeError(
|
||||
"Expected provider of interfaces.AsymmetricPadding.")
|
||||
|
||||
self._pkey_size = self._backend._lib.EVP_PKEY_size(
|
||||
self._private_key._evp_pkey
|
||||
)
|
||||
|
||||
if isinstance(padding, PKCS1v15):
|
||||
if self._backend._lib.Cryptography_HAS_PKEY_CTX:
|
||||
self._finalize_method = self._finalize_pkey_ctx
|
||||
self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
|
||||
else:
|
||||
self._finalize_method = self._finalize_pkcs1
|
||||
elif isinstance(padding, PSS):
|
||||
if not isinstance(padding._mgf, MGF1):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Only MGF1 is supported by this backend.",
|
||||
_Reasons.UNSUPPORTED_MGF
|
||||
)
|
||||
|
||||
# Size of key in bytes - 2 is the maximum
|
||||
# PSS signature length (salt length is checked later)
|
||||
assert self._pkey_size > 0
|
||||
if self._pkey_size - algorithm.digest_size - 2 < 0:
|
||||
raise ValueError("Digest too large for key size. Use a larger "
|
||||
"key.")
|
||||
|
||||
if not self._backend._mgf1_hash_supported(padding._mgf._algorithm):
|
||||
raise UnsupportedAlgorithm(
|
||||
"When OpenSSL is older than 1.0.1 then only SHA1 is "
|
||||
"supported with MGF1.",
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
||||
if self._backend._lib.Cryptography_HAS_PKEY_CTX:
|
||||
self._finalize_method = self._finalize_pkey_ctx
|
||||
self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
|
||||
else:
|
||||
self._finalize_method = self._finalize_pss
|
||||
else:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not supported by this backend.".format(padding.name),
|
||||
_Reasons.UNSUPPORTED_PADDING
|
||||
)
|
||||
|
||||
self._padding = padding
|
||||
self._algorithm = algorithm
|
||||
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
|
||||
|
||||
def update(self, data):
|
||||
self._hash_ctx.update(data)
|
||||
|
||||
def finalize(self):
|
||||
evp_md = self._backend._lib.EVP_get_digestbyname(
|
||||
self._algorithm.name.encode("ascii"))
|
||||
assert evp_md != self._backend._ffi.NULL
|
||||
|
||||
return self._finalize_method(evp_md)
|
||||
|
||||
def _finalize_pkey_ctx(self, evp_md):
|
||||
pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
|
||||
self._private_key._evp_pkey, self._backend._ffi.NULL
|
||||
)
|
||||
assert pkey_ctx != self._backend._ffi.NULL
|
||||
pkey_ctx = self._backend._ffi.gc(pkey_ctx,
|
||||
self._backend._lib.EVP_PKEY_CTX_free)
|
||||
res = self._backend._lib.EVP_PKEY_sign_init(pkey_ctx)
|
||||
assert res == 1
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
|
||||
pkey_ctx, evp_md)
|
||||
assert res > 0
|
||||
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
|
||||
pkey_ctx, self._padding_enum)
|
||||
assert res > 0
|
||||
if isinstance(self._padding, PSS):
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
|
||||
pkey_ctx,
|
||||
_get_rsa_pss_salt_length(
|
||||
self._padding,
|
||||
self._private_key.key_size,
|
||||
self._hash_ctx.algorithm.digest_size
|
||||
)
|
||||
)
|
||||
assert res > 0
|
||||
|
||||
if self._backend._lib.Cryptography_HAS_MGF1_MD:
|
||||
# MGF1 MD is configurable in OpenSSL 1.0.1+
|
||||
mgf1_md = self._backend._lib.EVP_get_digestbyname(
|
||||
self._padding._mgf._algorithm.name.encode("ascii"))
|
||||
assert mgf1_md != self._backend._ffi.NULL
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
|
||||
pkey_ctx, mgf1_md
|
||||
)
|
||||
assert res > 0
|
||||
data_to_sign = self._hash_ctx.finalize()
|
||||
buflen = self._backend._ffi.new("size_t *")
|
||||
res = self._backend._lib.EVP_PKEY_sign(
|
||||
pkey_ctx,
|
||||
self._backend._ffi.NULL,
|
||||
buflen,
|
||||
data_to_sign,
|
||||
len(data_to_sign)
|
||||
)
|
||||
assert res == 1
|
||||
buf = self._backend._ffi.new("unsigned char[]", buflen[0])
|
||||
res = self._backend._lib.EVP_PKEY_sign(
|
||||
pkey_ctx, buf, buflen, data_to_sign, len(data_to_sign))
|
||||
if res != 1:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
|
||||
reason = None
|
||||
if (errors[0].reason ==
|
||||
self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE):
|
||||
reason = ("Salt length too long for key size. Try using "
|
||||
"MAX_LENGTH instead.")
|
||||
elif (errors[0].reason ==
|
||||
self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY):
|
||||
reason = "Digest too large for key size. Use a larger key."
|
||||
assert reason is not None
|
||||
raise ValueError(reason)
|
||||
|
||||
return self._backend._ffi.buffer(buf)[:]
|
||||
|
||||
def _finalize_pkcs1(self, evp_md):
|
||||
if self._hash_ctx._ctx is None:
|
||||
raise AlreadyFinalized("Context has already been finalized.")
|
||||
|
||||
sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
|
||||
sig_len = self._backend._ffi.new("unsigned int *")
|
||||
res = self._backend._lib.EVP_SignFinal(
|
||||
self._hash_ctx._ctx._ctx,
|
||||
sig_buf,
|
||||
sig_len,
|
||||
self._private_key._evp_pkey
|
||||
)
|
||||
self._hash_ctx.finalize()
|
||||
if res == 0:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
|
||||
assert (errors[0].reason ==
|
||||
self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
|
||||
raise ValueError("Digest too large for key size. Use a larger "
|
||||
"key.")
|
||||
|
||||
return self._backend._ffi.buffer(sig_buf)[:sig_len[0]]
|
||||
|
||||
def _finalize_pss(self, evp_md):
|
||||
data_to_sign = self._hash_ctx.finalize()
|
||||
padded = self._backend._ffi.new("unsigned char[]", self._pkey_size)
|
||||
res = self._backend._lib.RSA_padding_add_PKCS1_PSS(
|
||||
self._private_key._rsa_cdata,
|
||||
padded,
|
||||
data_to_sign,
|
||||
evp_md,
|
||||
_get_rsa_pss_salt_length(
|
||||
self._padding,
|
||||
self._private_key.key_size,
|
||||
len(data_to_sign)
|
||||
)
|
||||
)
|
||||
if res != 1:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
|
||||
assert (errors[0].reason ==
|
||||
self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
|
||||
raise ValueError("Salt length too long for key size. Try using "
|
||||
"MAX_LENGTH instead.")
|
||||
|
||||
sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
|
||||
sig_len = self._backend._lib.RSA_private_encrypt(
|
||||
self._pkey_size,
|
||||
padded,
|
||||
sig_buf,
|
||||
self._private_key._rsa_cdata,
|
||||
self._backend._lib.RSA_NO_PADDING
|
||||
)
|
||||
assert sig_len != -1
|
||||
return self._backend._ffi.buffer(sig_buf)[:sig_len]
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.AsymmetricVerificationContext)
|
||||
class _RSAVerificationContext(object):
|
||||
def __init__(self, backend, public_key, signature, padding, algorithm):
|
||||
self._backend = backend
|
||||
self._public_key = public_key
|
||||
self._signature = signature
|
||||
|
||||
if not isinstance(padding, interfaces.AsymmetricPadding):
|
||||
raise TypeError(
|
||||
"Expected provider of interfaces.AsymmetricPadding.")
|
||||
|
||||
self._pkey_size = self._backend._lib.EVP_PKEY_size(
|
||||
self._public_key._evp_pkey
|
||||
)
|
||||
|
||||
if isinstance(padding, PKCS1v15):
|
||||
if self._backend._lib.Cryptography_HAS_PKEY_CTX:
|
||||
self._verify_method = self._verify_pkey_ctx
|
||||
self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
|
||||
else:
|
||||
self._verify_method = self._verify_pkcs1
|
||||
elif isinstance(padding, PSS):
|
||||
if not isinstance(padding._mgf, MGF1):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Only MGF1 is supported by this backend.",
|
||||
_Reasons.UNSUPPORTED_MGF
|
||||
)
|
||||
|
||||
# Size of key in bytes - 2 is the maximum
|
||||
# PSS signature length (salt length is checked later)
|
||||
assert self._pkey_size > 0
|
||||
if self._pkey_size - algorithm.digest_size - 2 < 0:
|
||||
raise ValueError(
|
||||
"Digest too large for key size. Check that you have the "
|
||||
"correct key and digest algorithm."
|
||||
)
|
||||
|
||||
if not self._backend._mgf1_hash_supported(padding._mgf._algorithm):
|
||||
raise UnsupportedAlgorithm(
|
||||
"When OpenSSL is older than 1.0.1 then only SHA1 is "
|
||||
"supported with MGF1.",
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
|
||||
if self._backend._lib.Cryptography_HAS_PKEY_CTX:
|
||||
self._verify_method = self._verify_pkey_ctx
|
||||
self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
|
||||
else:
|
||||
self._verify_method = self._verify_pss
|
||||
else:
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not supported by this backend.".format(padding.name),
|
||||
_Reasons.UNSUPPORTED_PADDING
|
||||
)
|
||||
|
||||
self._padding = padding
|
||||
self._algorithm = algorithm
|
||||
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
|
||||
|
||||
def update(self, data):
|
||||
self._hash_ctx.update(data)
|
||||
|
||||
def verify(self):
|
||||
evp_md = self._backend._lib.EVP_get_digestbyname(
|
||||
self._algorithm.name.encode("ascii"))
|
||||
assert evp_md != self._backend._ffi.NULL
|
||||
|
||||
self._verify_method(evp_md)
|
||||
|
||||
def _verify_pkey_ctx(self, evp_md):
|
||||
pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
|
||||
self._public_key._evp_pkey, self._backend._ffi.NULL
|
||||
)
|
||||
assert pkey_ctx != self._backend._ffi.NULL
|
||||
pkey_ctx = self._backend._ffi.gc(pkey_ctx,
|
||||
self._backend._lib.EVP_PKEY_CTX_free)
|
||||
res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx)
|
||||
assert res == 1
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
|
||||
pkey_ctx, evp_md)
|
||||
assert res > 0
|
||||
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
|
||||
pkey_ctx, self._padding_enum)
|
||||
assert res > 0
|
||||
if isinstance(self._padding, PSS):
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
|
||||
pkey_ctx,
|
||||
_get_rsa_pss_salt_length(
|
||||
self._padding,
|
||||
self._public_key.key_size,
|
||||
self._hash_ctx.algorithm.digest_size
|
||||
)
|
||||
)
|
||||
assert res > 0
|
||||
if self._backend._lib.Cryptography_HAS_MGF1_MD:
|
||||
# MGF1 MD is configurable in OpenSSL 1.0.1+
|
||||
mgf1_md = self._backend._lib.EVP_get_digestbyname(
|
||||
self._padding._mgf._algorithm.name.encode("ascii"))
|
||||
assert mgf1_md != self._backend._ffi.NULL
|
||||
res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
|
||||
pkey_ctx, mgf1_md
|
||||
)
|
||||
assert res > 0
|
||||
|
||||
data_to_verify = self._hash_ctx.finalize()
|
||||
res = self._backend._lib.EVP_PKEY_verify(
|
||||
pkey_ctx,
|
||||
self._signature,
|
||||
len(self._signature),
|
||||
data_to_verify,
|
||||
len(data_to_verify)
|
||||
)
|
||||
# The previous call can return negative numbers in the event of an
|
||||
# error. This is not a signature failure but we need to fail if it
|
||||
# occurs.
|
||||
assert res >= 0
|
||||
if res == 0:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors
|
||||
raise InvalidSignature
|
||||
|
||||
def _verify_pkcs1(self, evp_md):
|
||||
if self._hash_ctx._ctx is None:
|
||||
raise AlreadyFinalized("Context has already been finalized.")
|
||||
|
||||
res = self._backend._lib.EVP_VerifyFinal(
|
||||
self._hash_ctx._ctx._ctx,
|
||||
self._signature,
|
||||
len(self._signature),
|
||||
self._public_key._evp_pkey
|
||||
)
|
||||
self._hash_ctx.finalize()
|
||||
# The previous call can return negative numbers in the event of an
|
||||
# error. This is not a signature failure but we need to fail if it
|
||||
# occurs.
|
||||
assert res >= 0
|
||||
if res == 0:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors
|
||||
raise InvalidSignature
|
||||
|
||||
def _verify_pss(self, evp_md):
|
||||
buf = self._backend._ffi.new("unsigned char[]", self._pkey_size)
|
||||
res = self._backend._lib.RSA_public_decrypt(
|
||||
len(self._signature),
|
||||
self._signature,
|
||||
buf,
|
||||
self._public_key._rsa_cdata,
|
||||
self._backend._lib.RSA_NO_PADDING
|
||||
)
|
||||
if res != self._pkey_size:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors
|
||||
raise InvalidSignature
|
||||
|
||||
data_to_verify = self._hash_ctx.finalize()
|
||||
res = self._backend._lib.RSA_verify_PKCS1_PSS(
|
||||
self._public_key._rsa_cdata,
|
||||
data_to_verify,
|
||||
evp_md,
|
||||
buf,
|
||||
_get_rsa_pss_salt_length(
|
||||
self._padding,
|
||||
self._public_key.key_size,
|
||||
len(data_to_verify)
|
||||
)
|
||||
)
|
||||
if res != 1:
|
||||
errors = self._backend._consume_errors()
|
||||
assert errors
|
||||
raise InvalidSignature
|
||||
|
||||
|
||||
@utils.register_interface(RSAPrivateKeyWithNumbers)
|
||||
class _RSAPrivateKey(object):
|
||||
def __init__(self, backend, rsa_cdata):
|
||||
self._backend = backend
|
||||
self._rsa_cdata = rsa_cdata
|
||||
|
||||
evp_pkey = self._backend._lib.EVP_PKEY_new()
|
||||
assert evp_pkey != self._backend._ffi.NULL
|
||||
evp_pkey = self._backend._ffi.gc(
|
||||
evp_pkey, self._backend._lib.EVP_PKEY_free
|
||||
)
|
||||
res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
|
||||
assert res == 1
|
||||
self._evp_pkey = evp_pkey
|
||||
|
||||
self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return self._key_size
|
||||
|
||||
def signer(self, padding, algorithm):
|
||||
return _RSASignatureContext(self._backend, self, padding, algorithm)
|
||||
|
||||
def decrypt(self, ciphertext, padding):
|
||||
key_size_bytes = int(math.ceil(self.key_size / 8.0))
|
||||
if key_size_bytes != len(ciphertext):
|
||||
raise ValueError("Ciphertext length must be equal to key size.")
|
||||
|
||||
return _enc_dec_rsa(self._backend, self, ciphertext, padding)
|
||||
|
||||
def public_key(self):
|
||||
ctx = self._backend._lib.RSA_new()
|
||||
assert ctx != self._backend._ffi.NULL
|
||||
ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free)
|
||||
ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e)
|
||||
ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n)
|
||||
res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
|
||||
assert res == 1
|
||||
return _RSAPublicKey(self._backend, ctx)
|
||||
|
||||
def private_numbers(self):
|
||||
return rsa.RSAPrivateNumbers(
|
||||
p=self._backend._bn_to_int(self._rsa_cdata.p),
|
||||
q=self._backend._bn_to_int(self._rsa_cdata.q),
|
||||
d=self._backend._bn_to_int(self._rsa_cdata.d),
|
||||
dmp1=self._backend._bn_to_int(self._rsa_cdata.dmp1),
|
||||
dmq1=self._backend._bn_to_int(self._rsa_cdata.dmq1),
|
||||
iqmp=self._backend._bn_to_int(self._rsa_cdata.iqmp),
|
||||
public_numbers=rsa.RSAPublicNumbers(
|
||||
e=self._backend._bn_to_int(self._rsa_cdata.e),
|
||||
n=self._backend._bn_to_int(self._rsa_cdata.n),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@utils.register_interface(RSAPublicKeyWithNumbers)
|
||||
class _RSAPublicKey(object):
|
||||
def __init__(self, backend, rsa_cdata):
|
||||
self._backend = backend
|
||||
self._rsa_cdata = rsa_cdata
|
||||
|
||||
evp_pkey = self._backend._lib.EVP_PKEY_new()
|
||||
assert evp_pkey != self._backend._ffi.NULL
|
||||
evp_pkey = self._backend._ffi.gc(
|
||||
evp_pkey, self._backend._lib.EVP_PKEY_free
|
||||
)
|
||||
res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
|
||||
assert res == 1
|
||||
self._evp_pkey = evp_pkey
|
||||
|
||||
self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return self._key_size
|
||||
|
||||
def verifier(self, signature, padding, algorithm):
|
||||
return _RSAVerificationContext(
|
||||
self._backend, self, signature, padding, algorithm
|
||||
)
|
||||
|
||||
def encrypt(self, plaintext, padding):
|
||||
return _enc_dec_rsa(self._backend, self, plaintext, padding)
|
||||
|
||||
def public_numbers(self):
|
||||
return rsa.RSAPublicNumbers(
|
||||
e=self._backend._bn_to_int(self._rsa_cdata.e),
|
||||
n=self._backend._bn_to_int(self._rsa_cdata.n),
|
||||
)
|
||||
|
|
@ -25,10 +25,16 @@ class Binding(object):
|
|||
"""
|
||||
_module_prefix = "cryptography.hazmat.bindings.commoncrypto."
|
||||
_modules = [
|
||||
"cf",
|
||||
"common_digest",
|
||||
"common_hmac",
|
||||
"common_key_derivation",
|
||||
"common_cryptor",
|
||||
"secimport",
|
||||
"secitem",
|
||||
"seckey",
|
||||
"seckeychain",
|
||||
"sectransform",
|
||||
]
|
||||
|
||||
ffi = None
|
||||
|
|
@ -45,6 +51,7 @@ class Binding(object):
|
|||
cls.ffi, cls.lib = build_ffi(
|
||||
module_prefix=cls._module_prefix,
|
||||
modules=cls._modules,
|
||||
extra_link_args=["-framework", "Security"]
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
typedef bool Boolean;
|
||||
typedef signed long OSStatus;
|
||||
typedef unsigned char UInt8;
|
||||
typedef uint32_t UInt32;
|
||||
|
||||
typedef const void * CFAllocatorRef;
|
||||
const CFAllocatorRef kCFAllocatorDefault;
|
||||
typedef const void * CFDataRef;
|
||||
typedef signed long long CFIndex;
|
||||
typedef ... *CFStringRef;
|
||||
typedef ... *CFArrayRef;
|
||||
typedef ... *CFBooleanRef;
|
||||
typedef ... *CFErrorRef;
|
||||
typedef ... *CFNumberRef;
|
||||
typedef ... *CFTypeRef;
|
||||
typedef ... *CFDictionaryRef;
|
||||
typedef ... *CFMutableDictionaryRef;
|
||||
typedef struct {
|
||||
...;
|
||||
} CFDictionaryKeyCallBacks;
|
||||
typedef struct {
|
||||
...;
|
||||
} CFDictionaryValueCallBacks;
|
||||
typedef struct {
|
||||
...;
|
||||
} CFRange;
|
||||
|
||||
typedef UInt32 CFStringEncoding;
|
||||
enum {
|
||||
kCFStringEncodingASCII = 0x0600
|
||||
};
|
||||
|
||||
enum {
|
||||
kCFNumberSInt8Type = 1,
|
||||
kCFNumberSInt16Type = 2,
|
||||
kCFNumberSInt32Type = 3,
|
||||
kCFNumberSInt64Type = 4,
|
||||
kCFNumberFloat32Type = 5,
|
||||
kCFNumberFloat64Type = 6,
|
||||
kCFNumberCharType = 7,
|
||||
kCFNumberShortType = 8,
|
||||
kCFNumberIntType = 9,
|
||||
kCFNumberLongType = 10,
|
||||
kCFNumberLongLongType = 11,
|
||||
kCFNumberFloatType = 12,
|
||||
kCFNumberDoubleType = 13,
|
||||
kCFNumberCFIndexType = 14,
|
||||
kCFNumberNSIntegerType = 15,
|
||||
kCFNumberCGFloatType = 16,
|
||||
kCFNumberMaxType = 16
|
||||
};
|
||||
typedef int CFNumberType;
|
||||
|
||||
const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
|
||||
const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
|
||||
|
||||
const CFBooleanRef kCFBooleanTrue;
|
||||
const CFBooleanRef kCFBooleanFalse;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
CFDataRef CFDataCreate(CFAllocatorRef, const UInt8 *, CFIndex);
|
||||
CFStringRef CFStringCreateWithCString(CFAllocatorRef, const char *,
|
||||
CFStringEncoding);
|
||||
CFDictionaryRef CFDictionaryCreate(CFAllocatorRef, const void **,
|
||||
const void **, CFIndex,
|
||||
const CFDictionaryKeyCallBacks *,
|
||||
const CFDictionaryValueCallBacks *);
|
||||
CFMutableDictionaryRef CFDictionaryCreateMutable(
|
||||
CFAllocatorRef,
|
||||
CFIndex,
|
||||
const CFDictionaryKeyCallBacks *,
|
||||
const CFDictionaryValueCallBacks *
|
||||
);
|
||||
void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *);
|
||||
CFIndex CFArrayGetCount(CFArrayRef);
|
||||
const void *CFArrayGetValueAtIndex(CFArrayRef, CFIndex);
|
||||
CFIndex CFDataGetLength(CFDataRef);
|
||||
void CFDataGetBytes(CFDataRef, CFRange, UInt8 *);
|
||||
CFRange CFRangeMake(CFIndex, CFIndex);
|
||||
void CFShow(CFTypeRef);
|
||||
Boolean CFBooleanGetValue(CFBooleanRef);
|
||||
CFNumberRef CFNumberCreate(CFAllocatorRef, CFNumberType, const void *);
|
||||
void CFRelease(CFTypeRef);
|
||||
CFTypeRef CFRetain(CFTypeRef);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {}
|
||||
|
|
@ -101,7 +101,7 @@ MACROS = """
|
|||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
// Not defined in the public header
|
||||
/* Not defined in the public header */
|
||||
enum {
|
||||
kCCModeGCM = 11
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <Security/SecImportExport.h>
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
typedef ... *SecAccessRef;
|
||||
|
||||
CFStringRef kSecImportExportPassphrase;
|
||||
CFStringRef kSecImportExportKeychain;
|
||||
CFStringRef kSecImportExportAccess;
|
||||
|
||||
typedef uint32_t SecExternalItemType;
|
||||
enum {
|
||||
kSecItemTypeUnknown,
|
||||
kSecItemTypePrivateKey,
|
||||
kSecItemTypePublicKey,
|
||||
kSecItemTypeSessionKey,
|
||||
kSecItemTypeCertificate,
|
||||
kSecItemTypeAggregate
|
||||
};
|
||||
|
||||
|
||||
typedef uint32_t SecExternalFormat;
|
||||
enum {
|
||||
kSecFormatUnknown = 0,
|
||||
kSecFormatOpenSSL,
|
||||
kSecFormatSSH,
|
||||
kSecFormatBSAFE,
|
||||
kSecFormatRawKey,
|
||||
kSecFormatWrappedPKCS8,
|
||||
kSecFormatWrappedOpenSSL,
|
||||
kSecFormatWrappedSSH,
|
||||
kSecFormatWrappedLSH,
|
||||
kSecFormatX509Cert,
|
||||
kSecFormatPEMSequence,
|
||||
kSecFormatPKCS7,
|
||||
kSecFormatPKCS12,
|
||||
kSecFormatNetscapeCertSequence,
|
||||
kSecFormatSSHv2
|
||||
};
|
||||
|
||||
typedef uint32_t SecItemImportExportFlags;
|
||||
enum {
|
||||
kSecKeyImportOnlyOne = 0x00000001,
|
||||
kSecKeySecurePassphrase = 0x00000002,
|
||||
kSecKeyNoAccessControl = 0x00000004
|
||||
};
|
||||
typedef uint32_t SecKeyImportExportFlags;
|
||||
|
||||
typedef struct {
|
||||
/* for import and export */
|
||||
uint32_t version;
|
||||
SecKeyImportExportFlags flags;
|
||||
CFTypeRef passphrase;
|
||||
CFStringRef alertTitle;
|
||||
CFStringRef alertPrompt;
|
||||
|
||||
/* for import only */
|
||||
SecAccessRef accessRef;
|
||||
CFArrayRef keyUsage;
|
||||
|
||||
CFArrayRef keyAttributes;
|
||||
} SecItemImportExportKeyParameters;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
OSStatus SecItemImport(CFDataRef, CFStringRef, SecExternalFormat *,
|
||||
SecExternalItemType *, SecItemImportExportFlags,
|
||||
const SecItemImportExportKeyParameters *,
|
||||
SecKeychainRef, CFArrayRef *);
|
||||
OSStatus SecPKCS12Import(CFDataRef, CFDictionaryRef, CFArrayRef *);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <Security/SecItem.h>
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
const CFTypeRef kSecAttrKeyType;
|
||||
const CFTypeRef kSecAttrKeySizeInBits;
|
||||
const CFTypeRef kSecAttrIsPermanent;
|
||||
const CFTypeRef kSecAttrKeyTypeRSA;
|
||||
const CFTypeRef kSecAttrKeyTypeDSA;
|
||||
const CFTypeRef kSecUseKeychain;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <Security/SecKey.h>
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
typedef ... *SecKeyRef;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
OSStatus SecKeyGeneratePair(CFDictionaryRef, SecKeyRef *, SecKeyRef *);
|
||||
size_t SecKeyGetBlockSize(SecKeyRef);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <Security/SecKeychain.h>
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
typedef ... *SecKeychainRef;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
OSStatus SecKeychainCreate(const char *, UInt32, const void *, Boolean,
|
||||
SecAccessRef, SecKeychainRef *);
|
||||
OSStatus SecKeychainDelete(SecKeychainRef);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <Security/SecDigestTransform.h>
|
||||
#include <Security/SecSignVerifyTransform.h>
|
||||
#include <Security/SecEncryptTransform.h>
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
typedef ... *SecTransformRef;
|
||||
|
||||
CFStringRef kSecImportExportPassphrase;
|
||||
CFStringRef kSecImportExportKeychain;
|
||||
CFStringRef kSecImportExportAccess;
|
||||
|
||||
CFStringRef kSecEncryptionMode;
|
||||
CFStringRef kSecEncryptKey;
|
||||
CFStringRef kSecIVKey;
|
||||
CFStringRef kSecModeCBCKey;
|
||||
CFStringRef kSecModeCFBKey;
|
||||
CFStringRef kSecModeECBKey;
|
||||
CFStringRef kSecModeNoneKey;
|
||||
CFStringRef kSecModeOFBKey;
|
||||
CFStringRef kSecOAEPEncodingParametersAttributeName;
|
||||
CFStringRef kSecPaddingKey;
|
||||
CFStringRef kSecPaddingNoneKey;
|
||||
CFStringRef kSecPaddingOAEPKey;
|
||||
CFStringRef kSecPaddingPKCS1Key;
|
||||
CFStringRef kSecPaddingPKCS5Key;
|
||||
CFStringRef kSecPaddingPKCS7Key;
|
||||
|
||||
const CFStringRef kSecTransformInputAttributeName;
|
||||
const CFStringRef kSecTransformOutputAttributeName;
|
||||
const CFStringRef kSecTransformDebugAttributeName;
|
||||
const CFStringRef kSecTransformTransformName;
|
||||
const CFStringRef kSecTransformAbortAttributeName;
|
||||
|
||||
CFStringRef kSecInputIsAttributeName;
|
||||
CFStringRef kSecInputIsPlainText;
|
||||
CFStringRef kSecInputIsDigest;
|
||||
CFStringRef kSecInputIsRaw;
|
||||
|
||||
const CFStringRef kSecDigestTypeAttribute;
|
||||
const CFStringRef kSecDigestLengthAttribute;
|
||||
const CFStringRef kSecDigestMD5;
|
||||
const CFStringRef kSecDigestSHA1;
|
||||
const CFStringRef kSecDigestSHA2;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
Boolean SecTransformSetAttribute(SecTransformRef, CFStringRef, CFTypeRef,
|
||||
CFErrorRef *);
|
||||
SecTransformRef SecDecryptTransformCreate(SecKeyRef, CFErrorRef *);
|
||||
SecTransformRef SecEncryptTransformCreate(SecKeyRef, CFErrorRef *);
|
||||
SecTransformRef SecVerifyTransformCreate(SecKeyRef, CFDataRef, CFErrorRef *);
|
||||
SecTransformRef SecSignTransformCreate(SecKeyRef, CFErrorRef *) ;
|
||||
CFTypeRef SecTransformExecute(SecTransformRef, CFErrorRef *);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {}
|
||||
|
|
@ -38,10 +38,18 @@ int AES_wrap_key(AES_KEY *, const unsigned char *, unsigned char *,
|
|||
const unsigned char *, unsigned int);
|
||||
int AES_unwrap_key(AES_KEY *, const unsigned char *, unsigned char *,
|
||||
const unsigned char *, unsigned int);
|
||||
|
||||
/* The ctr128_encrypt function is only useful in 0.9.8. You should use EVP for
|
||||
this in 1.0.0+. It is defined in macros because the function signature
|
||||
changed after 0.9.8 */
|
||||
void AES_ctr128_encrypt(const unsigned char *, unsigned char *,
|
||||
const size_t, const AES_KEY *,
|
||||
unsigned char[], unsigned char[], unsigned int *);
|
||||
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
// OpenSSL 0.9.8h+
|
||||
/* OpenSSL 0.9.8h+ */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
|
||||
static const long Cryptography_HAS_AES_WRAP = 1;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *, ASN1_INTEGER *);
|
|||
|
||||
/* These isn't a macro the arg is const on openssl 1.0.2+ */
|
||||
int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *);
|
||||
|
||||
/* Not a macro, const on openssl 1.0 */
|
||||
int ASN1_STRING_set_default_mask_asc(char *);
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import os
|
||||
import sys
|
||||
import threading
|
||||
|
||||
|
|
@ -74,6 +75,7 @@ class Binding(object):
|
|||
"x509",
|
||||
"x509name",
|
||||
"x509v3",
|
||||
"x509_vfy"
|
||||
]
|
||||
|
||||
_locks = None
|
||||
|
|
@ -96,7 +98,8 @@ class Binding(object):
|
|||
if sys.platform != "win32":
|
||||
libraries = ["crypto", "ssl"]
|
||||
else: # pragma: no cover
|
||||
libraries = ["libeay32", "ssleay32", "advapi32"]
|
||||
link_type = os.environ.get("PYCA_WINDOWS_LINK_TYPE", "static")
|
||||
libraries = _get_windows_libraries(link_type)
|
||||
|
||||
cls.ffi, cls.lib = build_ffi(
|
||||
module_prefix=cls._module_prefix,
|
||||
|
|
@ -149,7 +152,19 @@ class Binding(object):
|
|||
lock.release()
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Unknown lock mode {0}: lock={1}, file={2}, line={3}".format(
|
||||
"Unknown lock mode {0}: lock={1}, file={2}, line={3}.".format(
|
||||
mode, n, file, line
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _get_windows_libraries(link_type):
|
||||
if link_type == "dynamic":
|
||||
return ["libeay32", "ssleay32", "advapi32"]
|
||||
elif link_type == "static" or link_type == "":
|
||||
return ["libeay32mt", "ssleay32mt", "advapi32",
|
||||
"crypt32", "gdi32", "user32", "ws2_32"]
|
||||
else:
|
||||
raise ValueError(
|
||||
"PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ from __future__ import absolute_import, division, print_function
|
|||
|
||||
INCLUDES = """
|
||||
#if !defined(OPENSSL_NO_CMS) && OPENSSL_VERSION_NUMBER >= 0x0090808fL
|
||||
// The next define should really be in the OpenSSL header, but it is missing.
|
||||
// Failing to include this on Windows causes compilation failures.
|
||||
/* The next define should really be in the OpenSSL header, but it is missing.
|
||||
Failing to include this on Windows causes compilation failures. */
|
||||
#if defined(OPENSSL_SYS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ typedef ... CONF;
|
|||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
void OPENSSL_config(const char *);
|
||||
void OPENSSL_no_config(void);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
|
|
|
|||
|
|
@ -19,13 +19,13 @@ INCLUDES = """
|
|||
|
||||
TYPES = """
|
||||
typedef struct dh_st {
|
||||
// prime number (shared)
|
||||
/* Prime number (shared) */
|
||||
BIGNUM *p;
|
||||
// generator of Z_p (shared)
|
||||
/* Generator of Z_p (shared) */
|
||||
BIGNUM *g;
|
||||
// private DH value x
|
||||
/* Private DH value x */
|
||||
BIGNUM *priv_key;
|
||||
// public DH value g^x
|
||||
/* Public DH value g^x */
|
||||
BIGNUM *pub_key;
|
||||
...;
|
||||
} DH;
|
||||
|
|
|
|||
|
|
@ -19,15 +19,15 @@ INCLUDES = """
|
|||
|
||||
TYPES = """
|
||||
typedef struct dsa_st {
|
||||
// prime number (public)
|
||||
/* Prime number (public) */
|
||||
BIGNUM *p;
|
||||
// 160-bit subprime, q | p-1 (public)
|
||||
/* Subprime (160-bit, q | p-1, public) */
|
||||
BIGNUM *q;
|
||||
// generator of subgroup (public)
|
||||
/* Generator of subgroup (public) */
|
||||
BIGNUM *g;
|
||||
// private key x
|
||||
/* Private key x */
|
||||
BIGNUM *priv_key;
|
||||
// public key y = g^x
|
||||
/* Public key y = g^x */
|
||||
BIGNUM *pub_key;
|
||||
...;
|
||||
} DSA;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ static const int Cryptography_HAS_EC_1_0_1;
|
|||
static const int Cryptography_HAS_EC_NISTP_64_GCC_128;
|
||||
static const int Cryptography_HAS_EC2M;
|
||||
|
||||
static const int OPENSSL_EC_NAMED_CURVE;
|
||||
|
||||
typedef ... EC_KEY;
|
||||
typedef ... EC_GROUP;
|
||||
typedef ... EC_POINT;
|
||||
|
|
@ -61,6 +63,8 @@ int EC_GROUP_set_curve_GF2m(
|
|||
int EC_GROUP_get_curve_GF2m(
|
||||
const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
|
||||
|
||||
int EC_GROUP_get_degree(const EC_GROUP *);
|
||||
|
||||
const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
|
||||
const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
|
||||
int EC_GROUP_get_curve_name(const EC_GROUP *);
|
||||
|
|
@ -198,6 +202,7 @@ int EC_METHOD_get_field_type(const EC_METHOD *);
|
|||
CUSTOMIZATIONS = """
|
||||
#ifdef OPENSSL_NO_EC
|
||||
static const long Cryptography_HAS_EC = 0;
|
||||
|
||||
typedef void EC_KEY;
|
||||
typedef void EC_GROUP;
|
||||
typedef void EC_POINT;
|
||||
|
|
@ -208,6 +213,8 @@ typedef struct {
|
|||
} EC_builtin_curve;
|
||||
typedef long point_conversion_form_t;
|
||||
|
||||
static const int OPENSSL_EC_NAMED_CURVE = 0;
|
||||
|
||||
void (*EC_KEY_free)(EC_KEY *) = NULL;
|
||||
size_t (*EC_get_builtin_curves)(EC_builtin_curve *, size_t) = NULL;
|
||||
EC_KEY *(*EC_KEY_new_by_curve_name)(int) = NULL;
|
||||
|
|
@ -250,6 +257,8 @@ int (*EC_GROUP_set_curve_GFp)(
|
|||
int (*EC_GROUP_get_curve_GFp)(
|
||||
const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
|
||||
|
||||
int (*EC_GROUP_get_degree)(const EC_GROUP *) = NULL;
|
||||
|
||||
const EC_METHOD *(*EC_GROUP_method_of)(const EC_GROUP *) = NULL;
|
||||
const EC_POINT *(*EC_GROUP_get0_generator)(const EC_GROUP *) = NULL;
|
||||
int (*EC_GROUP_get_curve_name)(const EC_GROUP *) = NULL;
|
||||
|
|
@ -389,6 +398,7 @@ static const long Cryptography_HAS_EC2M = 1;
|
|||
|
||||
CONDITIONAL_NAMES = {
|
||||
"Cryptography_HAS_EC": [
|
||||
"OPENSSL_EC_NAMED_CURVE",
|
||||
"EC_GROUP_new",
|
||||
"EC_GROUP_free",
|
||||
"EC_GROUP_clear_free",
|
||||
|
|
@ -399,6 +409,7 @@ CONDITIONAL_NAMES = {
|
|||
"EC_GROUP_method_of",
|
||||
"EC_GROUP_get0_generator",
|
||||
"EC_GROUP_get_curve_name",
|
||||
"EC_GROUP_get_degree",
|
||||
"EC_KEY_free",
|
||||
"EC_get_builtin_curves",
|
||||
"EC_KEY_new_by_curve_name",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ TYPES = """
|
|||
static const int Cryptography_HAS_REMOVE_THREAD_STATE;
|
||||
static const int Cryptography_HAS_098H_ERROR_CODES;
|
||||
static const int Cryptography_HAS_098C_CAMELLIA_CODES;
|
||||
static const int Cryptography_HAS_EC_CODES;
|
||||
|
||||
struct ERR_string_data_st {
|
||||
unsigned long error;
|
||||
|
|
@ -28,8 +29,8 @@ struct ERR_string_data_st {
|
|||
};
|
||||
typedef struct ERR_string_data_st ERR_STRING_DATA;
|
||||
|
||||
|
||||
static const int ERR_LIB_EVP;
|
||||
static const int ERR_LIB_EC;
|
||||
static const int ERR_LIB_PEM;
|
||||
static const int ERR_LIB_ASN1;
|
||||
static const int ERR_LIB_RSA;
|
||||
|
|
@ -135,6 +136,7 @@ static const int EVP_F_PKCS5_V2_PBE_KEYIVGEN;
|
|||
static const int EVP_F_PKCS8_SET_BROKEN;
|
||||
static const int EVP_F_RC2_MAGIC_TO_METH;
|
||||
static const int EVP_F_RC5_CTRL;
|
||||
|
||||
static const int EVP_R_AES_KEY_SETUP_FAILED;
|
||||
static const int EVP_R_ASN1_LIB;
|
||||
static const int EVP_R_BAD_BLOCK_LENGTH;
|
||||
|
|
@ -168,9 +170,14 @@ static const int EVP_R_UNSUPPORTED_CIPHER;
|
|||
static const int EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION;
|
||||
static const int EVP_R_UNSUPPORTED_KEYLENGTH;
|
||||
static const int EVP_R_UNSUPPORTED_SALT_TYPE;
|
||||
static const int EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM;
|
||||
static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH;
|
||||
static const int EVP_R_WRONG_PUBLIC_KEY_TYPE;
|
||||
|
||||
static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME;
|
||||
|
||||
static const int EC_R_UNKNOWN_GROUP;
|
||||
|
||||
static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
|
||||
static const int PEM_F_D2I_PKCS8PRIVATEKEY_FP;
|
||||
static const int PEM_F_DO_PK8PKEY;
|
||||
|
|
@ -283,7 +290,7 @@ typedef uint32_t CRYPTO_THREADID;
|
|||
void (*ERR_remove_thread_state)(const CRYPTO_THREADID *) = NULL;
|
||||
#endif
|
||||
|
||||
// OpenSSL 0.9.8h+
|
||||
/* OpenSSL 0.9.8h+ */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
|
||||
static const long Cryptography_HAS_098H_ERROR_CODES = 1;
|
||||
#else
|
||||
|
|
@ -297,7 +304,7 @@ static const int ASN1_R_NO_MULTIPART_BODY_FAILURE = 0;
|
|||
static const int ASN1_R_NO_MULTIPART_BOUNDARY = 0;
|
||||
#endif
|
||||
|
||||
// OpenSSL 0.9.8c+
|
||||
/* OpenSSL 0.9.8c+ */
|
||||
#ifdef EVP_F_CAMELLIA_INIT_KEY
|
||||
static const long Cryptography_HAS_098C_CAMELLIA_CODES = 1;
|
||||
#else
|
||||
|
|
@ -306,6 +313,14 @@ static const int EVP_F_CAMELLIA_INIT_KEY = 0;
|
|||
static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED = 0;
|
||||
#endif
|
||||
|
||||
// OpenSSL without EC. e.g. RHEL
|
||||
#ifndef OPENSSL_NO_EC
|
||||
static const long Cryptography_HAS_EC_CODES = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_EC_CODES = 0;
|
||||
static const int EC_R_UNKNOWN_GROUP = 0;
|
||||
static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME = 0;
|
||||
#endif
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {
|
||||
|
|
@ -324,5 +339,9 @@ CONDITIONAL_NAMES = {
|
|||
"Cryptography_HAS_098C_CAMELLIA_CODES": [
|
||||
"EVP_F_CAMELLIA_INIT_KEY",
|
||||
"EVP_R_CAMELLIA_KEY_SETUP_FAILED"
|
||||
],
|
||||
"Cryptography_HAS_EC_CODES": [
|
||||
"EC_R_UNKNOWN_GROUP",
|
||||
"EC_F_EC_GROUP_NEW_BY_CURVE_NAME"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,8 @@ int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int,
|
|||
|
||||
int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *, const EVP_MD *);
|
||||
|
||||
// not macros but must be in this section since they're not available in 0.9.8
|
||||
/* These aren't macros, but must be in this section because they're not
|
||||
available in 0.9.8. */
|
||||
EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *, ENGINE *);
|
||||
EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int, ENGINE *);
|
||||
EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ static const int NID_ecdsa_with_SHA512;
|
|||
static const int NID_crl_reason;
|
||||
static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
|
||||
static const int NID_subject_alt_name;
|
||||
static const int NID_issuer_alt_name;
|
||||
static const int NID_X9_62_c2pnb163v1;
|
||||
static const int NID_X9_62_c2pnb163v2;
|
||||
static const int NID_X9_62_c2pnb163v3;
|
||||
|
|
@ -193,7 +194,7 @@ MACROS = """
|
|||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
// OpenSSL 0.9.8g+
|
||||
/* OpenSSL 0.9.8g+ */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
|
||||
static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 1;
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ INCLUDES = """
|
|||
"""
|
||||
|
||||
TYPES = """
|
||||
/* Note that these will be resolved when cryptography is compiled and are NOT
|
||||
guaranteed to be the version that it actually loads. */
|
||||
static const int OPENSSL_VERSION_NUMBER;
|
||||
static const char *const OPENSSL_VERSION_TEXT;
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *,
|
|||
int i2d_PKCS8PrivateKey_nid_bio(BIO *, EVP_PKEY *, int,
|
||||
char *, int, pem_password_cb *, void *);
|
||||
|
||||
PKCS7 *d2i_PKCS7_bio(BIO *, PKCS7 **);
|
||||
EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *,
|
||||
void *);
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ CUSTOMIZATIONS = """
|
|||
#if OPENSSL_VERSION_NUMBER >= 0x10000000
|
||||
static const long Cryptography_HAS_PSS_PADDING = 1;
|
||||
#else
|
||||
// see evp.py for the definition of Cryptography_HAS_PKEY_CTX
|
||||
/* see evp.py for the definition of Cryptography_HAS_PKEY_CTX */
|
||||
static const long Cryptography_HAS_PSS_PADDING = 0;
|
||||
int (*EVP_PKEY_CTX_set_rsa_padding)(EVP_PKEY_CTX *, int) = NULL;
|
||||
int (*EVP_PKEY_CTX_set_rsa_pss_saltlen)(EVP_PKEY_CTX *, int) = NULL;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ from __future__ import absolute_import, division, print_function
|
|||
|
||||
INCLUDES = """
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
typedef STACK_OF(SSL_CIPHER) Cryptography_STACK_OF_SSL_CIPHER;
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
|
|
@ -24,6 +26,7 @@ TYPES = """
|
|||
static const long Cryptography_HAS_SSL2;
|
||||
static const long Cryptography_HAS_TLSv1_1;
|
||||
static const long Cryptography_HAS_TLSv1_2;
|
||||
static const long Cryptography_HAS_SECURE_RENEGOTIATION;
|
||||
|
||||
/* Internally invented symbol to tell us if SNI is supported */
|
||||
static const long Cryptography_HAS_TLSEXT_HOSTNAME;
|
||||
|
|
@ -43,6 +46,7 @@ static const long Cryptography_HAS_SSL_SET_SSL_CTX;
|
|||
static const long Cryptography_HAS_SSL_OP_NO_TICKET;
|
||||
static const long Cryptography_HAS_NETBSD_D1_METH;
|
||||
static const long Cryptography_HAS_NEXTPROTONEG;
|
||||
static const long Cryptography_HAS_ALPN;
|
||||
|
||||
static const long SSL_FILETYPE_PEM;
|
||||
static const long SSL_FILETYPE_ASN1;
|
||||
|
|
@ -84,6 +88,8 @@ static const long SSL_OP_COOKIE_EXCHANGE;
|
|||
static const long SSL_OP_NO_TICKET;
|
||||
static const long SSL_OP_ALL;
|
||||
static const long SSL_OP_SINGLE_ECDH_USE;
|
||||
static const long SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
|
||||
static const long SSL_OP_LEGACY_SERVER_CONNECT;
|
||||
static const long SSL_VERIFY_PEER;
|
||||
static const long SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
||||
static const long SSL_VERIFY_CLIENT_ONCE;
|
||||
|
|
@ -121,9 +127,6 @@ static const long SSL_MODE_ENABLE_PARTIAL_WRITE;
|
|||
static const long SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
|
||||
static const long SSL_MODE_AUTO_RETRY;
|
||||
static const long SSL3_RANDOM_SIZE;
|
||||
typedef ... X509_STORE_CTX;
|
||||
static const long X509_V_OK;
|
||||
static const long X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
typedef ... SSL_METHOD;
|
||||
typedef struct ssl_st {
|
||||
int version;
|
||||
|
|
@ -153,6 +156,8 @@ typedef struct {
|
|||
static const long TLSEXT_NAMETYPE_host_name;
|
||||
|
||||
typedef ... SSL_CIPHER;
|
||||
typedef ... Cryptography_STACK_OF_SSL_CIPHER;
|
||||
typedef ... COMP_METHOD;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
|
|
@ -190,6 +195,11 @@ int SSL_get_error(const SSL *, int);
|
|||
int SSL_do_handshake(SSL *);
|
||||
int SSL_shutdown(SSL *);
|
||||
const char *SSL_get_cipher_list(const SSL *, int);
|
||||
Cryptography_STACK_OF_SSL_CIPHER *SSL_get_ciphers(const SSL *);
|
||||
|
||||
const COMP_METHOD *SSL_get_current_compression(SSL *);
|
||||
const COMP_METHOD *SSL_get_current_expansion(SSL *);
|
||||
const char *SSL_COMP_get_name(const COMP_METHOD *);
|
||||
|
||||
/* context */
|
||||
void SSL_CTX_free(SSL_CTX *);
|
||||
|
|
@ -215,16 +225,6 @@ int SSL_CTX_add_client_CA(SSL_CTX *, X509 *);
|
|||
|
||||
void SSL_CTX_set_client_CA_list(SSL_CTX *, Cryptography_STACK_OF_X509_NAME *);
|
||||
|
||||
|
||||
/* X509_STORE_CTX */
|
||||
int X509_STORE_CTX_get_error(X509_STORE_CTX *);
|
||||
void X509_STORE_CTX_set_error(X509_STORE_CTX *, int);
|
||||
int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *);
|
||||
X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
|
||||
int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *, int, void *);
|
||||
void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *, int);
|
||||
|
||||
|
||||
/* SSL_SESSION */
|
||||
void SSL_SESSION_free(SSL_SESSION *);
|
||||
|
||||
|
|
@ -248,6 +248,7 @@ int SSL_want_read(const SSL *);
|
|||
int SSL_want_write(const SSL *);
|
||||
|
||||
long SSL_total_renegotiations(SSL *);
|
||||
long SSL_get_secure_renegotiation_support(SSL *);
|
||||
|
||||
/* Defined as unsigned long because SSL_OP_ALL is greater than signed 32-bit
|
||||
and Windows defines long as 32-bit. */
|
||||
|
|
@ -351,9 +352,38 @@ int SSL_select_next_proto(unsigned char **, unsigned char *,
|
|||
const unsigned char *, unsigned int);
|
||||
void SSL_get0_next_proto_negotiated(const SSL *,
|
||||
const unsigned char **, unsigned *);
|
||||
|
||||
int sk_SSL_CIPHER_num(Cryptography_STACK_OF_SSL_CIPHER *);
|
||||
SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int);
|
||||
|
||||
/* ALPN APIs were introduced in OpenSSL 1.0.2. To continue to support earlier
|
||||
* versions some special handling of these is necessary.
|
||||
*/
|
||||
int SSL_CTX_set_alpn_protos(SSL_CTX *, const unsigned char*, unsigned);
|
||||
int SSL_set_alpn_protos(SSL *, const unsigned char*, unsigned);
|
||||
void SSL_CTX_set_alpn_select_cb(SSL_CTX *,
|
||||
int (*) (SSL *,
|
||||
const unsigned char **,
|
||||
unsigned char *,
|
||||
const unsigned char *,
|
||||
unsigned int,
|
||||
void *),
|
||||
void *);
|
||||
void SSL_get0_alpn_selected(const SSL *, const unsigned char **, unsigned *);
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
/** Secure renegotiation is supported in OpenSSL >= 0.9.8m
|
||||
* But some Linux distributions have back ported some features.
|
||||
*/
|
||||
#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
|
||||
static const long Cryptography_HAS_SECURE_RENEGOTIATION = 0;
|
||||
long (*SSL_get_secure_renegotiation_support)(SSL *) = NULL;
|
||||
const long SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0;
|
||||
const long SSL_OP_LEGACY_SERVER_CONNECT = 0;
|
||||
#else
|
||||
static const long Cryptography_HAS_SECURE_RENEGOTIATION = 1;
|
||||
#endif
|
||||
#ifdef OPENSSL_NO_SSL2
|
||||
static const long Cryptography_HAS_SSL2 = 0;
|
||||
SSL_METHOD* (*SSLv2_method)(void) = NULL;
|
||||
|
|
@ -426,7 +456,7 @@ static const long Cryptography_HAS_SSL_OP_NO_TICKET = 0;
|
|||
const long SSL_OP_NO_TICKET = 0;
|
||||
#endif
|
||||
|
||||
// OpenSSL 0.9.8f+
|
||||
/* OpenSSL 0.9.8f+ */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00908070L
|
||||
static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1;
|
||||
#else
|
||||
|
|
@ -453,7 +483,7 @@ static const long Cryptography_HAS_NETBSD_D1_METH = 1;
|
|||
static const long Cryptography_HAS_NETBSD_D1_METH = 1;
|
||||
#endif
|
||||
|
||||
// Workaround for #794 caused by cffi const** bug.
|
||||
/* Workaround for #794 caused by cffi const** bug. */
|
||||
const SSL_METHOD* Cryptography_SSL_CTX_get_method(const SSL_CTX* ctx) {
|
||||
return ctx->method;
|
||||
}
|
||||
|
|
@ -488,6 +518,28 @@ void (*SSL_get0_next_proto_negotiated)(const SSL *,
|
|||
#else
|
||||
static const long Cryptography_HAS_NEXTPROTONEG = 1;
|
||||
#endif
|
||||
|
||||
/* ALPN was added in OpenSSL 1.0.2. */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10002001L
|
||||
int (*SSL_CTX_set_alpn_protos)(SSL_CTX *,
|
||||
const unsigned char*,
|
||||
unsigned) = NULL;
|
||||
int (*SSL_set_alpn_protos)(SSL *, const unsigned char*, unsigned) = NULL;
|
||||
void (*SSL_CTX_set_alpn_select_cb)(SSL_CTX *,
|
||||
int (*) (SSL *,
|
||||
const unsigned char **,
|
||||
unsigned char *,
|
||||
const unsigned char *,
|
||||
unsigned int,
|
||||
void *),
|
||||
void *) = NULL;
|
||||
void (*SSL_get0_alpn_selected)(const SSL *,
|
||||
const unsigned char **,
|
||||
unsigned *) = NULL;
|
||||
static const long Cryptography_HAS_ALPN = 0;
|
||||
#else
|
||||
static const long Cryptography_HAS_ALPN = 1;
|
||||
#endif
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {
|
||||
|
|
@ -551,5 +603,18 @@ CONDITIONAL_NAMES = {
|
|||
"SSL_CTX_set_next_proto_select_cb",
|
||||
"SSL_select_next_proto",
|
||||
"SSL_get0_next_proto_negotiated",
|
||||
],
|
||||
|
||||
"Cryptography_HAS_SECURE_RENEGOTIATION": [
|
||||
"SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION",
|
||||
"SSL_OP_LEGACY_SERVER_CONNECT",
|
||||
"SSL_get_secure_renegotiation_support",
|
||||
],
|
||||
|
||||
"Cryptography_HAS_ALPN": [
|
||||
"SSL_CTX_set_alpn_protos",
|
||||
"SSL_set_alpn_protos",
|
||||
"SSL_CTX_set_alpn_select_cb",
|
||||
"SSL_get0_alpn_selected",
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ INCLUDES = """
|
|||
* Note that the result is an opaque type.
|
||||
*/
|
||||
typedef STACK_OF(X509) Cryptography_STACK_OF_X509;
|
||||
typedef STACK_OF(X509_CRL) Cryptography_STACK_OF_X509_CRL;
|
||||
typedef STACK_OF(X509_REVOKED) Cryptography_STACK_OF_X509_REVOKED;
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
typedef ... Cryptography_STACK_OF_X509;
|
||||
typedef ... Cryptography_STACK_OF_X509_CRL;
|
||||
typedef ... Cryptography_STACK_OF_X509_REVOKED;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -76,7 +78,6 @@ typedef struct {
|
|||
...;
|
||||
} X509;
|
||||
|
||||
typedef ... X509_STORE;
|
||||
typedef ... NETSCAPE_SPKI;
|
||||
"""
|
||||
|
||||
|
|
@ -166,12 +167,6 @@ EVP_PKEY *d2i_PUBKEY_bio(BIO *, EVP_PKEY **);
|
|||
ASN1_INTEGER *X509_get_serialNumber(X509 *);
|
||||
int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
|
||||
|
||||
/* X509_STORE */
|
||||
X509_STORE *X509_STORE_new(void);
|
||||
void X509_STORE_free(X509_STORE *);
|
||||
int X509_STORE_add_cert(X509_STORE *, X509 *);
|
||||
int X509_verify_cert(X509_STORE_CTX *);
|
||||
|
||||
const char *X509_verify_cert_error_string(long);
|
||||
|
||||
const char *X509_get_default_cert_area(void);
|
||||
|
|
@ -190,7 +185,6 @@ DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
|
|||
DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long);
|
||||
DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long);
|
||||
|
||||
|
||||
RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
|
||||
int i2d_RSAPrivateKey_bio(BIO *, RSA *);
|
||||
RSA *d2i_RSAPublicKey_bio(BIO *, RSA **);
|
||||
|
|
@ -237,7 +231,7 @@ int i2d_DSAPrivateKey(DSA *, unsigned char **);
|
|||
int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
|
||||
int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
|
||||
|
||||
/* these use STACK_OF(X509_EXTENSION) in 0.9.8e. Once we drop support for
|
||||
/* These use STACK_OF(X509_EXTENSION) in 0.9.8e. Once we drop support for
|
||||
RHEL/CentOS 5 we should move these back to FUNCTIONS. */
|
||||
int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
|
||||
X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
|
||||
|
|
@ -251,7 +245,7 @@ int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
|
|||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
// OpenSSL 0.9.8e does not have this definition
|
||||
/* OpenSSL 0.9.8e does not have this definition. */
|
||||
#if OPENSSL_VERSION_NUMBER <= 0x0090805fL
|
||||
typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,336 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
INCLUDES = """
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
/*
|
||||
* This is part of a work-around for the difficulty cffi has in dealing with
|
||||
* `STACK_OF(foo)` as the name of a type. We invent a new, simpler name that
|
||||
* will be an alias for this type and use the alias throughout. This works
|
||||
* together with another opaque typedef for the same name in the TYPES section.
|
||||
* Note that the result is an opaque type.
|
||||
*/
|
||||
typedef STACK_OF(ASN1_OBJECT) Cryptography_STACK_OF_ASN1_OBJECT;
|
||||
"""
|
||||
|
||||
TYPES = """
|
||||
static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES;
|
||||
static const long Cryptography_HAS_102_VERIFICATION_PARAMS;
|
||||
static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST;
|
||||
static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN;
|
||||
static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES;
|
||||
static const long Cryptography_HAS_100_VERIFICATION_PARAMS;
|
||||
static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE;
|
||||
|
||||
typedef ... Cryptography_STACK_OF_ASN1_OBJECT;
|
||||
|
||||
typedef ... X509_STORE;
|
||||
typedef ... X509_STORE_CTX;
|
||||
typedef ... X509_VERIFY_PARAM;
|
||||
|
||||
/* While these are defined in the source as ints, they're tagged here
|
||||
as longs, just in case they ever grow to large, such as what we saw
|
||||
with OP_ALL. */
|
||||
|
||||
/* Verification error codes */
|
||||
static const int X509_V_OK;
|
||||
static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
|
||||
static const int X509_V_ERR_UNABLE_TO_GET_CRL;
|
||||
static const int X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE;
|
||||
static const int X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE;
|
||||
static const int X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
|
||||
static const int X509_V_ERR_CERT_SIGNATURE_FAILURE;
|
||||
static const int X509_V_ERR_CRL_SIGNATURE_FAILURE;
|
||||
static const int X509_V_ERR_CERT_NOT_YET_VALID;
|
||||
static const int X509_V_ERR_CERT_HAS_EXPIRED;
|
||||
static const int X509_V_ERR_CRL_NOT_YET_VALID;
|
||||
static const int X509_V_ERR_CRL_HAS_EXPIRED;
|
||||
static const int X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
|
||||
static const int X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
|
||||
static const int X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
|
||||
static const int X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
|
||||
static const int X509_V_ERR_OUT_OF_MEM;
|
||||
static const int X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
|
||||
static const int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
|
||||
static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
|
||||
static const int X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
|
||||
static const int X509_V_ERR_CERT_CHAIN_TOO_LONG;
|
||||
static const int X509_V_ERR_CERT_REVOKED;
|
||||
static const int X509_V_ERR_INVALID_CA;
|
||||
static const int X509_V_ERR_PATH_LENGTH_EXCEEDED;
|
||||
static const int X509_V_ERR_INVALID_PURPOSE;
|
||||
static const int X509_V_ERR_CERT_UNTRUSTED;
|
||||
static const int X509_V_ERR_CERT_REJECTED;
|
||||
static const int X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
|
||||
static const int X509_V_ERR_AKID_SKID_MISMATCH;
|
||||
static const int X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
|
||||
static const int X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
|
||||
static const int X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
|
||||
static const int X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
|
||||
static const int X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
|
||||
static const int X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
|
||||
static const int X509_V_ERR_INVALID_NON_CA;
|
||||
static const int X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
|
||||
static const int X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
|
||||
static const int X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
|
||||
static const int X509_V_ERR_INVALID_EXTENSION;
|
||||
static const int X509_V_ERR_INVALID_POLICY_EXTENSION;
|
||||
static const int X509_V_ERR_NO_EXPLICIT_POLICY;
|
||||
static const int X509_V_ERR_DIFFERENT_CRL_SCOPE;
|
||||
static const int X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE;
|
||||
static const int X509_V_ERR_UNNESTED_RESOURCE;
|
||||
static const int X509_V_ERR_PERMITTED_VIOLATION;
|
||||
static const int X509_V_ERR_EXCLUDED_VIOLATION;
|
||||
static const int X509_V_ERR_SUBTREE_MINMAX;
|
||||
static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
|
||||
static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
|
||||
static const int X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
|
||||
static const int X509_V_ERR_CRL_PATH_VALIDATION_ERROR;
|
||||
static const int X509_V_ERR_SUITE_B_INVALID_VERSION;
|
||||
static const int X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
|
||||
static const int X509_V_ERR_SUITE_B_INVALID_CURVE;
|
||||
static const int X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
|
||||
static const int X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
|
||||
static const int X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256;
|
||||
static const int X509_V_ERR_HOSTNAME_MISMATCH;
|
||||
static const int X509_V_ERR_EMAIL_MISMATCH;
|
||||
static const int X509_V_ERR_IP_ADDRESS_MISMATCH;
|
||||
static const int X509_V_ERR_APPLICATION_VERIFICATION;
|
||||
|
||||
/* Verification parameters */
|
||||
static const long X509_V_FLAG_CB_ISSUER_CHECK;
|
||||
static const long X509_V_FLAG_USE_CHECK_TIME;
|
||||
static const long X509_V_FLAG_CRL_CHECK;
|
||||
static const long X509_V_FLAG_CRL_CHECK_ALL;
|
||||
static const long X509_V_FLAG_IGNORE_CRITICAL;
|
||||
static const long X509_V_FLAG_X509_STRICT;
|
||||
static const long X509_V_FLAG_ALLOW_PROXY_CERTS;
|
||||
static const long X509_V_FLAG_POLICY_CHECK;
|
||||
static const long X509_V_FLAG_EXPLICIT_POLICY;
|
||||
static const long X509_V_FLAG_INHIBIT_ANY;
|
||||
static const long X509_V_FLAG_INHIBIT_MAP;
|
||||
static const long X509_V_FLAG_NOTIFY_POLICY;
|
||||
static const long X509_V_FLAG_EXTENDED_CRL_SUPPORT;
|
||||
static const long X509_V_FLAG_USE_DELTAS;
|
||||
static const long X509_V_FLAG_CHECK_SS_SIGNATURE;
|
||||
static const long X509_V_FLAG_TRUSTED_FIRST;
|
||||
static const long X509_V_FLAG_SUITEB_128_LOS_ONLY;
|
||||
static const long X509_V_FLAG_SUITEB_192_LOS;
|
||||
static const long X509_V_FLAG_SUITEB_128_LOS;
|
||||
static const long X509_V_FLAG_PARTIAL_CHAIN;
|
||||
"""
|
||||
|
||||
FUNCTIONS = """
|
||||
int X509_verify_cert(X509_STORE_CTX *);
|
||||
|
||||
/* X509_STORE */
|
||||
X509_STORE *X509_STORE_new(void);
|
||||
void X509_STORE_free(X509_STORE *);
|
||||
int X509_STORE_add_cert(X509_STORE *, X509 *);
|
||||
|
||||
/* X509_STORE_CTX */
|
||||
X509_STORE_CTX *X509_STORE_CTX_new(void);
|
||||
void X509_STORE_CTX_cleanup(X509_STORE_CTX *);
|
||||
void X509_STORE_CTX_free(X509_STORE_CTX *);
|
||||
int X509_STORE_CTX_init(X509_STORE_CTX *, X509_STORE *, X509 *,
|
||||
Cryptography_STACK_OF_X509 *);
|
||||
void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *,
|
||||
Cryptography_STACK_OF_X509 *);
|
||||
void X509_STORE_CTX_set_cert(X509_STORE_CTX *, X509 *);
|
||||
void X509_STORE_CTX_set_chain(X509_STORE_CTX *,Cryptography_STACK_OF_X509 *);
|
||||
X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *);
|
||||
void X509_STORE_CTX_set0_param(X509_STORE_CTX *, X509_VERIFY_PARAM *);
|
||||
int X509_STORE_CTX_set_default(X509_STORE_CTX *, const char *);
|
||||
void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *,
|
||||
int (*)(int, X509_STORE_CTX *));
|
||||
Cryptography_STACK_OF_X509 *X509_STORE_CTX_get_chain(X509_STORE_CTX *);
|
||||
Cryptography_STACK_OF_X509 *X509_STORE_CTX_get1_chain(X509_STORE_CTX *);
|
||||
int X509_STORE_CTX_get_error(X509_STORE_CTX *);
|
||||
void X509_STORE_CTX_set_error(X509_STORE_CTX *, int);
|
||||
int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *);
|
||||
X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
|
||||
int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *, int, void *);
|
||||
void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *, int);
|
||||
|
||||
/* X509_VERIFY_PARAM */
|
||||
X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
|
||||
int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *, unsigned long);
|
||||
int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *, unsigned long);
|
||||
unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *);
|
||||
int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *, int);
|
||||
int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *, int);
|
||||
void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *, time_t);
|
||||
int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *, ASN1_OBJECT *);
|
||||
int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *,
|
||||
Cryptography_STACK_OF_ASN1_OBJECT *);
|
||||
void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *, int);
|
||||
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
/* X509_STORE_CTX */
|
||||
void X509_STORE_CTX_set0_crls(X509_STORE_CTX *,
|
||||
Cryptography_STACK_OF_X509_CRL *);
|
||||
|
||||
/* X509_VERIFY_PARAM */
|
||||
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *, const char *,
|
||||
size_t);
|
||||
void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *, unsigned int);
|
||||
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *, const char *,
|
||||
size_t);
|
||||
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *, const unsigned char *,
|
||||
size_t);
|
||||
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *, const char *);
|
||||
"""
|
||||
|
||||
CUSTOMIZATIONS = """
|
||||
/* OpenSSL 1.0.2+ verification error codes */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 0;
|
||||
static const long X509_V_ERR_SUITE_B_INVALID_VERSION = 0;
|
||||
static const long X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 0;
|
||||
static const long X509_V_ERR_SUITE_B_INVALID_CURVE = 0;
|
||||
static const long X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 0;
|
||||
static const long X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 0;
|
||||
static const long X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 0;
|
||||
static const long X509_V_ERR_HOSTNAME_MISMATCH = 0;
|
||||
static const long X509_V_ERR_EMAIL_MISMATCH = 0;
|
||||
static const long X509_V_ERR_IP_ADDRESS_MISMATCH = 0;
|
||||
#endif
|
||||
|
||||
/* OpenSSL 1.0.2+ verification parameters */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 0;
|
||||
/* X509_V_FLAG_TRUSTED_FIRST is also new in 1.0.2+, but it is added separately
|
||||
below because it shows up in some earlier 3rd party OpenSSL packages. */
|
||||
static const long X509_V_FLAG_SUITEB_128_LOS_ONLY = 0;
|
||||
static const long X509_V_FLAG_SUITEB_192_LOS = 0;
|
||||
static const long X509_V_FLAG_SUITEB_128_LOS = 0;
|
||||
|
||||
int (*X509_VERIFY_PARAM_set1_host)(X509_VERIFY_PARAM *, const char *,
|
||||
size_t) = NULL;
|
||||
int (*X509_VERIFY_PARAM_set1_email)(X509_VERIFY_PARAM *, const char *,
|
||||
size_t) = NULL;
|
||||
int (*X509_VERIFY_PARAM_set1_ip)(X509_VERIFY_PARAM *, const unsigned char *,
|
||||
size_t) = NULL;
|
||||
int (*X509_VERIFY_PARAM_set1_ip_asc)(X509_VERIFY_PARAM *, const char *) = NULL;
|
||||
void (*X509_VERIFY_PARAM_set_hostflags)(X509_VERIFY_PARAM *,
|
||||
unsigned int) = NULL;
|
||||
#endif
|
||||
|
||||
/* OpenSSL 1.0.2+ or Solaris's backport */
|
||||
#ifdef X509_V_FLAG_PARTIAL_CHAIN
|
||||
static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN = 0;
|
||||
static const long X509_V_FLAG_PARTIAL_CHAIN = 0;
|
||||
#endif
|
||||
|
||||
/* OpenSSL 1.0.2+, *or* Fedora 20's flavor of OpenSSL 1.0.1e... */
|
||||
#ifdef X509_V_FLAG_TRUSTED_FIRST
|
||||
static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 0;
|
||||
static const long X509_V_FLAG_TRUSTED_FIRST = 0;
|
||||
#endif
|
||||
|
||||
/* OpenSSL 1.0.0+ verification error codes */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES = 0;
|
||||
static const long X509_V_ERR_DIFFERENT_CRL_SCOPE = 0;
|
||||
static const long X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE = 0;
|
||||
static const long X509_V_ERR_PERMITTED_VIOLATION = 0;
|
||||
static const long X509_V_ERR_EXCLUDED_VIOLATION = 0;
|
||||
static const long X509_V_ERR_SUBTREE_MINMAX = 0;
|
||||
static const long X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE = 0;
|
||||
static const long X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 0;
|
||||
static const long X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 0;
|
||||
static const long X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 0;
|
||||
#endif
|
||||
|
||||
/* OpenSSL 1.0.0+ verification parameters */
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
|
||||
static const long Cryptography_HAS_100_VERIFICATION_PARAMS = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_100_VERIFICATION_PARAMS = 0;
|
||||
static const long X509_V_FLAG_EXTENDED_CRL_SUPPORT = 0;
|
||||
static const long X509_V_FLAG_USE_DELTAS = 0;
|
||||
#endif
|
||||
|
||||
/* OpenSSL 0.9.8recent+ */
|
||||
#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
|
||||
static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 1;
|
||||
#else
|
||||
static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
|
||||
static const long X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
|
||||
#endif
|
||||
"""
|
||||
|
||||
CONDITIONAL_NAMES = {
|
||||
"Cryptography_HAS_102_VERIFICATION_ERROR_CODES": [
|
||||
'X509_V_ERR_SUITE_B_INVALID_VERSION',
|
||||
'X509_V_ERR_SUITE_B_INVALID_ALGORITHM',
|
||||
'X509_V_ERR_SUITE_B_INVALID_CURVE',
|
||||
'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM',
|
||||
'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED',
|
||||
'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256',
|
||||
'X509_V_ERR_HOSTNAME_MISMATCH',
|
||||
'X509_V_ERR_EMAIL_MISMATCH',
|
||||
'X509_V_ERR_IP_ADDRESS_MISMATCH'
|
||||
],
|
||||
"Cryptography_HAS_102_VERIFICATION_PARAMS": [
|
||||
"X509_V_FLAG_SUITEB_128_LOS_ONLY",
|
||||
"X509_V_FLAG_SUITEB_192_LOS",
|
||||
"X509_V_FLAG_SUITEB_128_LOS",
|
||||
"X509_VERIFY_PARAM_set1_host",
|
||||
"X509_VERIFY_PARAM_set1_email",
|
||||
"X509_VERIFY_PARAM_set1_ip",
|
||||
"X509_VERIFY_PARAM_set1_ip_asc",
|
||||
"X509_VERIFY_PARAM_set_hostflags",
|
||||
],
|
||||
"Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": [
|
||||
"X509_V_FLAG_TRUSTED_FIRST",
|
||||
],
|
||||
"Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": [
|
||||
"X509_V_FLAG_PARTIAL_CHAIN",
|
||||
],
|
||||
"Cryptography_HAS_100_VERIFICATION_ERROR_CODES": [
|
||||
'X509_V_ERR_DIFFERENT_CRL_SCOPE',
|
||||
'X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE',
|
||||
'X509_V_ERR_UNNESTED_RESOURCE',
|
||||
'X509_V_ERR_PERMITTED_VIOLATION',
|
||||
'X509_V_ERR_EXCLUDED_VIOLATION',
|
||||
'X509_V_ERR_SUBTREE_MINMAX',
|
||||
'X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE',
|
||||
'X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX',
|
||||
'X509_V_ERR_UNSUPPORTED_NAME_SYNTAX',
|
||||
'X509_V_ERR_CRL_PATH_VALIDATION_ERROR',
|
||||
],
|
||||
"Cryptography_HAS_100_VERIFICATION_PARAMS": [
|
||||
"Cryptography_HAS_100_VERIFICATION_PARAMS",
|
||||
"X509_V_FLAG_EXTENDED_CRL_SUPPORT",
|
||||
"X509_V_FLAG_USE_DELTAS",
|
||||
],
|
||||
"Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE": [
|
||||
"X509_V_FLAG_CHECK_SS_SIGNATURE",
|
||||
]
|
||||
}
|
||||
|
|
@ -82,6 +82,8 @@ FUNCTIONS = """
|
|||
void X509V3_set_ctx(X509V3_CTX *, X509 *, X509 *, X509_REQ *, X509_CRL *, int);
|
||||
X509_EXTENSION *X509V3_EXT_nconf(CONF *, X509V3_CTX *, char *, char *);
|
||||
int GENERAL_NAME_print(BIO *, GENERAL_NAME *);
|
||||
void GENERAL_NAMES_free(GENERAL_NAMES *);
|
||||
void *X509V3_EXT_d2i(X509_EXTENSION *);
|
||||
"""
|
||||
|
||||
MACROS = """
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import warnings
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
|
|
@ -21,31 +23,54 @@ 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")
|
||||
def generate_parameters(key_size, backend):
|
||||
return backend.generate_dsa_parameters(key_size)
|
||||
|
||||
if (utils.bit_length(modulus),
|
||||
utils.bit_length(subgroup_order)) not in (
|
||||
|
||||
def generate_private_key(key_size, backend):
|
||||
return backend.generate_dsa_private_key_and_parameters(key_size)
|
||||
|
||||
|
||||
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)")
|
||||
"or (3072, 256).")
|
||||
|
||||
if generator <= 1 or generator >= modulus:
|
||||
raise ValueError("generator must be > 1 and < modulus")
|
||||
if not (1 < parameters.g < parameters.p):
|
||||
raise ValueError("g, p don't satisfy 1 < g < p.")
|
||||
|
||||
|
||||
def _check_dsa_private_numbers(numbers):
|
||||
parameters = numbers.public_numbers.parameter_numbers
|
||||
_check_dsa_parameters(parameters)
|
||||
if numbers.x <= 0 or numbers.x >= parameters.q:
|
||||
raise ValueError("x must be > 0 and < q.")
|
||||
|
||||
if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p):
|
||||
raise ValueError("y must be equal to (g ** x % p).")
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.DSAParameters)
|
||||
class DSAParameters(object):
|
||||
def __init__(self, modulus, subgroup_order, generator):
|
||||
_check_dsa_parameters(modulus, subgroup_order, generator)
|
||||
warnings.warn(
|
||||
"The DSAParameters class is deprecated and will be removed in a "
|
||||
"future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
_check_dsa_parameters(
|
||||
DSAParameterNumbers(
|
||||
p=modulus,
|
||||
q=subgroup_order,
|
||||
g=generator
|
||||
)
|
||||
)
|
||||
|
||||
self._modulus = modulus
|
||||
self._subgroup_order = subgroup_order
|
||||
|
|
@ -53,13 +78,24 @@ class DSAParameters(object):
|
|||
|
||||
@classmethod
|
||||
def generate(cls, key_size, backend):
|
||||
warnings.warn(
|
||||
"generate is deprecated and will be removed in a future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
if not isinstance(backend, DSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement DSABackend",
|
||||
"Backend object does not implement DSABackend.",
|
||||
_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,18 +125,31 @@ 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)
|
||||
warnings.warn(
|
||||
"The DSAPrivateKey class is deprecated and will be removed in a "
|
||||
"future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
if (
|
||||
not isinstance(x, six.integer_types) or
|
||||
not isinstance(y, six.integer_types)
|
||||
):
|
||||
raise TypeError("DSAPrivateKey arguments must be integers")
|
||||
raise TypeError("DSAPrivateKey arguments must be integers.")
|
||||
|
||||
if x <= 0 or x >= subgroup_order:
|
||||
raise ValueError("x must be > 0 and < subgroup_order")
|
||||
|
||||
if y != pow(generator, x, modulus):
|
||||
raise ValueError("y must be equal to (generator ** x % modulus)")
|
||||
_check_dsa_private_numbers(
|
||||
DSAPrivateNumbers(
|
||||
public_numbers=DSAPublicNumbers(
|
||||
parameter_numbers=DSAParameterNumbers(
|
||||
p=modulus,
|
||||
q=subgroup_order,
|
||||
g=generator
|
||||
),
|
||||
y=y
|
||||
),
|
||||
x=x
|
||||
)
|
||||
)
|
||||
|
||||
self._modulus = modulus
|
||||
self._subgroup_order = subgroup_order
|
||||
|
|
@ -110,18 +159,31 @@ class DSAPrivateKey(object):
|
|||
|
||||
@classmethod
|
||||
def generate(cls, parameters, backend):
|
||||
warnings.warn(
|
||||
"generate is deprecated and will be removed in a future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
if not isinstance(backend, DSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement DSABackend",
|
||||
"Backend object does not implement DSABackend.",
|
||||
_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):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement DSABackend",
|
||||
"Backend object does not implement DSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -151,9 +213,21 @@ 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)
|
||||
warnings.warn(
|
||||
"The DSAPublicKey class is deprecated and will be removed in a "
|
||||
"future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
_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")
|
||||
raise TypeError("y must be an integer.")
|
||||
|
||||
self._modulus = modulus
|
||||
self._subgroup_order = subgroup_order
|
||||
|
|
@ -163,7 +237,7 @@ class DSAPublicKey(object):
|
|||
def verifier(self, signature, algorithm, backend):
|
||||
if not isinstance(backend, DSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement DSABackend",
|
||||
"Backend object does not implement DSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -181,3 +255,83 @@ class DSAPublicKey(object):
|
|||
def parameters(self):
|
||||
return DSAParameters(self._modulus, self._subgroup_order,
|
||||
self._generator)
|
||||
|
||||
|
||||
class DSAParameterNumbers(object):
|
||||
def __init__(self, p, q, g):
|
||||
if (
|
||||
not isinstance(p, six.integer_types) or
|
||||
not isinstance(q, six.integer_types) or
|
||||
not isinstance(g, six.integer_types)
|
||||
):
|
||||
raise TypeError(
|
||||
"DSAParameterNumbers p, q, and g arguments must be integers."
|
||||
)
|
||||
|
||||
self._p = p
|
||||
self._q = q
|
||||
self._g = g
|
||||
|
||||
@property
|
||||
def p(self):
|
||||
return self._p
|
||||
|
||||
@property
|
||||
def q(self):
|
||||
return self._q
|
||||
|
||||
@property
|
||||
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):
|
||||
if not isinstance(y, six.integer_types):
|
||||
raise TypeError("DSAPublicNumbers y argument must be an integer.")
|
||||
|
||||
if not isinstance(parameter_numbers, DSAParameterNumbers):
|
||||
raise TypeError(
|
||||
"parameter_numbers must be a DSAParameterNumbers instance."
|
||||
)
|
||||
|
||||
self._y = y
|
||||
self._parameter_numbers = parameter_numbers
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self._y
|
||||
|
||||
@property
|
||||
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):
|
||||
if not isinstance(x, six.integer_types):
|
||||
raise TypeError("DSAPrivateNumbers x argument must be an integer.")
|
||||
|
||||
if not isinstance(public_numbers, DSAPublicNumbers):
|
||||
raise TypeError(
|
||||
"public_numbers must be a DSAPublicNumbers instance."
|
||||
)
|
||||
self._public_numbers = public_numbers
|
||||
self._x = x
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def public_numbers(self):
|
||||
return self._public_numbers
|
||||
|
||||
def private_key(self, backend):
|
||||
return backend.load_dsa_private_numbers(self)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,255 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT571R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect571r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 571
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT409R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect409r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 409
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT283R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect283r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 283
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT233R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect233r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 233
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT163R2(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect163r2"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 163
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT571K1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect571k1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 571
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT409K1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect409k1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 409
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT283K1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect283k1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 283
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT233K1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect233k1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 233
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECT163K1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "sect163k1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 163
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECP521R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "secp521r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 521
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECP384R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "secp384r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 384
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECP256R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "secp256r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 256
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECP224R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "secp224r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 224
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurve)
|
||||
class SECP192R1(object):
|
||||
@property
|
||||
def name(self):
|
||||
return "secp192r1"
|
||||
|
||||
@property
|
||||
def key_size(self):
|
||||
return 192
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.EllipticCurveSignatureAlgorithm)
|
||||
class ECDSA(object):
|
||||
def __init__(self, algorithm):
|
||||
self._algorithm = algorithm
|
||||
|
||||
@property
|
||||
def algorithm(self):
|
||||
return self._algorithm
|
||||
|
||||
|
||||
def generate_private_key(curve, backend):
|
||||
return backend.generate_elliptic_curve_private_key(curve)
|
||||
|
||||
|
||||
class EllipticCurvePublicNumbers(object):
|
||||
def __init__(self, x, y, curve):
|
||||
if (
|
||||
not isinstance(x, six.integer_types) or
|
||||
not isinstance(y, six.integer_types)
|
||||
):
|
||||
raise TypeError("x and y must be integers.")
|
||||
|
||||
if not isinstance(curve, interfaces.EllipticCurve):
|
||||
raise TypeError("curve must provide the EllipticCurve interface.")
|
||||
|
||||
self._y = y
|
||||
self._x = x
|
||||
self._curve = curve
|
||||
|
||||
def public_key(self, backend):
|
||||
return backend.elliptic_curve_public_key_from_numbers(self)
|
||||
|
||||
@property
|
||||
def curve(self):
|
||||
return self._curve
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@property
|
||||
def y(self):
|
||||
return self._y
|
||||
|
||||
|
||||
class EllipticCurvePrivateNumbers(object):
|
||||
def __init__(self, private_value, public_numbers):
|
||||
if not isinstance(private_value, six.integer_types):
|
||||
raise TypeError("private_value must be an integer.")
|
||||
|
||||
if not isinstance(public_numbers, EllipticCurvePublicNumbers):
|
||||
raise TypeError(
|
||||
"public_numbers must be an EllipticCurvePublicNumbers "
|
||||
"instance."
|
||||
)
|
||||
|
||||
self._private_value = private_value
|
||||
self._public_numbers = public_numbers
|
||||
|
||||
def private_key(self, backend):
|
||||
return backend.elliptic_curve_private_key_from_numbers(self)
|
||||
|
||||
@property
|
||||
def private_value(self):
|
||||
return self._private_value
|
||||
|
||||
@property
|
||||
def public_numbers(self):
|
||||
return self._public_numbers
|
||||
|
|
@ -38,18 +38,19 @@ class PSS(object):
|
|||
warnings.warn(
|
||||
"salt_length is deprecated on MGF1 and should be added via the"
|
||||
" PSS constructor.",
|
||||
utils.DeprecatedIn04
|
||||
utils.DeprecatedIn04,
|
||||
stacklevel=2
|
||||
)
|
||||
else:
|
||||
if (not isinstance(salt_length, six.integer_types) and
|
||||
salt_length is not self.MAX_LENGTH):
|
||||
raise TypeError("salt_length must be an integer")
|
||||
raise TypeError("salt_length must be an integer.")
|
||||
|
||||
if salt_length is not self.MAX_LENGTH and salt_length < 0:
|
||||
raise ValueError("salt_length must be zero or greater")
|
||||
raise ValueError("salt_length must be zero or greater.")
|
||||
|
||||
if salt_length is None and self._mgf._salt_length is None:
|
||||
raise ValueError("You must supply salt_length")
|
||||
raise ValueError("You must supply salt_length.")
|
||||
|
||||
self._salt_length = salt_length
|
||||
|
||||
|
|
@ -80,13 +81,14 @@ class MGF1(object):
|
|||
warnings.warn(
|
||||
"salt_length is deprecated on MGF1 and should be passed to "
|
||||
"the PSS constructor instead.",
|
||||
utils.DeprecatedIn04
|
||||
utils.DeprecatedIn04,
|
||||
stacklevel=2
|
||||
)
|
||||
if (not isinstance(salt_length, six.integer_types) and
|
||||
salt_length is not self.MAX_LENGTH):
|
||||
raise TypeError("salt_length must be an integer")
|
||||
raise TypeError("salt_length must be an integer.")
|
||||
|
||||
if salt_length is not self.MAX_LENGTH and salt_length < 0:
|
||||
raise ValueError("salt_length must be zero or greater")
|
||||
raise ValueError("salt_length must be zero or greater.")
|
||||
|
||||
self._salt_length = salt_length
|
||||
|
|
|
|||
|
|
@ -13,31 +13,102 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import warnings
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
|
||||
from cryptography.hazmat.backends.interfaces import RSABackend
|
||||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.RSAPublicKey)
|
||||
def generate_private_key(public_exponent, key_size, backend):
|
||||
if not isinstance(backend, RSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement RSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
_verify_rsa_parameters(public_exponent, key_size)
|
||||
return backend.generate_rsa_private_key(public_exponent, key_size)
|
||||
|
||||
|
||||
def _verify_rsa_parameters(public_exponent, key_size):
|
||||
if public_exponent < 3:
|
||||
raise ValueError("public_exponent must be >= 3.")
|
||||
|
||||
if public_exponent & 1 == 0:
|
||||
raise ValueError("public_exponent must be odd.")
|
||||
|
||||
if key_size < 512:
|
||||
raise ValueError("key_size must be at least 512-bits.")
|
||||
|
||||
|
||||
def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp,
|
||||
public_exponent, modulus):
|
||||
if modulus < 3:
|
||||
raise ValueError("modulus must be >= 3.")
|
||||
|
||||
if p >= modulus:
|
||||
raise ValueError("p must be < modulus.")
|
||||
|
||||
if q >= modulus:
|
||||
raise ValueError("q must be < modulus.")
|
||||
|
||||
if dmp1 >= modulus:
|
||||
raise ValueError("dmp1 must be < modulus.")
|
||||
|
||||
if dmq1 >= modulus:
|
||||
raise ValueError("dmq1 must be < modulus.")
|
||||
|
||||
if iqmp >= modulus:
|
||||
raise ValueError("iqmp must be < modulus.")
|
||||
|
||||
if private_exponent >= modulus:
|
||||
raise ValueError("private_exponent must be < modulus.")
|
||||
|
||||
if public_exponent < 3 or public_exponent >= modulus:
|
||||
raise ValueError("public_exponent must be >= 3 and < modulus.")
|
||||
|
||||
if public_exponent & 1 == 0:
|
||||
raise ValueError("public_exponent must be odd.")
|
||||
|
||||
if dmp1 & 1 == 0:
|
||||
raise ValueError("dmp1 must be odd.")
|
||||
|
||||
if dmq1 & 1 == 0:
|
||||
raise ValueError("dmq1 must be odd.")
|
||||
|
||||
if p * q != modulus:
|
||||
raise ValueError("p*q must equal modulus.")
|
||||
|
||||
|
||||
def _check_public_key_components(e, n):
|
||||
if n < 3:
|
||||
raise ValueError("n must be >= 3.")
|
||||
|
||||
if e < 3 or e >= n:
|
||||
raise ValueError("e must be >= 3 and < n.")
|
||||
|
||||
if e & 1 == 0:
|
||||
raise ValueError("e must be odd.")
|
||||
|
||||
|
||||
class RSAPublicKey(object):
|
||||
def __init__(self, public_exponent, modulus):
|
||||
warnings.warn(
|
||||
"The RSAPublicKey class is deprecated and will be removed in a "
|
||||
"future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
if (
|
||||
not isinstance(public_exponent, six.integer_types) or
|
||||
not isinstance(modulus, six.integer_types)
|
||||
):
|
||||
raise TypeError("RSAPublicKey arguments must be integers")
|
||||
raise TypeError("RSAPublicKey arguments must be integers.")
|
||||
|
||||
if modulus < 3:
|
||||
raise ValueError("modulus must be >= 3")
|
||||
|
||||
if public_exponent < 3 or public_exponent >= modulus:
|
||||
raise ValueError("public_exponent must be >= 3 and < modulus")
|
||||
|
||||
if public_exponent & 1 == 0:
|
||||
raise ValueError("public_exponent must be odd")
|
||||
_check_public_key_components(public_exponent, modulus)
|
||||
|
||||
self._public_exponent = public_exponent
|
||||
self._modulus = modulus
|
||||
|
|
@ -45,7 +116,7 @@ class RSAPublicKey(object):
|
|||
def verifier(self, signature, padding, algorithm, backend):
|
||||
if not isinstance(backend, RSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement RSABackend",
|
||||
"Backend object does not implement RSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -55,7 +126,7 @@ class RSAPublicKey(object):
|
|||
def encrypt(self, plaintext, padding, backend):
|
||||
if not isinstance(backend, RSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement RSABackend",
|
||||
"Backend object does not implement RSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -118,10 +189,15 @@ def rsa_crt_dmq1(private_exponent, q):
|
|||
return private_exponent % (q - 1)
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.RSAPrivateKey)
|
||||
class RSAPrivateKey(object):
|
||||
def __init__(self, p, q, private_exponent, dmp1, dmq1, iqmp,
|
||||
public_exponent, modulus):
|
||||
warnings.warn(
|
||||
"The RSAPrivateKey class is deprecated and will be removed in a "
|
||||
"future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
if (
|
||||
not isinstance(p, six.integer_types) or
|
||||
not isinstance(q, six.integer_types) or
|
||||
|
|
@ -132,43 +208,10 @@ class RSAPrivateKey(object):
|
|||
not isinstance(public_exponent, six.integer_types) or
|
||||
not isinstance(modulus, six.integer_types)
|
||||
):
|
||||
raise TypeError("RSAPrivateKey arguments must be integers")
|
||||
raise TypeError("RSAPrivateKey arguments must be integers.")
|
||||
|
||||
if modulus < 3:
|
||||
raise ValueError("modulus must be >= 3")
|
||||
|
||||
if p >= modulus:
|
||||
raise ValueError("p must be < modulus")
|
||||
|
||||
if q >= modulus:
|
||||
raise ValueError("q must be < modulus")
|
||||
|
||||
if dmp1 >= modulus:
|
||||
raise ValueError("dmp1 must be < modulus")
|
||||
|
||||
if dmq1 >= modulus:
|
||||
raise ValueError("dmq1 must be < modulus")
|
||||
|
||||
if iqmp >= modulus:
|
||||
raise ValueError("iqmp must be < modulus")
|
||||
|
||||
if private_exponent >= modulus:
|
||||
raise ValueError("private_exponent must be < modulus")
|
||||
|
||||
if public_exponent < 3 or public_exponent >= modulus:
|
||||
raise ValueError("public_exponent must be >= 3 and < modulus")
|
||||
|
||||
if public_exponent & 1 == 0:
|
||||
raise ValueError("public_exponent must be odd")
|
||||
|
||||
if dmp1 & 1 == 0:
|
||||
raise ValueError("dmp1 must be odd")
|
||||
|
||||
if dmq1 & 1 == 0:
|
||||
raise ValueError("dmq1 must be odd")
|
||||
|
||||
if p * q != modulus:
|
||||
raise ValueError("p*q must equal modulus")
|
||||
_check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp,
|
||||
public_exponent, modulus)
|
||||
|
||||
self._p = p
|
||||
self._q = q
|
||||
|
|
@ -181,18 +224,35 @@ class RSAPrivateKey(object):
|
|||
|
||||
@classmethod
|
||||
def generate(cls, public_exponent, key_size, backend):
|
||||
warnings.warn(
|
||||
"generate is deprecated and will be removed in a future version.",
|
||||
utils.DeprecatedIn05,
|
||||
stacklevel=2
|
||||
)
|
||||
if not isinstance(backend, RSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement RSABackend",
|
||||
"Backend object does not implement RSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
return backend.generate_rsa_private_key(public_exponent, key_size)
|
||||
_verify_rsa_parameters(public_exponent, key_size)
|
||||
key = backend.generate_rsa_private_key(public_exponent, key_size)
|
||||
private_numbers = key.private_numbers()
|
||||
return RSAPrivateKey(
|
||||
p=private_numbers.p,
|
||||
q=private_numbers.q,
|
||||
dmp1=private_numbers.dmp1,
|
||||
dmq1=private_numbers.dmq1,
|
||||
iqmp=private_numbers.iqmp,
|
||||
private_exponent=private_numbers.d,
|
||||
public_exponent=private_numbers.public_numbers.e,
|
||||
modulus=private_numbers.public_numbers.n
|
||||
)
|
||||
|
||||
def signer(self, padding, algorithm, backend):
|
||||
if not isinstance(backend, RSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement RSABackend",
|
||||
"Backend object does not implement RSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -201,7 +261,7 @@ class RSAPrivateKey(object):
|
|||
def decrypt(self, ciphertext, padding, backend):
|
||||
if not isinstance(backend, RSABackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement RSABackend",
|
||||
"Backend object does not implement RSABackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -257,3 +317,88 @@ class RSAPrivateKey(object):
|
|||
@property
|
||||
def n(self):
|
||||
return self.modulus
|
||||
|
||||
|
||||
class RSAPrivateNumbers(object):
|
||||
def __init__(self, p, q, d, dmp1, dmq1, iqmp,
|
||||
public_numbers):
|
||||
if (
|
||||
not isinstance(p, six.integer_types) or
|
||||
not isinstance(q, six.integer_types) or
|
||||
not isinstance(d, six.integer_types) or
|
||||
not isinstance(dmp1, six.integer_types) or
|
||||
not isinstance(dmq1, six.integer_types) or
|
||||
not isinstance(iqmp, six.integer_types)
|
||||
):
|
||||
raise TypeError(
|
||||
"RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
|
||||
" all be an integers."
|
||||
)
|
||||
|
||||
if not isinstance(public_numbers, RSAPublicNumbers):
|
||||
raise TypeError(
|
||||
"RSAPrivateNumbers public_numbers must be an RSAPublicNumbers"
|
||||
" instance."
|
||||
)
|
||||
|
||||
self._p = p
|
||||
self._q = q
|
||||
self._d = d
|
||||
self._dmp1 = dmp1
|
||||
self._dmq1 = dmq1
|
||||
self._iqmp = iqmp
|
||||
self._public_numbers = public_numbers
|
||||
|
||||
@property
|
||||
def p(self):
|
||||
return self._p
|
||||
|
||||
@property
|
||||
def q(self):
|
||||
return self._q
|
||||
|
||||
@property
|
||||
def d(self):
|
||||
return self._d
|
||||
|
||||
@property
|
||||
def dmp1(self):
|
||||
return self._dmp1
|
||||
|
||||
@property
|
||||
def dmq1(self):
|
||||
return self._dmq1
|
||||
|
||||
@property
|
||||
def iqmp(self):
|
||||
return self._iqmp
|
||||
|
||||
@property
|
||||
def public_numbers(self):
|
||||
return self._public_numbers
|
||||
|
||||
def private_key(self, backend):
|
||||
return backend.load_rsa_private_numbers(self)
|
||||
|
||||
|
||||
class RSAPublicNumbers(object):
|
||||
def __init__(self, e, n):
|
||||
if (
|
||||
not isinstance(e, six.integer_types) or
|
||||
not isinstance(n, six.integer_types)
|
||||
):
|
||||
raise TypeError("RSAPublicNumbers arguments must be integers.")
|
||||
|
||||
self._e = e
|
||||
self._n = n
|
||||
|
||||
@property
|
||||
def e(self):
|
||||
return self._e
|
||||
|
||||
@property
|
||||
def n(self):
|
||||
return self._n
|
||||
|
||||
def public_key(self, backend):
|
||||
return backend.load_rsa_public_numbers(self)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ from cryptography.hazmat.primitives import interfaces
|
|||
def _verify_key_size(algorithm, key):
|
||||
# Verify that the key size matches the expected key size
|
||||
if len(key) * 8 not in algorithm.key_sizes:
|
||||
raise ValueError("Invalid key size ({0}) for {1}".format(
|
||||
raise ValueError("Invalid key size ({0}) for {1}.".format(
|
||||
len(key) * 8, algorithm.name
|
||||
))
|
||||
return key
|
||||
|
|
|
|||
|
|
@ -26,12 +26,14 @@ class Cipher(object):
|
|||
def __init__(self, algorithm, mode, backend):
|
||||
if not isinstance(backend, CipherBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement CipherBackend",
|
||||
"Backend object does not implement CipherBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
if not isinstance(algorithm, interfaces.CipherAlgorithm):
|
||||
raise TypeError("Expected interface of interfaces.CipherAlgorithm")
|
||||
raise TypeError(
|
||||
"Expected interface of interfaces.CipherAlgorithm."
|
||||
)
|
||||
|
||||
if mode is not None:
|
||||
mode.validate_for_algorithm(algorithm)
|
||||
|
|
@ -44,7 +46,7 @@ class Cipher(object):
|
|||
if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
|
||||
if self.mode.tag is not None:
|
||||
raise ValueError(
|
||||
"Authentication tag must be None when encrypting"
|
||||
"Authentication tag must be None when encrypting."
|
||||
)
|
||||
ctx = self._backend.create_symmetric_encryption_ctx(
|
||||
self.algorithm, self.mode
|
||||
|
|
@ -55,7 +57,7 @@ class Cipher(object):
|
|||
if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
|
||||
if self.mode.tag is None:
|
||||
raise ValueError(
|
||||
"Authentication tag must be provided when decrypting"
|
||||
"Authentication tag must be provided when decrypting."
|
||||
)
|
||||
ctx = self._backend.create_symmetric_decryption_ctx(
|
||||
self.algorithm, self.mode
|
||||
|
|
@ -79,12 +81,12 @@ class _CipherContext(object):
|
|||
|
||||
def update(self, data):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
return self._ctx.update(data)
|
||||
|
||||
def finalize(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
data = self._ctx.finalize()
|
||||
self._ctx = None
|
||||
return data
|
||||
|
|
@ -100,13 +102,13 @@ class _AEADCipherContext(object):
|
|||
|
||||
def update(self, data):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
self._updated = True
|
||||
return self._ctx.update(data)
|
||||
|
||||
def finalize(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
data = self._ctx.finalize()
|
||||
self._tag = self._ctx.tag
|
||||
self._ctx = None
|
||||
|
|
@ -114,9 +116,9 @@ class _AEADCipherContext(object):
|
|||
|
||||
def authenticate_additional_data(self, data):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
if self._updated:
|
||||
raise AlreadyUpdated("Update has been called on this context")
|
||||
raise AlreadyUpdated("Update has been called on this context.")
|
||||
self._ctx.authenticate_additional_data(data)
|
||||
|
||||
|
||||
|
|
@ -126,5 +128,5 @@ class _AEADEncryptionContext(_AEADCipherContext):
|
|||
def tag(self):
|
||||
if self._ctx is not None:
|
||||
raise NotYetFinalized("You must finalize encryption before "
|
||||
"getting the tag")
|
||||
"getting the tag.")
|
||||
return self._tag
|
||||
|
|
|
|||
|
|
@ -17,6 +17,13 @@ from cryptography import utils
|
|||
from cryptography.hazmat.primitives import interfaces
|
||||
|
||||
|
||||
def _check_iv_length(mode, algorithm):
|
||||
if len(mode.initialization_vector) * 8 != algorithm.block_size:
|
||||
raise ValueError("Invalid IV size ({0}) for {1}.".format(
|
||||
len(mode.initialization_vector), mode.name
|
||||
))
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.Mode)
|
||||
@utils.register_interface(interfaces.ModeWithInitializationVector)
|
||||
class CBC(object):
|
||||
|
|
@ -25,11 +32,7 @@ class CBC(object):
|
|||
def __init__(self, initialization_vector):
|
||||
self.initialization_vector = initialization_vector
|
||||
|
||||
def validate_for_algorithm(self, algorithm):
|
||||
if len(self.initialization_vector) * 8 != algorithm.block_size:
|
||||
raise ValueError("Invalid iv size ({0}) for {1}".format(
|
||||
len(self.initialization_vector), self.name
|
||||
))
|
||||
validate_for_algorithm = _check_iv_length
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.Mode)
|
||||
|
|
@ -48,11 +51,7 @@ class OFB(object):
|
|||
def __init__(self, initialization_vector):
|
||||
self.initialization_vector = initialization_vector
|
||||
|
||||
def validate_for_algorithm(self, algorithm):
|
||||
if len(self.initialization_vector) * 8 != algorithm.block_size:
|
||||
raise ValueError("Invalid iv size ({0}) for {1}".format(
|
||||
len(self.initialization_vector), self.name
|
||||
))
|
||||
validate_for_algorithm = _check_iv_length
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.Mode)
|
||||
|
|
@ -63,11 +62,18 @@ class CFB(object):
|
|||
def __init__(self, initialization_vector):
|
||||
self.initialization_vector = initialization_vector
|
||||
|
||||
def validate_for_algorithm(self, algorithm):
|
||||
if len(self.initialization_vector) * 8 != algorithm.block_size:
|
||||
raise ValueError("Invalid iv size ({0}) for {1}".format(
|
||||
len(self.initialization_vector), self.name
|
||||
))
|
||||
validate_for_algorithm = _check_iv_length
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.Mode)
|
||||
@utils.register_interface(interfaces.ModeWithInitializationVector)
|
||||
class CFB8(object):
|
||||
name = "CFB8"
|
||||
|
||||
def __init__(self, initialization_vector):
|
||||
self.initialization_vector = initialization_vector
|
||||
|
||||
validate_for_algorithm = _check_iv_length
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.Mode)
|
||||
|
|
@ -80,7 +86,7 @@ class CTR(object):
|
|||
|
||||
def validate_for_algorithm(self, algorithm):
|
||||
if len(self.nonce) * 8 != algorithm.block_size:
|
||||
raise ValueError("Invalid nonce size ({0}) for {1}".format(
|
||||
raise ValueError("Invalid nonce size ({0}) for {1}.".format(
|
||||
len(self.nonce), self.name
|
||||
))
|
||||
|
||||
|
|
@ -91,13 +97,16 @@ class CTR(object):
|
|||
class GCM(object):
|
||||
name = "GCM"
|
||||
|
||||
def __init__(self, initialization_vector, tag=None):
|
||||
def __init__(self, initialization_vector, tag=None, min_tag_length=16):
|
||||
# len(initialization_vector) must in [1, 2 ** 64), but it's impossible
|
||||
# to actually construct a bytes object that large, so we don't check
|
||||
# for it
|
||||
if tag is not None and len(tag) < 4:
|
||||
if min_tag_length < 4:
|
||||
raise ValueError("min_tag_length must be >= 4")
|
||||
if tag is not None and len(tag) < min_tag_length:
|
||||
raise ValueError(
|
||||
"Authentication tag must be 4 bytes or longer"
|
||||
"Authentication tag must be {0} bytes or longer.".format(
|
||||
min_tag_length)
|
||||
)
|
||||
|
||||
self.initialization_vector = initialization_vector
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
|
||||
|
|
@ -28,13 +26,13 @@ class CMAC(object):
|
|||
def __init__(self, algorithm, backend, ctx=None):
|
||||
if not isinstance(backend, CMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement CMACBackend",
|
||||
"Backend object does not implement CMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
if not isinstance(algorithm, interfaces.BlockCipherAlgorithm):
|
||||
raise TypeError(
|
||||
"Expected instance of interfaces.BlockCipherAlgorithm"
|
||||
"Expected instance of interfaces.BlockCipherAlgorithm."
|
||||
)
|
||||
self._algorithm = algorithm
|
||||
|
||||
|
|
@ -46,28 +44,28 @@ class CMAC(object):
|
|||
|
||||
def update(self, data):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
if isinstance(data, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before hashing")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("data must be bytes.")
|
||||
self._ctx.update(data)
|
||||
|
||||
def finalize(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
digest = self._ctx.finalize()
|
||||
self._ctx = None
|
||||
return digest
|
||||
|
||||
def verify(self, signature):
|
||||
if isinstance(signature, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before verifying")
|
||||
if not isinstance(signature, bytes):
|
||||
raise TypeError("signature must be bytes.")
|
||||
digest = self.finalize()
|
||||
if not constant_time.bytes_eq(digest, signature):
|
||||
raise InvalidSignature("Signature did not match digest.")
|
||||
|
||||
def copy(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
return CMAC(
|
||||
self._algorithm,
|
||||
backend=self._backend,
|
||||
|
|
|
|||
|
|
@ -13,12 +13,11 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import hmac
|
||||
import sys
|
||||
|
||||
import cffi
|
||||
|
||||
import six
|
||||
|
||||
from cryptography.hazmat.bindings.utils import _create_modulename
|
||||
|
||||
TYPES = """
|
||||
|
|
@ -55,9 +54,18 @@ _lib = _ffi.verify(
|
|||
ext_package="cryptography",
|
||||
)
|
||||
|
||||
if hasattr(hmac, "compare_digest"):
|
||||
def bytes_eq(a, b):
|
||||
if not isinstance(a, bytes) or not isinstance(b, bytes):
|
||||
raise TypeError("a and b must be bytes.")
|
||||
|
||||
def bytes_eq(a, b):
|
||||
if isinstance(a, six.text_type) or isinstance(b, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before comparing")
|
||||
return hmac.compare_digest(a, b)
|
||||
|
||||
return _lib.Cryptography_constant_time_bytes_eq(a, len(a), b, len(b)) == 1
|
||||
else:
|
||||
def bytes_eq(a, b):
|
||||
if not isinstance(a, bytes) or not isinstance(b, bytes):
|
||||
raise TypeError("a and b must be bytes.")
|
||||
|
||||
return _lib.Cryptography_constant_time_bytes_eq(
|
||||
a, len(a), b, len(b)
|
||||
) == 1
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
|
||||
|
|
@ -28,7 +26,7 @@ class Hash(object):
|
|||
def __init__(self, algorithm, backend, ctx=None):
|
||||
if not isinstance(backend, HashBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement HashBackend",
|
||||
"Backend object does not implement HashBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -45,21 +43,21 @@ class Hash(object):
|
|||
|
||||
def update(self, data):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
if isinstance(data, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before hashing")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("data must be bytes.")
|
||||
self._ctx.update(data)
|
||||
|
||||
def copy(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
return Hash(
|
||||
self.algorithm, backend=self._backend, ctx=self._ctx.copy()
|
||||
)
|
||||
|
||||
def finalize(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
digest = self._ctx.finalize()
|
||||
self._ctx = None
|
||||
return digest
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
|
||||
|
|
@ -28,7 +26,7 @@ class HMAC(object):
|
|||
def __init__(self, key, algorithm, backend, ctx=None):
|
||||
if not isinstance(backend, HMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement HMACBackend",
|
||||
"Backend object does not implement HMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -45,14 +43,14 @@ class HMAC(object):
|
|||
|
||||
def update(self, msg):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
if isinstance(msg, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before hashing")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
if not isinstance(msg, bytes):
|
||||
raise TypeError("msg must be bytes.")
|
||||
self._ctx.update(msg)
|
||||
|
||||
def copy(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
return HMAC(
|
||||
self._key,
|
||||
self.algorithm,
|
||||
|
|
@ -62,14 +60,14 @@ class HMAC(object):
|
|||
|
||||
def finalize(self):
|
||||
if self._ctx is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
digest = self._ctx.finalize()
|
||||
self._ctx = None
|
||||
return digest
|
||||
|
||||
def verify(self, signature):
|
||||
if isinstance(signature, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before verifying")
|
||||
if not isinstance(signature, bytes):
|
||||
raise TypeError("signature must be bytes.")
|
||||
digest = self.finalize()
|
||||
if not constant_time.bytes_eq(digest, signature):
|
||||
raise InvalidSignature("Signature did not match digest.")
|
||||
|
|
|
|||
|
|
@ -186,27 +186,15 @@ class HashContext(object):
|
|||
@six.add_metaclass(abc.ABCMeta)
|
||||
class RSAPrivateKey(object):
|
||||
@abc.abstractmethod
|
||||
def signer(self, padding, algorithm, backend):
|
||||
def signer(self, padding, algorithm):
|
||||
"""
|
||||
Returns an AsymmetricSignatureContext used for signing data.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def modulus(self):
|
||||
@abc.abstractmethod
|
||||
def decrypt(self, ciphertext, padding):
|
||||
"""
|
||||
The public modulus of the RSA key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def public_exponent(self):
|
||||
"""
|
||||
The public exponent of the RSA key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def private_exponent(self):
|
||||
"""
|
||||
The private exponent of the RSA key.
|
||||
Decrypts the provided ciphertext.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
|
|
@ -221,77 +209,28 @@ class RSAPrivateKey(object):
|
|||
The RSAPublicKey associated with this private key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def n(self):
|
||||
"""
|
||||
The public modulus of the RSA key. Alias for modulus.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def p(self):
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class RSAPrivateKeyWithNumbers(RSAPrivateKey):
|
||||
@abc.abstractmethod
|
||||
def private_numbers(self):
|
||||
"""
|
||||
One of the two primes used to generate d.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def q(self):
|
||||
"""
|
||||
One of the two primes used to generate d.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def d(self):
|
||||
"""
|
||||
The private exponent. This can be calculated using p and q. Alias for
|
||||
private_exponent.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def dmp1(self):
|
||||
"""
|
||||
A Chinese remainder theorem coefficient used to speed up RSA
|
||||
calculations. Calculated as: d mod (p-1)
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def dmq1(self):
|
||||
"""
|
||||
A Chinese remainder theorem coefficient used to speed up RSA
|
||||
calculations. Calculated as: d mod (q-1)
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def iqmp(self):
|
||||
"""
|
||||
A Chinese remainder theorem coefficient used to speed up RSA
|
||||
calculations. The modular inverse of q modulo p
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def e(self):
|
||||
"""
|
||||
The public exponent of the RSA key. Alias for public_exponent.
|
||||
Returns an RSAPrivateNumbers.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class RSAPublicKey(object):
|
||||
@abc.abstractmethod
|
||||
def verifier(self, signature, padding, algorithm, backend):
|
||||
def verifier(self, signature, padding, algorithm):
|
||||
"""
|
||||
Returns an AsymmetricVerificationContext used for verifying signatures.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def modulus(self):
|
||||
@abc.abstractmethod
|
||||
def encrypt(self, plaintext, padding):
|
||||
"""
|
||||
The public modulus of the RSA key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def public_exponent(self):
|
||||
"""
|
||||
The public exponent of the RSA key.
|
||||
Encrypts the given plaintext.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
|
|
@ -300,63 +239,31 @@ class RSAPublicKey(object):
|
|||
The bit length of the public modulus.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def n(self):
|
||||
"""
|
||||
The public modulus of the RSA key. Alias for modulus.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def e(self):
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class RSAPublicKeyWithNumbers(RSAPublicKey):
|
||||
@abc.abstractmethod
|
||||
def public_numbers(self):
|
||||
"""
|
||||
The public exponent of the RSA key. Alias for public_exponent.
|
||||
Returns an RSAPublicNumbers
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DSAParameters(object):
|
||||
@abc.abstractproperty
|
||||
def modulus(self):
|
||||
@abc.abstractmethod
|
||||
def generate_private_key(self):
|
||||
"""
|
||||
The prime modulus that's used in generating the DSA keypair and used
|
||||
in the DSA signing and verification processes.
|
||||
Generates and returns a DSAPrivateKey.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def subgroup_order(self):
|
||||
"""
|
||||
The subgroup order that's used in generating the DSA keypair
|
||||
by the generator and used in the DSA signing and verification
|
||||
processes.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def generator(self):
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DSAParametersWithNumbers(DSAParameters):
|
||||
@abc.abstractmethod
|
||||
def parameter_numbers(self):
|
||||
"""
|
||||
The generator that is used in generating the DSA keypair and used
|
||||
in the DSA signing and verification processes.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def p(self):
|
||||
"""
|
||||
The prime modulus that's used in generating the DSA keypair and used
|
||||
in the DSA signing and verification processes. Alias for modulus.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def q(self):
|
||||
"""
|
||||
The subgroup order that's used in generating the DSA keypair
|
||||
by the generator and used in the DSA signing and verification
|
||||
processes. Alias for subgroup_order.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def g(self):
|
||||
"""
|
||||
The generator that is used in generating the DSA keypair and used
|
||||
in the DSA signing and verification processes. Alias for generator.
|
||||
Returns a DSAParameterNumbers.
|
||||
"""
|
||||
|
||||
|
||||
|
|
@ -374,18 +281,6 @@ class DSAPrivateKey(object):
|
|||
The DSAPublicKey associated with this private key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def x(self):
|
||||
"""
|
||||
The private key "x" in the DSA structure.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def y(self):
|
||||
"""
|
||||
The public key.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def parameters(self):
|
||||
"""
|
||||
|
|
@ -393,6 +288,15 @@ class DSAPrivateKey(object):
|
|||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DSAPrivateKeyWithNumbers(DSAPrivateKey):
|
||||
@abc.abstractmethod
|
||||
def private_numbers(self):
|
||||
"""
|
||||
Returns a DSAPrivateNumbers.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DSAPublicKey(object):
|
||||
@abc.abstractproperty
|
||||
|
|
@ -401,12 +305,6 @@ class DSAPublicKey(object):
|
|||
The bit length of the prime modulus.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def y(self):
|
||||
"""
|
||||
The public key.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def parameters(self):
|
||||
"""
|
||||
|
|
@ -414,6 +312,15 @@ class DSAPublicKey(object):
|
|||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class DSAPublicKeyWithNumbers(DSAPublicKey):
|
||||
@abc.abstractmethod
|
||||
def public_numbers(self):
|
||||
"""
|
||||
Returns a DSAPublicNumbers.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class AsymmetricSignatureContext(object):
|
||||
@abc.abstractmethod
|
||||
|
|
@ -489,3 +396,63 @@ class CMACContext(object):
|
|||
"""
|
||||
Return a CMACContext that is a copy of the current context.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class EllipticCurve(object):
|
||||
@abc.abstractproperty
|
||||
def name(self):
|
||||
"""
|
||||
The name of the curve. e.g. secp256r1.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def key_size(self):
|
||||
"""
|
||||
The bit length of the base point of the curve.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class EllipticCurveSignatureAlgorithm(object):
|
||||
@abc.abstractproperty
|
||||
def algorithm(self):
|
||||
"""
|
||||
The digest algorithm used with this signature.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class EllipticCurvePrivateKey(object):
|
||||
@abc.abstractmethod
|
||||
def signer(self, signature_algorithm):
|
||||
"""
|
||||
Returns an AsymmetricSignatureContext used for signing data.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def public_key(self):
|
||||
"""
|
||||
The EllipticCurvePublicKey for this private key.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def curve(self):
|
||||
"""
|
||||
The EllipticCurve that this key is on.
|
||||
"""
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class EllipticCurvePublicKey(object):
|
||||
@abc.abstractmethod
|
||||
def verifier(self, signature, signature_algorithm):
|
||||
"""
|
||||
Returns an AsymmetricVerificationContext used for signing data.
|
||||
"""
|
||||
|
||||
@abc.abstractproperty
|
||||
def curve(self):
|
||||
"""
|
||||
The EllipticCurve that this key is on.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -28,12 +28,53 @@ class HKDF(object):
|
|||
def __init__(self, algorithm, length, salt, info, backend):
|
||||
if not isinstance(backend, HMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement HMACBackend",
|
||||
"Backend object does not implement HMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
self._algorithm = algorithm
|
||||
|
||||
if not isinstance(salt, bytes) and salt is not None:
|
||||
raise TypeError("salt must be bytes.")
|
||||
|
||||
if salt is None:
|
||||
salt = b"\x00" * (self._algorithm.digest_size // 8)
|
||||
|
||||
self._salt = salt
|
||||
|
||||
self._backend = backend
|
||||
|
||||
self._hkdf_expand = HKDFExpand(self._algorithm, length, info, backend)
|
||||
|
||||
def _extract(self, key_material):
|
||||
h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
|
||||
h.update(key_material)
|
||||
return h.finalize()
|
||||
|
||||
def derive(self, key_material):
|
||||
if not isinstance(key_material, bytes):
|
||||
raise TypeError("key_material must be bytes.")
|
||||
|
||||
return self._hkdf_expand.derive(self._extract(key_material))
|
||||
|
||||
def verify(self, key_material, expected_key):
|
||||
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
|
||||
raise InvalidKey
|
||||
|
||||
|
||||
@utils.register_interface(interfaces.KeyDerivationFunction)
|
||||
class HKDFExpand(object):
|
||||
def __init__(self, algorithm, length, info, backend):
|
||||
if not isinstance(backend, HMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement HMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
self._algorithm = algorithm
|
||||
|
||||
self._backend = backend
|
||||
|
||||
max_length = 255 * (algorithm.digest_size // 8)
|
||||
|
||||
if length > max_length:
|
||||
|
|
@ -44,32 +85,16 @@ class HKDF(object):
|
|||
|
||||
self._length = length
|
||||
|
||||
if isinstance(salt, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before using them as a salt.")
|
||||
|
||||
if salt is None:
|
||||
salt = b"\x00" * (self._algorithm.digest_size // 8)
|
||||
|
||||
self._salt = salt
|
||||
|
||||
if isinstance(info, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before using them as info.")
|
||||
if not isinstance(info, bytes) and info is not None:
|
||||
raise TypeError("info must be bytes.")
|
||||
|
||||
if info is None:
|
||||
info = b""
|
||||
|
||||
self._info = info
|
||||
self._backend = backend
|
||||
|
||||
self._used = False
|
||||
|
||||
def _extract(self, key_material):
|
||||
h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
|
||||
h.update(key_material)
|
||||
return h.finalize()
|
||||
|
||||
def _expand(self, key_material):
|
||||
output = [b""]
|
||||
counter = 1
|
||||
|
|
@ -85,17 +110,14 @@ class HKDF(object):
|
|||
return b"".join(output)[:self._length]
|
||||
|
||||
def derive(self, key_material):
|
||||
if isinstance(key_material, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before using them as key "
|
||||
"material."
|
||||
)
|
||||
if not isinstance(key_material, bytes):
|
||||
raise TypeError("key_material must be bytes.")
|
||||
|
||||
if self._used:
|
||||
raise AlreadyFinalized
|
||||
|
||||
self._used = True
|
||||
return self._expand(self._extract(key_material))
|
||||
return self._expand(key_material)
|
||||
|
||||
def verify(self, key_material, expected_key):
|
||||
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import six
|
||||
|
||||
from cryptography import utils
|
||||
from cryptography.exceptions import (
|
||||
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
|
||||
|
|
@ -28,38 +26,32 @@ class PBKDF2HMAC(object):
|
|||
def __init__(self, algorithm, length, salt, iterations, backend):
|
||||
if not isinstance(backend, PBKDF2HMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement PBKDF2HMACBackend",
|
||||
"Backend object does not implement PBKDF2HMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
if not backend.pbkdf2_hmac_supported(algorithm):
|
||||
raise UnsupportedAlgorithm(
|
||||
"{0} is not supported for PBKDF2 by this backend".format(
|
||||
"{0} is not supported for PBKDF2 by this backend.".format(
|
||||
algorithm.name),
|
||||
_Reasons.UNSUPPORTED_HASH
|
||||
)
|
||||
self._used = False
|
||||
self._algorithm = algorithm
|
||||
self._length = length
|
||||
if isinstance(salt, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before using them as key "
|
||||
"material."
|
||||
)
|
||||
if not isinstance(salt, bytes):
|
||||
raise TypeError("salt must be bytes.")
|
||||
self._salt = salt
|
||||
self._iterations = iterations
|
||||
self._backend = backend
|
||||
|
||||
def derive(self, key_material):
|
||||
if self._used:
|
||||
raise AlreadyFinalized("PBKDF2 instances can only be used once")
|
||||
raise AlreadyFinalized("PBKDF2 instances can only be used once.")
|
||||
self._used = True
|
||||
|
||||
if isinstance(key_material, six.text_type):
|
||||
raise TypeError(
|
||||
"Unicode-objects must be encoded before using them as key "
|
||||
"material."
|
||||
)
|
||||
if not isinstance(key_material, bytes):
|
||||
raise TypeError("key_material must be bytes.")
|
||||
return self._backend.derive_pbkdf2_hmac(
|
||||
self._algorithm,
|
||||
self._length,
|
||||
|
|
|
|||
|
|
@ -79,10 +79,10 @@ _lib = _ffi.verify(
|
|||
class PKCS7(object):
|
||||
def __init__(self, block_size):
|
||||
if not (0 <= block_size < 256):
|
||||
raise ValueError("block_size must be in range(0, 256)")
|
||||
raise ValueError("block_size must be in range(0, 256).")
|
||||
|
||||
if block_size % 8 != 0:
|
||||
raise ValueError("block_size must be a multiple of 8")
|
||||
raise ValueError("block_size must be a multiple of 8.")
|
||||
|
||||
self.block_size = block_size
|
||||
|
||||
|
|
@ -102,10 +102,10 @@ class _PKCS7PaddingContext(object):
|
|||
|
||||
def update(self, data):
|
||||
if self._buffer is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
|
||||
if isinstance(data, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before padding")
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("data must be bytes.")
|
||||
|
||||
self._buffer += data
|
||||
|
||||
|
|
@ -118,7 +118,7 @@ class _PKCS7PaddingContext(object):
|
|||
|
||||
def finalize(self):
|
||||
if self._buffer is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
|
||||
pad_size = self.block_size // 8 - len(self._buffer)
|
||||
result = self._buffer + six.int2byte(pad_size) * pad_size
|
||||
|
|
@ -135,10 +135,10 @@ class _PKCS7UnpaddingContext(object):
|
|||
|
||||
def update(self, data):
|
||||
if self._buffer is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
|
||||
if isinstance(data, six.text_type):
|
||||
raise TypeError("Unicode-objects must be encoded before unpadding")
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("data must be bytes.")
|
||||
|
||||
self._buffer += data
|
||||
|
||||
|
|
@ -154,17 +154,17 @@ class _PKCS7UnpaddingContext(object):
|
|||
|
||||
def finalize(self):
|
||||
if self._buffer is None:
|
||||
raise AlreadyFinalized("Context was already finalized")
|
||||
raise AlreadyFinalized("Context was already finalized.")
|
||||
|
||||
if len(self._buffer) != self.block_size // 8:
|
||||
raise ValueError("Invalid padding bytes")
|
||||
raise ValueError("Invalid padding bytes.")
|
||||
|
||||
valid = _lib.Cryptography_check_pkcs7_padding(
|
||||
self._buffer, self.block_size // 8
|
||||
)
|
||||
|
||||
if not valid:
|
||||
raise ValueError("Invalid padding bytes")
|
||||
raise ValueError("Invalid padding bytes.")
|
||||
|
||||
pad_size = six.indexbytes(self._buffer, -1)
|
||||
res = self._buffer[:-pad_size]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
|
||||
def load_pem_traditional_openssl_private_key(data, password, backend):
|
||||
return backend.load_traditional_openssl_pem_private_key(
|
||||
data, password
|
||||
)
|
||||
|
||||
|
||||
def load_pem_pkcs8_private_key(data, password, backend):
|
||||
return backend.load_pkcs8_pem_private_key(
|
||||
data, password
|
||||
)
|
||||
|
|
@ -29,7 +29,7 @@ class HOTP(object):
|
|||
def __init__(self, key, length, algorithm, backend):
|
||||
if not isinstance(backend, HMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement HMACBackend",
|
||||
"Backend object does not implement HMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -37,13 +37,13 @@ class HOTP(object):
|
|||
raise ValueError("Key length has to be at least 128 bits.")
|
||||
|
||||
if not isinstance(length, six.integer_types):
|
||||
raise TypeError("Length parameter must be an integer type")
|
||||
raise TypeError("Length parameter must be an integer type.")
|
||||
|
||||
if length < 6 or length > 8:
|
||||
raise ValueError("Length of HOTP has to be between 6 to 8.")
|
||||
|
||||
if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
|
||||
raise TypeError("Algorithm must be SHA1, SHA256 or SHA512")
|
||||
raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.")
|
||||
|
||||
self._key = key
|
||||
self._length = length
|
||||
|
|
@ -57,15 +57,13 @@ class HOTP(object):
|
|||
|
||||
def verify(self, hotp, counter):
|
||||
if not constant_time.bytes_eq(self.generate(counter), hotp):
|
||||
raise InvalidToken("Supplied HOTP value does not match")
|
||||
raise InvalidToken("Supplied HOTP value does not match.")
|
||||
|
||||
def _dynamic_truncate(self, counter):
|
||||
ctx = hmac.HMAC(self._key, self._algorithm, self._backend)
|
||||
ctx.update(struct.pack(">Q", counter))
|
||||
hmac_value = ctx.finalize()
|
||||
|
||||
offset_bits = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
|
||||
|
||||
offset = int(offset_bits)
|
||||
offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
|
||||
p = hmac_value[offset:offset + 4]
|
||||
return struct.unpack(">I", p)[0] & 0x7fffffff
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class TOTP(object):
|
|||
def __init__(self, key, length, algorithm, time_step, backend):
|
||||
if not isinstance(backend, HMACBackend):
|
||||
raise UnsupportedAlgorithm(
|
||||
"Backend object does not implement HMACBackend",
|
||||
"Backend object does not implement HMACBackend.",
|
||||
_Reasons.BACKEND_MISSING_INTERFACE
|
||||
)
|
||||
|
||||
|
|
@ -38,4 +38,4 @@ class TOTP(object):
|
|||
|
||||
def verify(self, totp, time):
|
||||
if not constant_time.bytes_eq(self.generate(time), totp):
|
||||
raise InvalidToken("Supplied TOTP value does not match")
|
||||
raise InvalidToken("Supplied TOTP value does not match.")
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ from __future__ import absolute_import, division, print_function
|
|||
import sys
|
||||
|
||||
|
||||
DeprecatedIn04 = PendingDeprecationWarning
|
||||
DeprecatedIn04 = DeprecationWarning
|
||||
DeprecatedIn05 = PendingDeprecationWarning
|
||||
|
||||
|
||||
def register_interface(iface):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue