Update bundled Botan library to version 2.8

Change-Id: Ie8fb13f096a3a8658f6bde3d21f46ea453dc627f
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
Christian Kandeler
2018-10-11 15:04:05 +02:00
parent 8f29b0bcde
commit d3cc47f757
141 changed files with 3141 additions and 1191 deletions

View File

@@ -276,7 +276,7 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes
else:
raise InternalError("Unknown src info type '%s'" % (typ))
def process_command_line(args): # pylint: disable=too-many-locals
def process_command_line(args): # pylint: disable=too-many-locals,too-many-statements
"""
Handle command line options
Do not use logging in this method as command line options need to be
@@ -469,6 +469,9 @@ def process_command_line(args): # pylint: disable=too-many-locals
build_group.add_option('--with-debug-asserts', action='store_true', default=False,
help=optparse.SUPPRESS_HELP)
build_group.add_option('--ack-vc2013-deprecated', action='store_true', default=False,
help=optparse.SUPPRESS_HELP)
docs_group = optparse.OptionGroup(parser, 'Documentation Options')
docs_group.add_option('--with-documentation', action='store_true',
@@ -520,7 +523,7 @@ def process_command_line(args): # pylint: disable=too-many-locals
help='minimize build')
# Should be derived from info.txt but this runs too early
third_party = ['bearssl', 'boost', 'bzip2', 'lzma', 'openssl', 'sqlite3', 'zlib', 'tpm']
third_party = ['bearssl', 'boost', 'bzip2', 'lzma', 'openssl', 'commoncrypto', 'sqlite3', 'zlib', 'tpm']
for mod in third_party:
mods_group.add_option('--with-%s' % (mod),
@@ -754,6 +757,7 @@ class ModuleInfo(InfoObject):
"""
def __init__(self, infofile):
# pylint: disable=too-many-statements
super(ModuleInfo, self).__init__(infofile)
lex = lex_me_harder(
infofile,
@@ -850,7 +854,7 @@ class ModuleInfo(InfoObject):
for key, value in defines.items():
if not re.match('^[0-9A-Za-z_]{3,30}$', key):
raise InternalError('Module defines key has invalid format: "%s"' % key)
if not re.match('^[0-9]{8}$', value):
if not re.match('^20[0-9]{6}$', value):
raise InternalError('Module defines value has invalid format: "%s"' % value)
def cross_check(self, arch_info, cc_info, all_os_features):
@@ -959,7 +963,7 @@ class ModuleInfo(InfoObject):
def dependencies(self, osinfo):
# base is an implicit dep for all submodules
deps = ['base']
if self.parent_module != None:
if self.parent_module is not None:
deps.append(self.parent_module)
for req in self.requires:
@@ -1173,22 +1177,22 @@ class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes
return self.visibility_attribute
return ''
def mach_abi_link_flags(self, options, with_debug_info=None):
def mach_abi_link_flags(self, options, debug_mode=None):
#pylint: disable=too-many-branches
"""
Return the machine specific ABI flags
"""
if with_debug_info is None:
with_debug_info = options.with_debug_info
if debug_mode is None:
debug_mode = options.debug_mode
def mach_abi_groups():
yield 'all'
if options.msvc_runtime is None:
if with_debug_info:
if debug_mode:
yield 'rt-debug'
else:
yield 'rt'
@@ -1205,7 +1209,7 @@ class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes
for what in mach_abi_groups():
if what in self.mach_abi_linking:
flag = self.mach_abi_linking.get(what)
if flag != None and flag != '' and flag not in abi_link:
if flag is not None and flag != '' and flag not in abi_link:
abi_link.add(flag)
if options.msvc_runtime:
@@ -1418,7 +1422,7 @@ class OsInfo(InfoObject): # pylint: disable=too-many-instance-attributes
return False
def building_shared_supported(self):
return self.soname_pattern_base != None
return self.soname_pattern_base is not None
def enabled_features(self, options):
feats = []
@@ -1466,7 +1470,7 @@ def guess_processor(archinfo):
for info_part in system_cpu_info():
if info_part:
match = canon_processor(archinfo, info_part)
if match != None:
if match is not None:
logging.debug("Matched '%s' to processor '%s'" % (info_part, match))
return match, info_part
else:
@@ -1727,13 +1731,13 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
"""
Figure out what external libraries/frameworks are needed based on selected modules
"""
if not (module_member_name == 'libs' or module_member_name == 'frameworks'):
if module_member_name not in ['libs', 'frameworks']:
raise InternalError("Invalid argument")
libs = set()
for module in modules:
for (osname, module_link_to) in getattr(module, module_member_name).items():
if osname == 'all' or osname == osinfo.basename:
if osname in ['all', osinfo.basename]:
libs |= set(module_link_to)
else:
match = re.match('^all!(.*)', osname)
@@ -1787,7 +1791,7 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
return osinfo.ar_command
def choose_endian(arch_info, options):
if options.with_endian != None:
if options.with_endian is not None:
return options.with_endian
if options.cpu.endswith('eb') or options.cpu.endswith('be'):
@@ -1795,7 +1799,8 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
elif options.cpu.endswith('el') or options.cpu.endswith('le'):
return 'little'
logging.info('Defaulting to assuming %s endian', arch_info.endian)
if arch_info.endian:
logging.info('Defaulting to assuming %s endian', arch_info.endian)
return arch_info.endian
build_dir = options.with_build_dir or os.path.curdir
@@ -1863,6 +1868,7 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
'with_rst2man': options.with_rst2man,
'sphinx_config_dir': source_paths.sphinx_config_dir,
'with_doxygen': options.with_doxygen,
'maintainer_mode': options.maintainer_mode,
'out_dir': build_dir,
'build_dir': build_paths.build_dir,
@@ -1968,6 +1974,7 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
'with_openmp': options.with_openmp,
'with_debug_asserts': options.with_debug_asserts,
'test_mode': options.test_mode,
'optimize_for_size': options.optimize_for_size,
'mod_list': sorted([m.basename for m in modules])
}
@@ -1980,15 +1987,15 @@ def create_template_vars(source_paths, build_paths, options, modules, cc, arch,
variables['static_suffix'])
if options.build_shared_lib:
if osinfo.soname_pattern_base != None:
if osinfo.soname_pattern_base is not None:
variables['soname_base'] = osinfo.soname_pattern_base.format(**variables)
variables['shared_lib_name'] = variables['soname_base']
if osinfo.soname_pattern_abi != None:
if osinfo.soname_pattern_abi is not None:
variables['soname_abi'] = osinfo.soname_pattern_abi.format(**variables)
variables['shared_lib_name'] = variables['soname_abi']
if osinfo.soname_pattern_patch != None:
if osinfo.soname_pattern_patch is not None:
variables['soname_patch'] = osinfo.soname_pattern_patch.format(**variables)
variables['lib_link_cmd'] = variables['lib_link_cmd'].format(**variables)
@@ -2035,15 +2042,15 @@ class ModulesChooser(object):
self._modules, self._options.enabled_modules, self._options.disabled_modules)
def _check_usable(self, module, modname):
if not module.compatible_os(self._osinfo, self._options):
if not module.compatible_cpu(self._archinfo, self._options):
self._not_using_because['incompatible CPU'].add(modname)
return False
elif not module.compatible_os(self._osinfo, self._options):
self._not_using_because['incompatible OS'].add(modname)
return False
elif not module.compatible_compiler(self._ccinfo, self._cc_min_version, self._archinfo.basename):
self._not_using_because['incompatible compiler'].add(modname)
return False
elif not module.compatible_cpu(self._archinfo, self._options):
self._not_using_because['incompatible CPU'].add(modname)
return False
return True
@staticmethod
@@ -2265,11 +2272,13 @@ def choose_link_method(options):
# Symbolic link support on Windows was introduced in Windows 6.0 (Vista) and Python 3.2
# Furthermore the SeCreateSymbolicLinkPrivilege is required in order to successfully create symlinks
# So only try to use symlinks on Windows if explicitly requested
if req == 'symlink' and options.os == 'windows':
yield 'symlink'
# otherwise keep old conservative behavior
if 'symlink' in os.__dict__ and options.os != 'windows':
if options.os in ['windows', 'mingw', 'cygwin']:
if req == 'symlink':
yield 'symlink'
elif 'symlink' in os.__dict__:
yield 'symlink'
if 'link' in os.__dict__:
yield 'hardlink'
yield 'copy'
@@ -2352,16 +2361,10 @@ class AmalgamationHeader(object):
self.included_already = set()
self.all_std_includes = set()
encoding_kwords = {}
if sys.version_info[0] == 3:
encoding_kwords['encoding'] = 'utf8'
self.file_contents = {}
for filepath in sorted(input_filepaths):
try:
with open(filepath, **encoding_kwords) as f:
raw_content = f.readlines()
contents = AmalgamationGenerator.strip_header_goop(filepath, raw_content)
contents = AmalgamationGenerator.read_header(filepath)
self.file_contents[os.path.basename(filepath)] = contents
except IOError as e:
logging.error('Error processing file %s for amalgamation: %s' % (filepath, e))
@@ -2438,6 +2441,15 @@ class AmalgamationGenerator(object):
_header_guard_pattern = re.compile('^#define BOTAN_.*_H_$')
@staticmethod
def read_header(filepath):
encoding_kwords = {}
if sys.version_info[0] == 3:
encoding_kwords['encoding'] = 'utf8'
with open(filepath, **encoding_kwords) as f:
raw_content = f.readlines()
return AmalgamationGenerator.strip_header_goop(filepath, raw_content)
@staticmethod
def strip_header_goop(header_name, header_lines):
lines = copy.copy(header_lines) # defensive copy
@@ -2505,16 +2517,32 @@ class AmalgamationGenerator(object):
logging.info('Writing amalgamation header to %s' % (header_name))
pub_header_amalag.write_to_file(header_name, "BOTAN_AMALGAMATION_H_")
internal_headers = AmalgamationHeader(self._build_paths.internal_headers)
isa_headers = {}
internal_headers = []
def known_isa_header(hdr):
if hdr == 'simd_avx2.h':
return 'avx2'
return None
for hdr in self._build_paths.internal_headers:
isa = known_isa_header(os.path.basename(hdr))
if isa:
isa_headers[isa] = ''.join(AmalgamationGenerator.read_header(hdr))
else:
internal_headers.append(hdr)
internal_headers = AmalgamationHeader(internal_headers)
header_int_name = '%s_internal.h' % (AmalgamationGenerator.filename_prefix)
logging.info('Writing amalgamation header to %s' % (header_int_name))
internal_headers.write_to_file(header_int_name, "BOTAN_AMALGAMATION_INTERNAL_H_")
header_files = [header_name, header_int_name]
included_in_headers = pub_header_amalag.all_std_includes | internal_headers.all_std_includes
return header_files, included_in_headers
return header_files, included_in_headers, isa_headers
def _generate_sources(self, amalgamation_headers, included_in_headers): #pylint: disable=too-many-locals,too-many-branches
def _generate_sources(self, amalgamation_headers, included_in_headers, isa_headers):
#pylint: disable=too-many-locals,too-many-branches
encoding_kwords = {}
if sys.version_info[0] == 3:
encoding_kwords['encoding'] = 'utf8'
@@ -2533,6 +2561,14 @@ class AmalgamationGenerator(object):
logging.info('Writing amalgamation source to %s' % (filepath))
amalgamation_files[target] = open(filepath, 'w', **encoding_kwords)
def gcc_isa(isa):
if isa == 'sse41':
return 'sse4.1'
elif isa == 'sse42':
return 'ssse4.2'
else:
return isa
for target, f in amalgamation_files.items():
AmalgamationHeader.write_banner(f)
f.write('\n')
@@ -2542,13 +2578,11 @@ class AmalgamationGenerator(object):
for isa in self._isas_for_target(target):
if isa == 'sse41':
isa = 'sse4.1'
elif isa == 'sse42':
isa = 'ssse4.2'
if isa in isa_headers:
f.write(isa_headers[isa])
f.write('#if defined(__GNUG__) && !defined(__clang__)\n')
f.write('#pragma GCC target ("%s")\n' % (isa))
f.write('#pragma GCC target ("%s")\n' % (gcc_isa(isa)))
f.write('#endif\n')
# target to include header map
@@ -2580,8 +2614,8 @@ class AmalgamationGenerator(object):
return set(amalgamation_sources.values())
def generate(self):
amalgamation_headers, included_in_headers = self._generate_headers()
amalgamation_sources = self._generate_sources(amalgamation_headers, included_in_headers)
amalgamation_headers, included_in_headers, isa_headers = self._generate_headers()
amalgamation_sources = self._generate_sources(amalgamation_headers, included_in_headers, isa_headers)
return (sorted(amalgamation_sources), sorted(amalgamation_headers))
@@ -2712,7 +2746,7 @@ def set_defaults_for_unset_options(options, info_arch, info_cc): # pylint: disab
return 'gcc'
return None
if options.compiler is None and options.compiler_binary != None:
if options.compiler is None and options.compiler_binary is not None:
options.compiler = deduce_compiler_type_from_cc_bin(options.compiler_binary)
if options.compiler is None:
@@ -2836,7 +2870,7 @@ def validate_options(options, info_os, info_cc, available_module_policies):
if options.os != options.cpu:
raise UserError('LLVM target requires both CPU and OS be set to llvm')
if options.build_fuzzers != None:
if options.build_fuzzers is not None:
if options.build_fuzzers not in ['libfuzzer', 'afl', 'klee', 'test']:
raise UserError('Bad value to --build-fuzzers')
@@ -2932,7 +2966,10 @@ def calculate_cc_min_version(options, ccinfo, source_paths):
if ccinfo.basename == 'msvc':
if major_version == 18:
logging.warning('MSVC 2013 support is deprecated and will be removed in a future release')
logging.warning('MSVC 2013 support is deprecated, and will be removed in Jan 2019')
if not options.ack_vc2013_deprecated:
logging.error('Acknowledge this deprecation by adding flag --ack-vc2013-deprecated')
return cc_version
def check_compiler_arch(options, ccinfo, archinfo, source_paths):
@@ -2941,7 +2978,10 @@ def check_compiler_arch(options, ccinfo, archinfo, source_paths):
abi_flags = ccinfo.mach_abi_link_flags(options).split(' ')
cc_output = run_compiler_preproc(options, ccinfo, detect_version_source, 'UNKNOWN', abi_flags).lower()
if cc_output in ['', 'unknown']:
if cc_output == '':
cc_output = run_compiler_preproc(options, ccinfo, detect_version_source, 'UNKNOWN').lower()
if cc_output == 'unknown':
logging.warning('Unable to detect target architecture via compiler macro checks')
return None
@@ -2954,7 +2994,7 @@ def check_compiler_arch(options, ccinfo, archinfo, source_paths):
return cc_output
def do_io_for_build(cc, arch, osinfo, using_mods, build_paths, source_paths, template_vars, options):
# pylint: disable=too-many-locals,too-many-branches
# pylint: disable=too-many-locals,too-many-branches,too-many-statements
try:
robust_rmtree(build_paths.build_dir)
@@ -3165,10 +3205,8 @@ if __name__ == '__main__':
logging.error("""%s
An internal error occurred.
Don't panic, this is probably not your fault!
Please report the entire output at https://github.com/randombit/botan or email
to the mailing list https://lists.randombit.net/mailman/listinfo/botan-devel
Don't panic, this is probably not your fault! Please open an issue
with the entire output at https://github.com/randombit/botan
You'll meet friendly people happy to help!""" % traceback.format_exc())

View File

@@ -1,50 +1,36 @@
Botan: Crypto and TLS for C++11
Botan: Crypto and TLS for Modern C++
========================================
Botan (Japanese for peony) is a cryptography library written in C++11
and released under the permissive `Simplified BSD
<https://botan.randombit.net/license.txt>`_ license.
Botan (Japanese for peony flower) is a C++ cryptography library released under the
permissive `Simplified BSD <https://botan.randombit.net/license.txt>`_ license.
Botan's goal is to be the best option for cryptography in C++ by offering the
tools necessary to implement a range of practical systems, such as TLS/DTLS,
tools necessary to implement a range of practical systems, such as TLS protocol,
X.509 certificates, modern AEAD ciphers, PKCS#11 and TPM hardware support,
password hashing, and post quantum crypto schemes. Botan also has a C89 API
specifically designed to be easy to call from other languages. A Python binding
using ctypes is included, and several other `language bindings
password hashing, and post quantum crypto schemes.
See the `documentation <https://botan.randombit.net/manual>`_ for more information.
A Python binding is included, and several other `language bindings
<https://github.com/randombit/botan/wiki/Language-Bindings>`_ are available.
Find the full feature list below.
Development is coordinated on `GitHub <https://github.com/randombit/botan>`_
and contributions are welcome (read `doc/contributing.rst` for more info).
If you need help with a problem, please open an `issue on GitHub
<https://github.com/randombit/botan/issues>`_ or email the
`botan-devel mailing list
<https://lists.randombit.net/mailman/listinfo/botan-devel/>`_.
New releases are announced on the
`botan-announce mailing list
and contributions are welcome. If you need help, please open an issue on
`GitHub <https://github.com/randombit/botan/issues>`_ or email the
`botan-devel mailing list <https://lists.randombit.net/mailman/listinfo/botan-devel/>`_.
New releases are announced on the `botan-announce mailing list
<https://lists.randombit.net/mailman/listinfo/botan-announce/>`_.
If you think you have found a security issue, see the `security page
<https://botan.randombit.net/security.html>`_ for contact information.
If you think you have found a security bug in Botan please contact
Jack Lloyd by emailing jack@randombit.net. His PGP public key with
fingerprint 4E60C73551AF2188DF0A5A6278E9804357123B60 can can be found
in ``doc/pgpkey.txt`` in the distribution,
https://keybase.io/jacklloyd, and some public PGP key servers.
.. highlight:: none
For all the details on building the library, read the
`users manual <https://botan.randombit.net/manual>`_, but basically::
$ ./configure.py
$ make
$ ./botan-test
...
$ make install
Botan can also be built into a single-file amalgamation for easy inclusion into
external build systems, see the manual for details.
The latest release is
`2.8.0 <https://botan.randombit.net/releases/Botan-2.8.0.tgz>`_
`(sig) <https://botan.randombit.net/releases/Botan-2.8.0.tgz.asc>`_,
released on 2018-10-01.
All releases are signed with a `PGP key <https://botan.randombit.net/pgpkey.txt>`_.
See the `release notes <https://botan.randombit.net/news.html>`_ for
what is new. Botan is also available through most
`distributions <https://github.com/randombit/botan/wiki/Distros>`_
such as Fedora, Debian, Arch and Homebrew.
.. image:: https://travis-ci.org/randombit/botan.svg?branch=master
:target: https://travis-ci.org/randombit/botan
@@ -66,55 +52,10 @@ external build systems, see the manual for details.
:target: https://scan.coverity.com/projects/624
:alt: Coverity results
.. image:: https://sonarcloud.io/api/project_badges/measure?project=botan&metric=ncloc
:target: https://sonarcloud.io/dashboard/index/botan
:alt: Sonarcloud analysis
.. image:: https://bestpractices.coreinfrastructure.org/projects/531/badge
:target: https://bestpractices.coreinfrastructure.org/projects/531
:alt: CII Best Practices statement
Release Downloads
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
See the `release notes <https://botan.randombit.net/news.html>`_ and
`security advisories <https://botan.randombit.net/security.html>`_
All releases are signed with a
`PGP key <https://botan.randombit.net/pgpkey.txt>`_::
pub 2048R/EFBADFBC 2004-10-30
Key fingerprint = 621D AF64 11E1 851C 4CF9 A2E1 6211 EBF1 EFBA DFBC
uid Botan Distribution Key
Some `distributions <https://github.com/randombit/botan/wiki/Distros>`_
such as Arch, Fedora and Debian include packages for Botan. However
these are often out of date; using the latest source release is recommended.
Current Stable Release
----------------------------------------
Version 2 requires a C++11 compiler; GCC 4.8 and later, Clang 3.8 and later, and
MSVC 2015/2017 are regularly tested. New releases of Botan 2 are made on a
quarterly basis.
The latest 2.x release is
`2.7.0 <https://botan.randombit.net/releases/Botan-2.7.0.tgz>`_
`(sig) <https://botan.randombit.net/releases/Botan-2.7.0.tgz.asc>`_
released on 2018-07-02
Old Release
----------------------------------------
The 1.10 branch is the last version of the library written in C++98. It is no
longer supported except for critical security updates (with all support ending
in December 2018), and the developers do not recommend its use anymore.
The latest 1.10 release is
`1.10.17 <https://botan.randombit.net/releases/Botan-1.10.17.tgz>`_
`(sig) <https://botan.randombit.net/releases/Botan-1.10.17.tgz.asc>`_
released on 2017-10-02
Find Enclosed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -123,8 +64,8 @@ Transport Layer Security (TLS) Protocol
* TLS v1.0, v1.1, and v1.2. The broken SSLv3 protocol is no longer supported.
* DTLS v1.0 and v1.2 are adaptations of TLS to datagram operation.
* Extensions include session tickets, SNI, ALPN, OCSP staple requests (client
side only right now), encrypt-then-mac CBC, and extended master secret.
* Supported extensions include session tickets, SNI, ALPN, OCSP stapling,
encrypt-then-mac CBC, and extended master secret.
* Supports authentication using preshared keys (PSK) or passwords (SRP)
* Supports record encryption with ChaCha20Poly1305, AES/OCB, AES/GCM, AES/CCM,
Camellia/GCM as well as legacy CBC ciphersuites.
@@ -144,7 +85,7 @@ Public Key Cryptography
* RSA signatures and encryption
* DH and ECDH key agreement
* Signature schemes ECDSA, DSA, Ed25519, ECGDSA, ECKCDSA, SM2, and GOST 34.10-2001
* Signature schemes ECDSA, DSA, Ed25519, ECGDSA, ECKCDSA, SM2, GOST 34.10-2001
* Post-quantum signature scheme XMSS
* Post-quantum key agreement schemes McEliece and NewHope
* ElGamal encryption
@@ -153,17 +94,15 @@ Public Key Cryptography
Ciphers, hashes, MACs, and checksums
----------------------------------------
* Authenticated cipher modes EAX, OCB, GCM, SIV, CCM, and ChaCha20Poly1305
* Cipher modes CTR, CBC, XTS, CFB, and OFB
* Block ciphers AES, ARIA, Blowfish, Camellia, CAST-128, CAST-256,
DES/3DES, GOST 28147, IDEA, KASUMI, Lion, MISTY1, Noekeon, SEED,
Serpent, SHACAL2, SM4, Threefish-512, Twofish, XTEA
* Stream ciphers ChaCha20, Salsa20/XSalsa20, SHAKE-128, and RC4
* Hash functions SHA-1, SHA-2, SHA-3, RIPEMD-160, Skein-512,
BLAKE2b, SM3, Tiger, Whirlpool, GOST 34.11, MD5, MD4
* Hash function combiners Parallel and Comb4P
* Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, CBC-MAC, X9.19 DES-MAC
* Non-cryptographic checksums Adler32, CRC24, and CRC32
* Authenticated cipher modes EAX, OCB, GCM, SIV, CCM, (X)ChaCha20Poly1305
* Cipher modes CTR, CBC, XTS, CFB, OFB
* Block ciphers AES, ARIA, Blowfish, Camellia, CAST-128, DES/3DES, GOST 28147,
IDEA, Lion, Noekeon, SEED, Serpent, SHACAL2, SM4, Threefish-512, Twofish, XTEA
* Stream ciphers (X)ChaCha20, (X)Salsa20, SHAKE-128, RC4
* Hash functions SHA-1, SHA-2, SHA-3, MD4, MD5, RIPEMD-160, BLAKE2b,
Skein-512, SM3, Tiger, Whirlpool, GOST 34.11
* Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, X9.19 DES-MAC
* Non-cryptographic checksums Adler32, CRC24, CRC32
Other Useful Things
----------------------------------------
@@ -173,8 +112,7 @@ Other Useful Things
* Simple compression API wrapping zlib, bzip2, and lzma libraries
* RNG wrappers for system RNG and hardware RNGs
* HMAC_DRBG and entropy collection system for userspace RNGs
* Password based key derivation functions PBKDF2 and Scrypt
* Password hashing function bcrypt and passhash9 (custom PBKDF scheme)
* Password hashing schemes PBKDF2, Scrypt, bcrypt
* SRP-6a password authenticated key exchange
* Key derivation functions including HKDF, KDF2, SP 800-108, SP 800-56A, SP 800-56C
* HOTP and TOTP algorithms

View File

@@ -12,4 +12,8 @@ armv8-a
<isa_extensions>
neon
armv8crypto
armv8sm3
armv8sm4
armv8sha3
armv8sha512
</isa_extensions>

View File

@@ -6,6 +6,7 @@ wordsize 64
<aliases>
powerpc64
ppc64le
ppc64el
</aliases>
<isa_extensions>

View File

@@ -1 +1,2 @@
family riscv
endian little

View File

@@ -1,2 +1,3 @@
family sparc
wordsize 64
endian big

View File

@@ -12,6 +12,7 @@ x86pc # for QNX
bepc # for Haiku
i686
i586
i386
</aliases>

View File

@@ -74,7 +74,10 @@ WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
%{if maintainer_mode}
WARN_AS_ERROR = YES
%{endif}
#---------------------------------------------------------------------------
# configuration options related to the input files
@@ -154,14 +157,17 @@ PREDEFINED = BOTAN_HAS_AES_ARMV8 \
BOTAN_HAS_AES_POWER8 \
BOTAN_HAS_AES_SSSE3 \
BOTAN_HAS_CHACHA_SSE2 \
BOTAN_HAS_CHACHA_AVX2 \
BOTAN_HAS_IDEA_SSE2 \
BOTAN_HAS_NOEKEON_SIMD \
BOTAN_HAS_SERPENT_SIMD \
BOTAN_HAS_SERPENT_AVX2 \
BOTAN_HAS_SHA1_SSE2 \
BOTAN_HAS_SHA2_32_X86 \
BOTAN_HAS_SHA2_32_X86_BMI2 \
BOTAN_HAS_SHACAL2_SIMD \
BOTAN_HAS_SHACAL2_X86 \
BOTAN_HAS_SM4_ARMV8 \
BOTAN_HAS_THREEFISH_512_AVX2 \
BOTAN_DEPRECATED(msg)= \
BOTAN_PUBLIC_API(maj,min)=

View File

@@ -87,6 +87,10 @@
#define BOTAN_ENABLE_DEBUG_ASSERTS
%{endif}
%{if optimize_for_size}
#define BOTAN_OPTIMIZE_FOR_SIZE
%{endif}
/*
* Module availability definitions
*/
@@ -166,8 +170,8 @@
* broken system RNG.
*/
#define BOTAN_ENTROPY_DEFAULT_SOURCES \
{ "rdseed", "rdrand", "darwin_secrandom", "getentropy", \
"dev_random", "system_rng", "proc_walk", "system_stats" }
{ "rdseed", "rdrand", "getentropy", "dev_random", \
"system_rng", "proc_walk", "system_stats" }
/* Multiplier on a block cipher's native parallelism */
#define BOTAN_BLOCK_CIPHER_PAR_MULT 4
@@ -176,7 +180,7 @@
* These control the RNG used by the system RNG interface
*/
#define BOTAN_SYSTEM_RNG_DEVICE "/dev/urandom"
#define BOTAN_SYSTEM_RNG_POLL_DEVICES { "/dev/urandom", "/dev/random", "/dev/srandom" }
#define BOTAN_SYSTEM_RNG_POLL_DEVICES { "/dev/urandom", "/dev/random" }
/*
* This directory will be monitored by ProcWalking_EntropySource and

View File

@@ -18,7 +18,7 @@ default -> address,undefined
address -> "-fsanitize=address"
undefined -> "-fsanitize=undefined -fno-sanitize-recover=undefined"
coverage -> "-fsanitize-coverage=edge,indirect-calls,8bit-counters"
coverage -> "-fsanitize-coverage=edge,indirect-calls,trace-pc-guard,trace-cmp,trace-gep"
memory -> "-fsanitize=memory"
</sanitizers>

View File

@@ -65,6 +65,10 @@ altivec -> "-maltivec"
ppccrypto -> "-mcrypto"
arm64:armv8crypto -> ""
arm64:armv8sm3 -> "-march=armv8.2-a+sm4"
arm64:armv8sm4 -> "-march=armv8.2-a+sm4"
arm64:armv8sha512 -> "-march=armv8.2-a+sha3"
arm64:armv8sha3 -> "-march=armv8.2-a+sha3"
# For Aarch32 -mfpu=neon is required
# For Aarch64 NEON is enabled by default

View File

@@ -23,7 +23,7 @@ debug_info_flags "/Zi /FS"
preproc_flags "/nologo /EP"
lang_flags "/EHs /GR"
lang_flags "/EHs /GR /D_ENABLE_EXTENDED_ALIGNED_STORAGE"
warning_flags "/W4 /wd4250 /wd4251 /wd4275"
visibility_build_flags "/DBOTAN_DLL=__declspec(dllexport)"
@@ -38,7 +38,7 @@ sse2 -> ""
ssse3 -> ""
sse41 -> ""
sse42 -> ""
x86_64:avx2 -> ""
x86_64:avx2 -> "/arch:AVX"
bmi2 -> ""
aesni -> ""
clmul -> ""

View File

@@ -5,8 +5,8 @@ binary_name CC
optimization_flags "-xO2"
shared_flags "-KPIC"
warning_flags "+w -erroff=truncwarn,wnoretvalue"
lang_flags "-std=c++11 +p -features=extensions -D__FUNCTION__=__func__"
warning_flags "+w -erroff=truncwarn,wnoretvalue,wlessrestrictedthrow"
lang_flags "-std=c++11 +p -features=extensions"
ar_command CC
ar_options "-xar -o"
@@ -19,7 +19,7 @@ default -> "$(CXX) -G -h{soname_abi}"
# Needed on some Linux distros
linux -> "-library=stlport4"
sparc64 -> "-xarch=v9"
sparc64 -> "-m64 -xarch=sparc"
x86_64 -> "-m64"
</mach_abi_linking>

View File

@@ -57,6 +57,14 @@
#elif defined(__s390__)
S390
#elif defined(__riscv)
#if defined(__LP64__)
RISCV64
#else
RISCV32
#endif
#else
UNKNOWN

View File

@@ -54,7 +54,7 @@ distclean:
$(PYTHON_EXE) $(SCRIPTS_DIR)/cleanup.py --build-dir="%{build_dir}" --distclean
install: libs cli docs
$(PYTHON_EXE) $(SCRIPTS_DIR)/install.py --prefix=%{prefix} --build-dir="%{build_dir}" --bindir=%{bindir} --libdir=%{libdir} --docdir=%{docdir} --includedir=%{includedir}
$(PYTHON_EXE) $(SCRIPTS_DIR)/install.py --prefix="%{prefix}" --build-dir="%{build_dir}" --bindir=%{bindir} --libdir=%{libdir} --docdir=%{docdir} --includedir=%{includedir}
# Object Files
LIBOBJS = %{join lib_objs}

View File

@@ -21,6 +21,7 @@
1.3.132.1.12 = ECDH
1.2.156.10197.1.301.1 = SM2_Sig
1.2.156.10197.1.301.1 = SM2
1.2.156.10197.1.301.2 = SM2_Kex
1.2.156.10197.1.301.3 = SM2_Enc
@@ -40,7 +41,6 @@
# Cipher modes
1.3.14.3.2.7 = DES/CBC
1.2.840.113549.3.7 = TripleDES/CBC
1.2.840.113549.3.2 = RC2/CBC
1.2.840.113533.7.66.10 = CAST-128/CBC
2.16.840.1.101.3.4.1.2 = AES-128/CBC
2.16.840.1.101.3.4.1.22 = AES-192/CBC
@@ -80,6 +80,21 @@
1.3.6.1.4.1.25258.3.2.3 = AES-256/OCB
1.3.6.1.4.1.25258.3.2.4 = Serpent/OCB
1.3.6.1.4.1.25258.3.2.5 = Twofish/OCB
1.3.6.1.4.1.25258.3.2.6 = Camellia-128/OCB
1.3.6.1.4.1.25258.3.2.7 = Camellia-192/OCB
1.3.6.1.4.1.25258.3.2.8 = Camellia-256/OCB
1.2.156.10197.1.104.100 = SM4/OCB
1.3.6.1.4.1.25258.3.4.1 = AES-128/SIV
1.3.6.1.4.1.25258.3.4.2 = AES-192/SIV
1.3.6.1.4.1.25258.3.4.3 = AES-256/SIV
1.3.6.1.4.1.25258.3.4.4 = Serpent/SIV
1.3.6.1.4.1.25258.3.4.5 = Twofish/SIV
1.3.6.1.4.1.25258.3.4.6 = Camellia-128/SIV
1.3.6.1.4.1.25258.3.4.7 = Camellia-192/SIV
1.3.6.1.4.1.25258.3.4.8 = Camellia-256/SIV
1.3.6.1.4.1.25258.3.4.9 = SM4/SIV
[hash]
# Hash functions
@@ -115,11 +130,11 @@
1.2.840.113549.2.9 = HMAC(SHA-256)
1.2.840.113549.2.10 = HMAC(SHA-384)
1.2.840.113549.2.11 = HMAC(SHA-512)
1.2.840.113549.2.13 = HMAC(SHA-512-256)
[keywrap]
# Keywrap algorithms
1.2.840.113549.1.9.16.3.6 = KeyWrap.TripleDES
1.2.840.113549.1.9.16.3.7 = KeyWrap.RC2
1.2.840.113533.7.66.15 = KeyWrap.CAST-128
2.16.840.1.101.3.4.1.5 = KeyWrap.AES-128
2.16.840.1.101.3.4.1.25 = KeyWrap.AES-192
@@ -140,6 +155,8 @@
1.2.840.113549.1.1.14 = RSA/EMSA3(SHA-224)
1.2.840.113549.1.1.16 = RSA/EMSA3(SHA-512-256)
1.3.36.3.3.1.2 = RSA/EMSA3(RIPEMD-160)
1.2.156.10197.1.501 = SM2_Sig/SM3
1.2.156.10197.1.504 = RSA/EMSA3(SM3)
1.2.840.10040.4.3 = DSA/EMSA1(SHA-160)
@@ -208,6 +225,7 @@
[pbe]
1.2.840.113549.1.5.12 = PKCS5.PBKDF2
1.2.840.113549.1.5.13 = PBES2
1.2.840.113549.1.5.13 = PBE-PKCS5v20
1.3.6.1.4.1.11591.4.11 = Scrypt
@@ -258,6 +276,9 @@
1.3.6.1.5.5.7.48.2 = PKIX.CertificateAuthorityIssuers
1.3.6.1.4.1.311.20.2.2 = Microsoft SmartcardLogon
1.3.6.1.4.1.311.20.2.3 = Microsoft UPN
2.16.840.1.113730.1.13 = Certificate Comment
# ECC param sets
[ecc_param]

View File

@@ -14,8 +14,8 @@ posix1
posix_mlock
arc4random
dev_random
security_framework
commoncrypto
sockets
threads
filesystem

View File

@@ -10,6 +10,7 @@ posix1
posix_mlock
arc4random
commoncrypto
sockets
threads
filesystem

View File

@@ -10,6 +10,9 @@ proc_fs
clock_gettime
getauxval
# not enabled by default as only available in newer kernel/glibc
#getrandom
sockets
threads
filesystem

View File

@@ -1,10 +1,10 @@
release_major = 2
release_minor = 7
release_minor = 8
release_patch = 0
release_so_abi_rev = 7
release_so_abi_rev = 8
# These are set by the distribution script
release_vc_rev = 'git:5874000d42c338ec95a7ff24cdc0c64e70f967b5'
release_datestamp = 20180702
release_vc_rev = 'git:a792728e8941b62761052f5e0d288ba13a016c77'
release_datestamp = 20181001
release_type = 'release'

View File

@@ -174,7 +174,7 @@ void ASN1_Formatter::decode(std::ostream& output,
data.decode(number, ENUMERATED, class_tag);
}
std::vector<uint8_t> rep = BigInt::encode(number, BigInt::Binary);
std::vector<uint8_t> rep = BigInt::encode(number);
if(rep.empty()) // if zero
rep.resize(1);

View File

@@ -262,6 +262,12 @@ std::chrono::system_clock::time_point X509_Time::to_std_timepoint() const
return calendar_point(m_year, m_month, m_day, m_hour, m_minute, m_second).to_std_timepoint();
}
uint64_t X509_Time::time_since_epoch() const
{
auto tp = this->to_std_timepoint();
return std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
}
/*
* Compare two X509_Times for in various ways
*/

View File

@@ -49,6 +49,9 @@ class BOTAN_PUBLIC_API(2,0) X509_Time final : public ASN1_Object
/// Returns a STL timepoint object
std::chrono::system_clock::time_point to_std_timepoint() const;
/// Return time since epoch
uint64_t time_since_epoch() const;
private:
void set_to(const std::string& t_spec, ASN1_Tag);
bool passes_sanity_check() const;

View File

@@ -1,7 +1,7 @@
/*
* OID maps
*
* This file was automatically generated by ./src/scripts/oids.py on 2018-07-01
* This file was automatically generated by ./src/scripts/oids.py on 2018-08-23
*
* All manual edits to this file will be lost. Edit the script
* then regenerate this source file.
@@ -21,13 +21,15 @@ std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
{ "0.3.4401.5.3.1.9.46", "Camellia-256/GCM" },
{ "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" },
{ "1.0.14888.3.0.5", "ECKCDSA" },
{ "1.2.156.10197.1.104.100", "SM4/OCB" },
{ "1.2.156.10197.1.104.2", "SM4/CBC" },
{ "1.2.156.10197.1.104.8", "SM4/GCM" },
{ "1.2.156.10197.1.301", "sm2p256v1" },
{ "1.2.156.10197.1.301.1", "SM2_Sig" },
{ "1.2.156.10197.1.301.1", "SM2" },
{ "1.2.156.10197.1.301.2", "SM2_Kex" },
{ "1.2.156.10197.1.301.3", "SM2_Enc" },
{ "1.2.156.10197.1.401", "SM3" },
{ "1.2.156.10197.1.501", "SM2_Sig/SM3" },
{ "1.2.156.10197.1.504", "RSA/EMSA3(SM3)" },
{ "1.2.250.1.223.101.256.1", "frp256v1" },
{ "1.2.392.200011.61.1.1.1.2", "Camellia-128/CBC" },
@@ -78,7 +80,6 @@ std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
{ "1.2.840.113549.1.9.14", "PKCS9.ExtensionRequest" },
{ "1.2.840.113549.1.9.16.3.18", "ChaCha20Poly1305" },
{ "1.2.840.113549.1.9.16.3.6", "KeyWrap.TripleDES" },
{ "1.2.840.113549.1.9.16.3.7", "KeyWrap.RC2" },
{ "1.2.840.113549.1.9.16.3.8", "Compression.Zlib" },
{ "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" },
{ "1.2.840.113549.1.9.3", "PKCS9.ContentType" },
@@ -86,11 +87,11 @@ std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
{ "1.2.840.113549.1.9.7", "PKCS9.ChallengePassword" },
{ "1.2.840.113549.2.10", "HMAC(SHA-384)" },
{ "1.2.840.113549.2.11", "HMAC(SHA-512)" },
{ "1.2.840.113549.2.13", "HMAC(SHA-512-256)" },
{ "1.2.840.113549.2.5", "MD5" },
{ "1.2.840.113549.2.7", "HMAC(SHA-160)" },
{ "1.2.840.113549.2.8", "HMAC(SHA-224)" },
{ "1.2.840.113549.2.9", "HMAC(SHA-256)" },
{ "1.2.840.113549.3.2", "RC2/CBC" },
{ "1.2.840.113549.3.7", "TripleDES/CBC" },
{ "1.3.101.110", "Curve25519" },
{ "1.3.101.112", "Ed25519" },
@@ -137,10 +138,23 @@ std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
{ "1.3.6.1.4.1.25258.3.2.3", "AES-256/OCB" },
{ "1.3.6.1.4.1.25258.3.2.4", "Serpent/OCB" },
{ "1.3.6.1.4.1.25258.3.2.5", "Twofish/OCB" },
{ "1.3.6.1.4.1.25258.3.2.6", "Camellia-128/OCB" },
{ "1.3.6.1.4.1.25258.3.2.7", "Camellia-192/OCB" },
{ "1.3.6.1.4.1.25258.3.2.8", "Camellia-256/OCB" },
{ "1.3.6.1.4.1.25258.3.3", "Twofish/CBC" },
{ "1.3.6.1.4.1.25258.3.4.1", "AES-128/SIV" },
{ "1.3.6.1.4.1.25258.3.4.2", "AES-192/SIV" },
{ "1.3.6.1.4.1.25258.3.4.3", "AES-256/SIV" },
{ "1.3.6.1.4.1.25258.3.4.4", "Serpent/SIV" },
{ "1.3.6.1.4.1.25258.3.4.5", "Twofish/SIV" },
{ "1.3.6.1.4.1.25258.3.4.6", "Camellia-128/SIV" },
{ "1.3.6.1.4.1.25258.3.4.7", "Camellia-192/SIV" },
{ "1.3.6.1.4.1.25258.3.4.8", "Camellia-256/SIV" },
{ "1.3.6.1.4.1.25258.3.4.9", "SM4/SIV" },
{ "1.3.6.1.4.1.3029.1.2.1", "ElGamal" },
{ "1.3.6.1.4.1.3029.1.5.1", "OpenPGP.Curve25519" },
{ "1.3.6.1.4.1.311.20.2.2", "Microsoft SmartcardLogon" },
{ "1.3.6.1.4.1.311.20.2.3", "Microsoft UPN" },
{ "1.3.6.1.4.1.8301.3.1.2.9.0.38", "secp521r1" },
{ "1.3.6.1.5.5.7.1.1", "PKIX.AuthorityInformationAccess" },
{ "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth" },
@@ -195,6 +209,7 @@ std::unordered_map<std::string, std::string> OIDS::load_oid2str_map()
{ "2.16.840.1.101.3.4.3.7", "DSA/EMSA1(SHA-3(384))" },
{ "2.16.840.1.101.3.4.3.8", "DSA/EMSA1(SHA-3(512))" },
{ "2.16.840.1.101.3.4.3.9", "ECDSA/EMSA1(SHA-3(224))" },
{ "2.16.840.1.113730.1.13", "Certificate Comment" },
{ "2.5.29.14", "X509v3.SubjectKeyIdentifier" },
{ "2.5.29.15", "X509v3.KeyUsage" },
{ "2.5.29.17", "X509v3.SubjectAlternativeName" },
@@ -237,21 +252,31 @@ std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
{ "AES-128/CCM", OID({2,16,840,1,101,3,4,1,7}) },
{ "AES-128/GCM", OID({2,16,840,1,101,3,4,1,6}) },
{ "AES-128/OCB", OID({1,3,6,1,4,1,25258,3,2,1}) },
{ "AES-128/SIV", OID({1,3,6,1,4,1,25258,3,4,1}) },
{ "AES-192/CBC", OID({2,16,840,1,101,3,4,1,22}) },
{ "AES-192/CCM", OID({2,16,840,1,101,3,4,1,27}) },
{ "AES-192/GCM", OID({2,16,840,1,101,3,4,1,26}) },
{ "AES-192/OCB", OID({1,3,6,1,4,1,25258,3,2,2}) },
{ "AES-192/SIV", OID({1,3,6,1,4,1,25258,3,4,2}) },
{ "AES-256/CBC", OID({2,16,840,1,101,3,4,1,42}) },
{ "AES-256/CCM", OID({2,16,840,1,101,3,4,1,47}) },
{ "AES-256/GCM", OID({2,16,840,1,101,3,4,1,46}) },
{ "AES-256/OCB", OID({1,3,6,1,4,1,25258,3,2,3}) },
{ "AES-256/SIV", OID({1,3,6,1,4,1,25258,3,4,3}) },
{ "CAST-128/CBC", OID({1,2,840,113533,7,66,10}) },
{ "Camellia-128/CBC", OID({1,2,392,200011,61,1,1,1,2}) },
{ "Camellia-128/GCM", OID({0,3,4401,5,3,1,9,6}) },
{ "Camellia-128/OCB", OID({1,3,6,1,4,1,25258,3,2,6}) },
{ "Camellia-128/SIV", OID({1,3,6,1,4,1,25258,3,4,6}) },
{ "Camellia-192/CBC", OID({1,2,392,200011,61,1,1,1,3}) },
{ "Camellia-192/GCM", OID({0,3,4401,5,3,1,9,26}) },
{ "Camellia-192/OCB", OID({1,3,6,1,4,1,25258,3,2,7}) },
{ "Camellia-192/SIV", OID({1,3,6,1,4,1,25258,3,4,7}) },
{ "Camellia-256/CBC", OID({1,2,392,200011,61,1,1,1,4}) },
{ "Camellia-256/GCM", OID({0,3,4401,5,3,1,9,46}) },
{ "Camellia-256/OCB", OID({1,3,6,1,4,1,25258,3,2,8}) },
{ "Camellia-256/SIV", OID({1,3,6,1,4,1,25258,3,4,8}) },
{ "Certificate Comment", OID({2,16,840,1,113730,1,13}) },
{ "ChaCha20Poly1305", OID({1,2,840,113549,1,9,16,3,18}) },
{ "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) },
{ "Curve25519", OID({1,3,101,110}) },
@@ -299,19 +324,21 @@ std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
{ "HMAC(SHA-256)", OID({1,2,840,113549,2,9}) },
{ "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) },
{ "HMAC(SHA-512)", OID({1,2,840,113549,2,11}) },
{ "HMAC(SHA-512-256)", OID({1,2,840,113549,2,13}) },
{ "KeyWrap.AES-128", OID({2,16,840,1,101,3,4,1,5}) },
{ "KeyWrap.AES-192", OID({2,16,840,1,101,3,4,1,25}) },
{ "KeyWrap.AES-256", OID({2,16,840,1,101,3,4,1,45}) },
{ "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) },
{ "KeyWrap.RC2", OID({1,2,840,113549,1,9,16,3,7}) },
{ "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) },
{ "MD5", OID({1,2,840,113549,2,5}) },
{ "MGF1", OID({1,2,840,113549,1,1,8}) },
{ "McEliece", OID({1,3,6,1,4,1,25258,1,3}) },
{ "Microsoft SmartcardLogon", OID({1,3,6,1,4,1,311,20,2,2}) },
{ "Microsoft UPN", OID({1,3,6,1,4,1,311,20,2,3}) },
{ "OpenPGP.Curve25519", OID({1,3,6,1,4,1,3029,1,5,1}) },
{ "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) },
{ "PBE-PKCS5v20", OID({1,2,840,113549,1,5,13}) },
{ "PBES2", OID({1,2,840,113549,1,5,13}) },
{ "PKCS5.PBKDF2", OID({1,2,840,113549,1,5,12}) },
{ "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) },
{ "PKCS9.ContentType", OID({1,2,840,113549,1,9,3}) },
@@ -333,7 +360,6 @@ std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
{ "PKIX.ServerAuth", OID({1,3,6,1,5,5,7,3,1}) },
{ "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) },
{ "PKIX.XMPPAddr", OID({1,3,6,1,5,5,7,8,5}) },
{ "RC2/CBC", OID({1,2,840,113549,3,2}) },
{ "RIPEMD-160", OID({1,3,36,3,2,1}) },
{ "RSA", OID({1,2,840,113549,1,1,1}) },
{ "RSA/EMSA3(MD5)", OID({1,2,840,113549,1,1,4}) },
@@ -364,16 +390,21 @@ std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
{ "SHA-512-256", OID({2,16,840,1,101,3,4,2,6}) },
{ "SHAKE-128", OID({2,16,840,1,101,3,4,2,11}) },
{ "SHAKE-256", OID({2,16,840,1,101,3,4,2,12}) },
{ "SM2", OID({1,2,156,10197,1,301,1}) },
{ "SM2_Enc", OID({1,2,156,10197,1,301,3}) },
{ "SM2_Kex", OID({1,2,156,10197,1,301,2}) },
{ "SM2_Sig", OID({1,2,156,10197,1,301,1}) },
{ "SM2_Sig/SM3", OID({1,2,156,10197,1,501}) },
{ "SM3", OID({1,2,156,10197,1,401}) },
{ "SM4/CBC", OID({1,2,156,10197,1,104,2}) },
{ "SM4/GCM", OID({1,2,156,10197,1,104,8}) },
{ "SM4/OCB", OID({1,2,156,10197,1,104,100}) },
{ "SM4/SIV", OID({1,3,6,1,4,1,25258,3,4,9}) },
{ "Scrypt", OID({1,3,6,1,4,1,11591,4,11}) },
{ "Serpent/CBC", OID({1,3,6,1,4,1,25258,3,1}) },
{ "Serpent/GCM", OID({1,3,6,1,4,1,25258,3,101}) },
{ "Serpent/OCB", OID({1,3,6,1,4,1,25258,3,2,4}) },
{ "Serpent/SIV", OID({1,3,6,1,4,1,25258,3,4,4}) },
{ "Streebog-256", OID({1,2,643,7,1,1,2,2}) },
{ "Streebog-512", OID({1,2,643,7,1,1,2,3}) },
{ "Threefish-512/CBC", OID({1,3,6,1,4,1,25258,3,2}) },
@@ -382,6 +413,7 @@ std::unordered_map<std::string, OID> OIDS::load_str2oid_map()
{ "Twofish/CBC", OID({1,3,6,1,4,1,25258,3,3}) },
{ "Twofish/GCM", OID({1,3,6,1,4,1,25258,3,102}) },
{ "Twofish/OCB", OID({1,3,6,1,4,1,25258,3,2,5}) },
{ "Twofish/SIV", OID({1,3,6,1,4,1,25258,3,4,5}) },
{ "X509v3.AnyPolicy", OID({2,5,29,32,0}) },
{ "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) },
{ "X509v3.BasicConstraints", OID({2,5,29,19}) },

View File

@@ -14,7 +14,7 @@ namespace OIDS {
namespace {
class OID_Map
class OID_Map final
{
public:
void add_oid(const OID& oid, const std::string& str)

View File

@@ -88,7 +88,7 @@ operator!=(const secure_allocator<T>&, const secure_allocator<U>&)
template<typename T> using secure_vector = std::vector<T, secure_allocator<T>>;
template<typename T> using secure_deque = std::deque<T, secure_allocator<T>>;
// For better compatability with 1.10 API
// For better compatibility with 1.10 API
template<typename T> using SecureVector = secure_vector<T>;
template<typename T>

View File

@@ -1,6 +1,6 @@
/*
* AES
* (C) 1999-2010,2015,2017 Jack Lloyd
* (C) 1999-2010,2015,2017,2018 Jack Lloyd
*
* Based on the public domain reference implementation by Paulo Baretto
*
@@ -18,14 +18,14 @@
* countermeasures are used which may be helpful in some situations:
*
* - Only a single 256-word T-table is used, with rotations applied.
* Most implementations use 4 T-tables which leaks much more
* information via cache usage.
* Most implementations use 4 (or sometimes 5) T-tables, which leaks
* much more information via cache usage.
*
* - The TE and TD tables are computed at runtime to avoid flush+reload
* attacks using clflush. As different processes will not share the
* same underlying table data, an attacker can't manipulate another
* processes cache lines via their shared reference to the library
* read only segment.
* read only segment. (However, prime+probe attacks are still possible.)
*
* - Each cache line of the lookup tables is accessed at the beginning
* of each call to encrypt or decrypt. (See the Z variable below)
@@ -188,7 +188,6 @@ void aes_encrypt_n(const uint8_t in[], uint8_t out[],
BOTAN_ASSERT(EK.size() && ME.size() == 16, "Key was set");
const size_t cache_line_size = CPUID::cache_line_size();
const uint32_t* TE = AES_TE();
// Hit every cache line of TE
@@ -269,6 +268,10 @@ void aes_decrypt_n(const uint8_t in[], uint8_t out[], size_t blocks,
{
Z |= TD[i];
}
for(size_t i = 0; i < 256; i += cache_line_size)
{
Z |= SD[i];
}
Z &= TD[99]; // this is zero, which hopefully the compiler cannot deduce
for(size_t i = 0; i != blocks; ++i)
@@ -339,8 +342,24 @@ void aes_key_schedule(const uint8_t key[], size_t length,
// Can't happen, but make static analyzers happy
BOTAN_ARG_CHECK(X == 4 || X == 6 || X == 8, "Invalid AES key size");
const uint32_t* TD = AES_TD();
// Prefetch TD and SE which are used later on in this function
volatile uint32_t Z = 0;
const size_t cache_line_size = CPUID::cache_line_size();
for(size_t i = 0; i < 256; i += cache_line_size / sizeof(uint32_t))
{
Z |= TD[i];
}
for(size_t i = 0; i < 256; i += cache_line_size)
{
Z |= SE[i];
}
Z &= TD[99]; // this is zero, which hopefully the compiler cannot deduce
for(size_t i = 0; i != X; ++i)
XEK[i] = load_be<uint32_t>(key, i);
XEK[i] = Z ^ load_be<uint32_t>(key, i);
for(size_t i = X; i < 4*(rounds+1); i += X)
{
@@ -367,8 +386,8 @@ void aes_key_schedule(const uint8_t key[], size_t length,
for(size_t i = 4; i != length + 24; ++i)
{
XDK[i] = SE_word(XDK[i]);
XDK[i] = AES_T(AES_TD(), 0, XDK[i], XDK[i], XDK[i], XDK[i]);
XDK[i] = Z ^ SE_word(XDK[i]);
XDK[i] = AES_T(TD, 0, XDK[i], XDK[i], XDK[i], XDK[i]);
}
ME.resize(16);

View File

@@ -2,6 +2,4 @@
AES_NI -> 20131128
</defines>
load_on auto
need_isa aesni

View File

@@ -2,8 +2,6 @@
AES_SSSE3 -> 20131128
</defines>
load_on auto
need_isa ssse3
# Intel C++ can't deal with syntax for defining constants :(

View File

@@ -98,12 +98,27 @@
#include <botan/internal/openssl.h>
#endif
#if defined(BOTAN_HAS_COMMONCRYPTO)
#include <botan/internal/commoncrypto.h>
#endif
namespace Botan {
std::unique_ptr<BlockCipher>
BlockCipher::create(const std::string& algo,
const std::string& provider)
{
#if defined(BOTAN_HAS_COMMONCRYPTO)
if(provider.empty() || provider == "commoncrypto")
{
if(auto bc = make_commoncrypto_block_cipher(algo))
return bc;
if(!provider.empty())
return nullptr;
}
#endif
#if defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl")
{
@@ -115,7 +130,6 @@ BlockCipher::create(const std::string& algo,
}
#endif
// TODO: CommonCrypto
// TODO: CryptoAPI
// TODO: /dev/crypto
@@ -343,7 +357,7 @@ BlockCipher::create_or_throw(const std::string& algo,
std::vector<std::string> BlockCipher::providers(const std::string& algo)
{
return probe_providers_of<BlockCipher>(algo, { "base", "openssl" });
return probe_providers_of<BlockCipher>(algo, { "base", "openssl", "commoncrypto" });
}
}

View File

@@ -197,36 +197,52 @@ class BOTAN_PUBLIC_API(2,0) BlockCipher : public SymmetricAlgorithm
virtual ~BlockCipher() = default;
};
/**
* Tweakable block ciphers allow setting a tweak which is a non-keyed
* value which affects the encryption/decryption operation.
*/
class BOTAN_PUBLIC_API(2,8) Tweakable_Block_Cipher : public BlockCipher
{
public:
/**
* Set the tweak value. This must be called after setting a key. The value
* persists until either set_tweak, set_key, or clear is called.
* Different algorithms support different tweak length(s). If called with
* an unsupported length, Invalid_Argument will be thrown.
*/
virtual void set_tweak(const uint8_t tweak[], size_t len) = 0;
};
/**
* Represents a block cipher with a single fixed block size
*/
template<size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1>
class Block_Cipher_Fixed_Params : public BlockCipher
template<size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1, typename BaseClass = BlockCipher>
class Block_Cipher_Fixed_Params : public BaseClass
{
public:
enum { BLOCK_SIZE = BS };
size_t block_size() const override { return BS; }
size_t block_size() const final override { return BS; }
// override to take advantage of compile time constant block size
void encrypt_n_xex(uint8_t data[],
const uint8_t mask[],
size_t blocks) const override
size_t blocks) const final override
{
xor_buf(data, mask, blocks * BS);
encrypt_n(data, data, blocks);
this->encrypt_n(data, data, blocks);
xor_buf(data, mask, blocks * BS);
}
void decrypt_n_xex(uint8_t data[],
const uint8_t mask[],
size_t blocks) const override
size_t blocks) const final override
{
xor_buf(data, mask, blocks * BS);
decrypt_n(data, data, blocks);
this->decrypt_n(data, data, blocks);
xor_buf(data, mask, blocks * BS);
}
Key_Length_Specification key_spec() const override
Key_Length_Specification key_spec() const final override
{
return Key_Length_Specification(KMIN, KMAX, KMOD);
}

View File

@@ -6,30 +6,156 @@
*/
#include <botan/base64.h>
#include <botan/internal/codec_base.h>
#include <botan/exceptn.h>
#include <botan/mem_ops.h>
#include <botan/internal/rounding.h>
namespace Botan {
namespace {
static const uint8_t BIN_TO_BASE64[64] = {
class Base64 final
{
public:
static inline size_t encoding_bytes_in() BOTAN_NOEXCEPT
{
return m_encoding_bytes_in;
}
static inline size_t encoding_bytes_out() BOTAN_NOEXCEPT
{
return m_encoding_bytes_out;
}
static inline size_t decoding_bytes_in() BOTAN_NOEXCEPT
{
return m_encoding_bytes_out;
}
static inline size_t decoding_bytes_out() BOTAN_NOEXCEPT
{
return m_encoding_bytes_in;
}
static inline size_t bits_consumed() BOTAN_NOEXCEPT
{
return m_encoding_bits;
}
static inline size_t remaining_bits_before_padding() BOTAN_NOEXCEPT
{
return m_remaining_bits_before_padding;
}
static inline size_t encode_max_output(size_t input_length)
{
return (round_up(input_length, m_encoding_bytes_in) / m_encoding_bytes_in) * m_encoding_bytes_out;
}
static inline size_t decode_max_output(size_t input_length)
{
return (round_up(input_length, m_encoding_bytes_out) * m_encoding_bytes_in) / m_encoding_bytes_out;
}
static void encode(char out[8], const uint8_t in[5]) BOTAN_NOEXCEPT
{
out[0] = Base64::m_bin_to_base64[(in[0] & 0xFC) >> 2];
out[1] = Base64::m_bin_to_base64[((in[0] & 0x03) << 4) | (in[1] >> 4)];
out[2] = Base64::m_bin_to_base64[((in[1] & 0x0F) << 2) | (in[2] >> 6)];
out[3] = Base64::m_bin_to_base64[in[2] & 0x3F];
}
static inline uint8_t lookup_binary_value(char input) BOTAN_NOEXCEPT
{
return Base64::m_base64_to_bin[static_cast<uint8_t>(input)];
}
static inline bool check_bad_char(uint8_t bin, char input, bool ignore_ws)
{
if(bin <= 0x3F)
{
return true;
}
else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws)))
{
std::string bad_char(1, input);
if(bad_char == "\t")
{ bad_char = "\\t"; }
else if(bad_char == "\n")
{ bad_char = "\\n"; }
else if(bad_char == "\r")
{ bad_char = "\\r"; }
throw Invalid_Argument(
std::string("base64_decode: invalid base64 character '") +
bad_char + "'");
}
return false;
}
static void decode(uint8_t* out_ptr, const uint8_t decode_buf[4])
{
out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4);
out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2);
out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3];
}
static inline size_t bytes_to_remove(size_t final_truncate)
{
return final_truncate;
}
private:
static const size_t m_encoding_bits = 6;
static const size_t m_remaining_bits_before_padding = 8;
static const size_t m_encoding_bytes_in = 3;
static const size_t m_encoding_bytes_out = 4;
static const uint8_t m_bin_to_base64[64];
static const uint8_t m_base64_to_bin[256];
};
const uint8_t Base64::m_bin_to_base64[64] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
};
void do_base64_encode(char out[4], const uint8_t in[3])
/*
* base64 Decoder Lookup Table
* Warning: assumes ASCII encodings
*/
const uint8_t Base64::m_base64_to_bin[256] =
{
out[0] = BIN_TO_BASE64[(in[0] & 0xFC) >> 2];
out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)];
out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)];
out[3] = BIN_TO_BASE64[in[2] & 0x3F];
}
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C,
0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
}
size_t base64_encode(char out[],
@@ -38,58 +164,24 @@ size_t base64_encode(char out[],
size_t& input_consumed,
bool final_inputs)
{
input_consumed = 0;
size_t input_remaining = input_length;
size_t output_produced = 0;
while(input_remaining >= 3)
{
do_base64_encode(out + output_produced, in + input_consumed);
input_consumed += 3;
output_produced += 4;
input_remaining -= 3;
}
if(final_inputs && input_remaining)
{
uint8_t remainder[3] = { 0 };
for(size_t i = 0; i != input_remaining; ++i)
remainder[i] = in[input_consumed + i];
do_base64_encode(out + output_produced, remainder);
size_t empty_bits = 8 * (3 - input_remaining);
size_t index = output_produced + 4 - 1;
while(empty_bits >= 8)
{
out[index--] = '=';
empty_bits -= 6;
}
input_consumed += input_remaining;
output_produced += 4;
}
return output_produced;
return base_encode(Base64(), out, in, input_length, input_consumed, final_inputs);
}
std::string base64_encode(const uint8_t input[],
size_t input_length)
{
const size_t output_length = base64_encode_max_output(input_length);
const size_t output_length = Base64::encode_max_output(input_length);
std::string output(output_length, 0);
size_t consumed = 0;
size_t produced = 0;
if (output_length > 0)
{
if(output_length > 0)
{
produced = base64_encode(&output.front(),
input, input_length,
consumed, true);
}
}
BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input");
BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size");
@@ -97,111 +189,14 @@ std::string base64_encode(const uint8_t input[],
return output;
}
size_t base64_decode(uint8_t output[],
const char input[],
size_t base64_decode(uint8_t out[],
const char in[],
size_t input_length,
size_t& input_consumed,
bool final_inputs,
bool ignore_ws)
{
/*
* Base64 Decoder Lookup Table
* Warning: assumes ASCII encodings
*/
static const uint8_t BASE64_TO_BIN[256] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xFF, 0xFF, 0x3F, 0x34, 0x35,
0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF,
0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1A, 0x1B, 0x1C,
0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
uint8_t* out_ptr = output;
uint8_t decode_buf[4];
size_t decode_buf_pos = 0;
size_t final_truncate = 0;
clear_mem(output, input_length * 3 / 4);
for(size_t i = 0; i != input_length; ++i)
{
const uint8_t bin = BASE64_TO_BIN[static_cast<uint8_t>(input[i])];
if(bin <= 0x3F)
{
decode_buf[decode_buf_pos] = bin;
decode_buf_pos += 1;
}
else if(!(bin == 0x81 || (bin == 0x80 && ignore_ws)))
{
std::string bad_char(1, input[i]);
if(bad_char == "\t")
bad_char = "\\t";
else if(bad_char == "\n")
bad_char = "\\n";
else if(bad_char == "\r")
bad_char = "\\r";
throw Invalid_Argument(
std::string("base64_decode: invalid base64 character '") +
bad_char + "'");
}
/*
* If we're at the end of the input, pad with 0s and truncate
*/
if(final_inputs && (i == input_length - 1))
{
if(decode_buf_pos)
{
for(size_t j = decode_buf_pos; j != 4; ++j)
decode_buf[j] = 0;
final_truncate = (4 - decode_buf_pos);
decode_buf_pos = 4;
}
}
if(decode_buf_pos == 4)
{
out_ptr[0] = (decode_buf[0] << 2) | (decode_buf[1] >> 4);
out_ptr[1] = (decode_buf[1] << 4) | (decode_buf[2] >> 2);
out_ptr[2] = (decode_buf[2] << 6) | decode_buf[3];
out_ptr += 3;
decode_buf_pos = 0;
input_consumed = i+1;
}
}
while(input_consumed < input_length &&
BASE64_TO_BIN[static_cast<uint8_t>(input[input_consumed])] == 0x80)
{
++input_consumed;
}
size_t written = (out_ptr - output) - final_truncate;
return written;
return base_decode(Base64(), out, in, input_length, input_consumed, final_inputs, ignore_ws);
}
size_t base64_decode(uint8_t output[],
@@ -214,7 +209,7 @@ size_t base64_decode(uint8_t output[],
consumed, true, ignore_ws);
if(consumed != input_length)
throw Invalid_Argument("base64_decode: input did not have full bytes");
{ throw Invalid_Argument("base64_decode: input did not have full bytes"); }
return written;
}
@@ -227,10 +222,10 @@ size_t base64_decode(uint8_t output[],
}
secure_vector<uint8_t> base64_decode(const char input[],
size_t input_length,
bool ignore_ws)
size_t input_length,
bool ignore_ws)
{
const size_t output_length = base64_decode_max_output(input_length);
const size_t output_length = Base64::decode_max_output(input_length);
secure_vector<uint8_t> bin(output_length);
size_t written = base64_decode(bin.data(),
@@ -243,19 +238,19 @@ secure_vector<uint8_t> base64_decode(const char input[],
}
secure_vector<uint8_t> base64_decode(const std::string& input,
bool ignore_ws)
bool ignore_ws)
{
return base64_decode(input.data(), input.size(), ignore_ws);
}
size_t base64_encode_max_output(size_t input_length)
{
return (round_up(input_length, 3) / 3) * 4;
return Base64::encode_max_output(input_length);
}
size_t base64_decode_max_output(size_t input_length)
{
return (round_up(input_length, 4) * 3) / 4;
return Base64::decode_max_output(input_length);
}
}

View File

@@ -1,30 +0,0 @@
/*
* Darwin SecRandomCopyBytes EntropySource
* (C) 2015 Daniel Seither (Kullo GmbH)
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/darwin_secrandom.h>
#include <Security/Security.h>
#include <Security/SecRandom.h>
namespace Botan {
/**
* Gather entropy from SecRandomCopyBytes
*/
size_t Darwin_SecRandom::poll(RandomNumberGenerator& rng)
{
secure_vector<uint8_t> buf(BOTAN_SYSTEM_RNG_POLL_REQUEST);
if(0 == SecRandomCopyBytes(kSecRandomDefault, buf.size(), buf.data()))
{
rng.add_entropy(buf.data(), buf.size());
return buf.size() * 8;
}
return 0;
}
}

View File

@@ -1,28 +0,0 @@
/*
* Darwin SecRandomCopyBytes EntropySource
* (C) 2015 Daniel Seither (Kullo GmbH)
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#ifndef BOTAN_ENTROPY_SRC_DARWIN_SECRANDOM_H_
#define BOTAN_ENTROPY_SRC_DARWIN_SECRANDOM_H_
#include <botan/entropy_src.h>
namespace Botan {
/**
* Entropy source using SecRandomCopyBytes from Darwin's Security.framework
*/
class Darwin_SecRandom final : public Entropy_Source
{
public:
std::string name() const override { return "darwin_secrandom"; }
size_t poll(RandomNumberGenerator& rng) override;
};
}
#endif

View File

@@ -1,16 +0,0 @@
<defines>
ENTROPY_SRC_DARWIN_SECRANDOM -> 20150925
</defines>
<header:internal>
darwin_secrandom.h
</header:internal>
<os_features>
security_framework
</os_features>
<frameworks>
darwin -> Security
ios -> Security
</frameworks>

View File

@@ -30,10 +30,7 @@
#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER)
#include <botan/internal/proc_walk.h>
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM)
#include <botan/internal/darwin_secrandom.h>
#include <botan/internal/os_utils.h>
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY)
@@ -86,13 +83,6 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
}
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM)
if(name == "darwin_secrandom")
{
return std::unique_ptr<Entropy_Source>(new Darwin_SecRandom);
}
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY)
if(name == "getentropy")
{
@@ -108,7 +98,7 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
#endif
#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER)
if(name == "proc_walk")
if(name == "proc_walk" && OS::running_in_privileged_state() == false)
{
const std::string root_dir = BOTAN_ENTROPY_PROC_FS_PATH;
if(!root_dir.empty())

View File

@@ -8,12 +8,12 @@
#include <botan/internal/rdrand.h>
#include <botan/rdrand_rng.h>
#include <botan/cpuid.h>
namespace Botan {
size_t Intel_Rdrand::poll(RandomNumberGenerator& rng) {
if(CPUID::has_rdrand() && BOTAN_ENTROPY_INTEL_RNG_POLLS > 0)
size_t Intel_Rdrand::poll(RandomNumberGenerator& rng)
{
if(BOTAN_ENTROPY_INTEL_RNG_POLLS > 0 && RDRAND_RNG::available())
{
RDRAND_RNG rdrand_rng;
secure_vector<uint8_t> buf(4 * BOTAN_ENTROPY_INTEL_RNG_POLLS);

View File

@@ -15,7 +15,8 @@
namespace Botan {
BOTAN_FUNC_ISA("rdseed")
size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) {
size_t Intel_Rdseed::poll(RandomNumberGenerator& rng)
{
if(CPUID::has_rdseed())
{
for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p)

View File

@@ -67,28 +67,20 @@ class BOTAN_PUBLIC_API(2,0) Filter
/**
* @param in some input for the filter
*/
void send(const secure_vector<uint8_t>& in) { send(in.data(), in.size()); }
/**
* @param in some input for the filter
*/
void send(const std::vector<uint8_t>& in) { send(in.data(), in.size()); }
/**
* @param in some input for the filter
* @param length the number of bytes of in to send
*/
void send(const secure_vector<uint8_t>& in, size_t length)
template<typename Alloc>
void send(const std::vector<uint8_t, Alloc>& in)
{
send(in.data(), length);
send(in.data(), in.size());
}
/**
* @param in some input for the filter
* @param length the number of bytes of in to send
*/
void send(const std::vector<uint8_t>& in, size_t length)
template<typename Alloc>
void send(const std::vector<uint8_t, Alloc>& in, size_t length)
{
BOTAN_ASSERT_NOMSG(length <= in.size());
send(in.data(), length);
}

View File

@@ -101,11 +101,27 @@
#include <botan/internal/openssl.h>
#endif
#if defined(BOTAN_HAS_COMMONCRYPTO)
#include <botan/internal/commoncrypto.h>
#endif
namespace Botan {
std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec,
const std::string& provider)
{
#if defined(BOTAN_HAS_COMMONCRYPTO)
if(provider.empty() || provider == "commoncrypto")
{
if(auto hash = make_commoncrypto_hash(algo_spec))
return hash;
if(!provider.empty())
return nullptr;
}
#endif
#if defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl")
{
@@ -128,8 +144,6 @@ std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec,
}
#endif
// TODO: CommonCrypto hashes
if(provider.empty() == false && provider != "base")
return nullptr; // unknown provider
@@ -354,7 +368,7 @@ HashFunction::create_or_throw(const std::string& algo,
std::vector<std::string> HashFunction::providers(const std::string& algo_spec)
{
return probe_providers_of<HashFunction>(algo_spec, {"base", "bearssl", "openssl"});
return probe_providers_of<HashFunction>(algo_spec, {"base", "bearssl", "openssl", "commoncrypto"});
}
}

View File

@@ -20,15 +20,14 @@ namespace Botan {
BOTAN_FUNC_ISA("+crypto")
void SHA_160::sha1_armv8_compress_n(secure_vector<uint32_t>& digest, const uint8_t input8[], size_t blocks)
{
uint32x4_t C0, C1, C2, C3;
uint32x4_t ABCD, ABCD_SAVED;
uint32_t E0, E0_SAVED, E1;
uint32x4_t ABCD;
uint32_t E0;
// Load initial values
C0 = vdupq_n_u32(0x5A827999);
C1 = vdupq_n_u32(0x6ED9EBA1);
C2 = vdupq_n_u32(0x8F1BBCDC);
C3 = vdupq_n_u32(0xCA62C1D6);
// Load magic constants
const uint32x4_t C0 = vdupq_n_u32(0x5A827999);
const uint32x4_t C1 = vdupq_n_u32(0x6ED9EBA1);
const uint32x4_t C2 = vdupq_n_u32(0x8F1BBCDC);
const uint32x4_t C3 = vdupq_n_u32(0xCA62C1D6);
ABCD = vld1q_u32(&digest[0]);
E0 = digest[4];
@@ -38,12 +37,13 @@ void SHA_160::sha1_armv8_compress_n(secure_vector<uint32_t>& digest, const uint8
while (blocks)
{
// Save current hash
const uint32x4_t ABCD_SAVED = ABCD;
const uint32_t E0_SAVED = E0;
uint32x4_t MSG0, MSG1, MSG2, MSG3;
uint32x4_t TMP0, TMP1;
// Save current hash
ABCD_SAVED = ABCD;
E0_SAVED = E0;
uint32_t E1;
MSG0 = vld1q_u32(input32 + 0);
MSG1 = vld1q_u32(input32 + 4);

View File

@@ -12,6 +12,42 @@
namespace Botan {
std::string BigInt::to_dec_string() const
{
BigInt copy = *this;
copy.set_sign(Positive);
BigInt remainder;
std::vector<uint8_t> digits;
while(copy > 0)
{
divide(copy, 10, copy, remainder);
digits.push_back(static_cast<uint8_t>(remainder.word_at(0)));
}
std::string s;
for(auto i = digits.rbegin(); i != digits.rend(); ++i)
{
s.push_back(Charset::digit2char(*i));
}
if(s.empty())
s += "0";
return s;
}
std::string BigInt::to_hex_string() const
{
const std::vector<uint8_t> bits = BigInt::encode(*this);
if(bits.empty())
return "00";
else
return hex_encode(bits);
}
/*
* Encode a BigInt
*/
@@ -53,12 +89,15 @@ void BigInt::encode(uint8_t output[], const BigInt& n, Base base)
*/
std::vector<uint8_t> BigInt::encode(const BigInt& n, Base base)
{
if(base == Binary)
return BigInt::encode(n);
std::vector<uint8_t> output(n.encoded_size(base));
encode(output.data(), n, base);
if(base != Binary)
for(size_t j = 0; j != output.size(); ++j)
if(output[j] == 0)
output[j] = '0';
for(size_t j = 0; j != output.size(); ++j)
if(output[j] == 0)
output[j] = '0';
return output;
}
@@ -67,12 +106,15 @@ std::vector<uint8_t> BigInt::encode(const BigInt& n, Base base)
*/
secure_vector<uint8_t> BigInt::encode_locked(const BigInt& n, Base base)
{
if(base == Binary)
return BigInt::encode_locked(n);
secure_vector<uint8_t> output(n.encoded_size(base));
encode(output.data(), n, base);
if(base != Binary)
for(size_t j = 0; j != output.size(); ++j)
if(output[j] == 0)
output[j] = '0';
for(size_t j = 0; j != output.size(); ++j)
if(output[j] == 0)
output[j] = '0';
return output;
}

View File

@@ -125,6 +125,24 @@ BigInt operator*(const BigInt& x, const BigInt& y)
return z;
}
/*
* Multiplication Operator
*/
BigInt operator*(const BigInt& x, word y)
{
const size_t x_sw = x.sig_words();
BigInt z(BigInt::Positive, x_sw + 1);
if(x_sw && y)
{
bigint_linmul3(z.mutable_data(), x.data(), x_sw, y);
z.set_sign(x.sign());
}
return z;
}
/*
* Division Operator
*/

View File

@@ -96,7 +96,7 @@ BigInt::BigInt(const uint8_t input[], size_t length, Base base)
BigInt::BigInt(const uint8_t buf[], size_t length, size_t max_bits)
{
const size_t max_bytes = std::min(length, (max_bits + 7) / 8);
*this = decode(buf, max_bytes);
binary_decode(buf, max_bytes);
const size_t b = this->bits();
if(b > max_bits)
@@ -163,18 +163,19 @@ void BigInt::encode_words(word out[], size_t size) const
*/
uint32_t BigInt::get_substring(size_t offset, size_t length) const
{
if(length > 32)
throw Invalid_Argument("BigInt::get_substring: Substring size " + std::to_string(length) + " too big");
if(length == 0 || length > 32)
throw Invalid_Argument("BigInt::get_substring invalid substring length");
uint64_t piece = 0;
for(size_t i = 0; i != 8; ++i)
{
const uint8_t part = byte_at((offset / 8) + (7-i));
piece = (piece << 8) | part;
}
const uint64_t mask = (static_cast<uint64_t>(1) << length) - 1;
const size_t byte_offset = offset / 8;
const size_t shift = (offset % 8);
const uint32_t mask = 0xFFFFFFFF >> (32 - length);
const uint8_t b0 = byte_at(byte_offset);
const uint8_t b1 = byte_at(byte_offset + 1);
const uint8_t b2 = byte_at(byte_offset + 2);
const uint8_t b3 = byte_at(byte_offset + 3);
const uint8_t b4 = byte_at(byte_offset + 4);
const uint64_t piece = make_uint64(0, 0, 0, b4, b3, b2, b1, b0);
return static_cast<uint32_t>((piece >> shift) & mask);
}
@@ -341,6 +342,21 @@ void BigInt::binary_decode(const uint8_t buf[], size_t length)
m_reg[length / WORD_BYTES] = (m_reg[length / WORD_BYTES] << 8) | buf[i];
}
void BigInt::ct_cond_assign(bool predicate, BigInt& other)
{
const size_t t_words = size();
const size_t o_words = other.size();
const size_t r_words = std::max(t_words, o_words);
const word mask = CT::expand_mask<word>(predicate);
for(size_t i = 0; i != r_words; ++i)
{
this->set_word_at(i, CT::select<word>(mask, other.word_at(i), this->word_at(i)));
}
}
#if defined(BOTAN_HAS_VALGRIND)
void BigInt::const_time_poison() const
{

View File

@@ -77,6 +77,13 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
*/
BigInt(const uint8_t buf[], size_t length);
/**
* Create a BigInt from an integer in a byte array
* @param vec the byte vector holding the value
*/
template<typename Alloc>
explicit BigInt(const std::vector<uint8_t, Alloc>& vec) : BigInt(vec.data(), vec.size()) {}
/**
* Create a BigInt from an integer in a byte array
* @param buf the byte array holding the value
@@ -422,6 +429,17 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
*/
uint32_t to_u32bit() const;
/**
* Convert this value to a decimal string.
* Warning: decimal conversions are relatively slow
*/
std::string to_dec_string() const;
/**
* Convert this value to a hexadecimal string.
*/
std::string to_hex_string() const;
/**
* @param n the offset to get a byte from
* @result byte at offset n
@@ -616,6 +634,12 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
*/
void encode_words(word out[], size_t size) const;
/**
* If predicate is true assign other to *this
* Uses a masked operation to avoid side channels
*/
void ct_cond_assign(bool predicate, BigInt& other);
#if defined(BOTAN_HAS_VALGRIND)
void const_time_poison() const;
void const_time_unpoison() const;
@@ -646,13 +670,78 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
return b;
}
/**
* Encode the integer value from a BigInt to a std::vector of bytes
* @param n the BigInt to use as integer source
* @result secure_vector of bytes containing the bytes of the integer
*/
static std::vector<uint8_t> encode(const BigInt& n)
{
std::vector<uint8_t> output(n.bytes());
n.binary_encode(output.data());
return output;
}
/**
* Encode the integer value from a BigInt to a secure_vector of bytes
* @param n the BigInt to use as integer source
* @result secure_vector of bytes containing the bytes of the integer
*/
static secure_vector<uint8_t> encode_locked(const BigInt& n)
{
secure_vector<uint8_t> output(n.bytes());
n.binary_encode(output.data());
return output;
}
/**
* Encode the integer value from a BigInt to a byte array
* @param buf destination byte array for the encoded integer
* @param n the BigInt to use as integer source
*/
static void encode(uint8_t buf[], const BigInt& n)
{
n.binary_encode(buf);
}
/**
* Create a BigInt from an integer in a byte array
* @param buf the binary value to load
* @param length size of buf
* @result BigInt representing the integer in the byte array
*/
static BigInt decode(const uint8_t buf[], size_t length)
{
return BigInt(buf, length);
}
/**
* Create a BigInt from an integer in a byte array
* @param buf the binary value to load
* @result BigInt representing the integer in the byte array
*/
static BigInt decode(const secure_vector<uint8_t>& buf)
{
return BigInt(buf);
}
/**
* Create a BigInt from an integer in a byte array
* @param buf the binary value to load
* @result BigInt representing the integer in the byte array
*/
static BigInt decode(const std::vector<uint8_t>& buf)
{
return BigInt(buf);
}
/**
* Encode the integer value from a BigInt to a std::vector of bytes
* @param n the BigInt to use as integer source
* @param base number-base of resulting byte array representation
* @result secure_vector of bytes containing the integer with given base
*/
static std::vector<uint8_t> encode(const BigInt& n, Base base = Binary);
static std::vector<uint8_t> encode(const BigInt& n, Base base);
/**
* Encode the integer value from a BigInt to a secure_vector of bytes
@@ -661,7 +750,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
* @result secure_vector of bytes containing the integer with given base
*/
static secure_vector<uint8_t> encode_locked(const BigInt& n,
Base base = Binary);
Base base);
/**
* Encode the integer value from a BigInt to a byte array
@@ -670,7 +759,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
* @param n the BigInt to use as integer source
* @param base number-base of resulting byte array representation
*/
static void encode(uint8_t buf[], const BigInt& n, Base base = Binary);
static void encode(uint8_t buf[], const BigInt& n, Base base);
/**
* Create a BigInt from an integer in a byte array
@@ -680,7 +769,7 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
* @result BigInt representing the integer in the byte array
*/
static BigInt decode(const uint8_t buf[], size_t length,
Base base = Binary);
Base base);
/**
* Create a BigInt from an integer in a byte array
@@ -689,8 +778,10 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
* @result BigInt representing the integer in the byte array
*/
static BigInt decode(const secure_vector<uint8_t>& buf,
Base base = Binary)
Base base)
{
if(base == Binary)
return BigInt(buf);
return BigInt::decode(buf.data(), buf.size(), base);
}
@@ -700,9 +791,10 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
* @param base number-base of the integer in buf
* @result BigInt representing the integer in the byte array
*/
static BigInt decode(const std::vector<uint8_t>& buf,
Base base = Binary)
static BigInt decode(const std::vector<uint8_t>& buf, Base base)
{
if(base == Binary)
return BigInt(buf);
return BigInt::decode(buf.data(), buf.size(), base);
}
@@ -750,6 +842,9 @@ BigInt BOTAN_PUBLIC_API(2,0) operator-(const BigInt& x, const BigInt& y);
BigInt BOTAN_PUBLIC_API(2,7) operator-(const BigInt& x, word y);
BigInt BOTAN_PUBLIC_API(2,0) operator*(const BigInt& x, const BigInt& y);
BigInt BOTAN_PUBLIC_API(2,8) operator*(const BigInt& x, word y);
inline BigInt operator*(word x, const BigInt& y) { return y*x; }
BigInt BOTAN_PUBLIC_API(2,0) operator/(const BigInt& x, const BigInt& d);
BigInt BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, const BigInt& m);
word BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, word m);

View File

@@ -2,8 +2,6 @@
BIGINT -> 20131128
</defines>
load_on auto
<header:public>
bigint.h
divide.h

View File

@@ -353,11 +353,33 @@ void bigint_shl1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
}
}
namespace {
void bigint_shift_right_1(word x[], size_t x_size)
{
word carry = 0;
size_t top = x_size;
while(top)
{
word w = x[top-1];
x[top-1] = (w >> 1) | carry;
carry = (w << (BOTAN_MP_WORD_BITS - 1));
top--;
}
}
}
/*
* Single Operand Right Shift
*/
void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_shift)
{
if(word_shift == 0 && bit_shift == 1)
return bigint_shift_right_1(x, x_size);
if(x_size < word_shift)
{
clear_mem(x, x_size);

View File

@@ -14,15 +14,10 @@
namespace Botan {
#if (BOTAN_MP_WORD_BITS == 8)
typedef uint16_t dword;
#define BOTAN_HAS_MP_DWORD
#elif (BOTAN_MP_WORD_BITS == 16)
typedef uint32_t dword;
#define BOTAN_HAS_MP_DWORD
#elif (BOTAN_MP_WORD_BITS == 32)
#if (BOTAN_MP_WORD_BITS == 32)
typedef uint64_t dword;
#define BOTAN_HAS_MP_DWORD
#elif (BOTAN_MP_WORD_BITS == 64)
#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
typedef uint128_t dword;
@@ -32,21 +27,19 @@ namespace Botan {
#endif
#else
#error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64
#error BOTAN_MP_WORD_BITS must be 32 or 64
#endif
#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32)
#if defined(BOTAN_USE_GCC_INLINE_ASM)
#define BOTAN_MP_USE_X86_32_ASM
#define ASM(x) x "\n\t"
#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
#define BOTAN_MP_USE_X86_32_MSVC_ASM
#endif
#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) && (BOTAN_USE_GCC_INLINE_ASM)
#define BOTAN_MP_USE_X86_64_ASM
#define ASM(x) x "\n\t"
#endif
#if defined(BOTAN_MP_USE_X86_32_ASM) || defined(BOTAN_MP_USE_X86_64_ASM)

View File

@@ -23,8 +23,6 @@ namespace Botan {
BOTAN_PUBLIC_API(2,0) const BigInt& prime_p521();
BOTAN_PUBLIC_API(2,0) void redc_p521(BigInt& x, secure_vector<word>& ws);
#if (BOTAN_MP_WORD_BITS == 32) || (BOTAN_MP_WORD_BITS == 64)
#define BOTAN_HAS_NIST_PRIME_REDUCERS_W32
BOTAN_PUBLIC_API(2,0) const BigInt& prime_p384();
@@ -39,8 +37,6 @@ BOTAN_PUBLIC_API(2,0) void redc_p224(BigInt& x, secure_vector<word>& ws);
BOTAN_PUBLIC_API(2,0) const BigInt& prime_p192();
BOTAN_PUBLIC_API(2,0) void redc_p192(BigInt& x, secure_vector<word>& ws);
#endif
}
#endif

View File

@@ -2,8 +2,6 @@
NUMBERTHEORY -> 20131128
</defines>
load_on auto
<header:public>
curve_nistp.h
numthry.h
@@ -13,6 +11,7 @@ monty.h
</header:public>
<header:internal>
primality.h
def_powm.h
monty_exp.h
</header:internal>

View File

@@ -14,12 +14,11 @@ namespace Botan {
*/
int32_t jacobi(const BigInt& a, const BigInt& n)
{
if(a.is_negative())
throw Invalid_Argument("jacobi: first argument must be non-negative");
if(n.is_even() || n < 2)
throw Invalid_Argument("jacobi: second argument must be odd and > 1");
BigInt x = a, y = n;
BigInt x = a % n;
BigInt y = n;
int32_t J = 1;
while(y > 1)

View File

@@ -14,7 +14,7 @@ namespace Botan {
namespace {
class Prime_Sieve
class Prime_Sieve final
{
public:
Prime_Sieve(const BigInt& init_value) : m_sieve(PRIME_TABLE_SIZE)

View File

@@ -13,7 +13,7 @@ namespace Botan {
Montgomery_Params::Montgomery_Params(const BigInt& p,
const Modular_Reducer& mod_p)
{
if(p.is_negative() || p.is_even())
if(p.is_even() || p < 3)
throw Invalid_Argument("Montgomery_Params invalid modulus");
m_p = p;

View File

@@ -44,7 +44,7 @@ Montgomery_Exponentation_State::Montgomery_Exponentation_State(std::shared_ptr<c
if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ...
throw Invalid_Argument("Invalid window bits for Montgomery exponentiation");
const size_t window_size = (1U << m_window_bits);
const size_t window_size = (static_cast<size_t>(1) << m_window_bits);
m_g.reserve(window_size);
@@ -233,10 +233,10 @@ BigInt monty_multi_exp(std::shared_ptr<const Montgomery_Params> params_p,
H.square_this(ws);
}
const uint8_t z1_b = z1.get_substring(z_bits - i - 2, 2);
const uint8_t z2_b = z2.get_substring(z_bits - i - 2, 2);
const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2);
const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2);
const uint8_t z12 = (4*z2_b) + z1_b;
const uint32_t z12 = (4*z2_b) + z1_b;
H.mul_by(*M[z12], ws);
}

View File

@@ -43,7 +43,7 @@ void redc_p521(BigInt& x, secure_vector<word>& ws)
BOTAN_ASSERT_EQUAL(carry, 0, "Final carry in P-521 reduction");
// Now find the actual carry in bit 522
const uint8_t bit_522_set = x.word_at(p_full_words) >> (p_top_bits);
const word bit_522_set = x.word_at(p_full_words) >> p_top_bits;
#if (BOTAN_MP_WORD_BITS == 64)
static const word p521_words[9] = {
@@ -91,10 +91,8 @@ inline uint32_t get_uint32_t(const BigInt& x, size_t i)
{
#if (BOTAN_MP_WORD_BITS == 32)
return x.word_at(i);
#elif (BOTAN_MP_WORD_BITS == 64)
return static_cast<uint32_t>(x.word_at(i/2) >> ((i % 2)*32));
#else
#error "Not implemented"
return static_cast<uint32_t>(x.word_at(i/2) >> ((i % 2)*32));
#endif
}
@@ -103,10 +101,8 @@ inline void set_words(BigInt& x, size_t i, uint32_t R0, uint32_t R1)
#if (BOTAN_MP_WORD_BITS == 32)
x.set_word_at(i, R0);
x.set_word_at(i+1, R1);
#elif (BOTAN_MP_WORD_BITS == 64)
x.set_word_at(i/2, (static_cast<uint64_t>(R1) << 32) | R0);
#else
#error "Not implemented"
x.set_word_at(i/2, (static_cast<uint64_t>(R1) << 32) | R0);
#endif
}

View File

@@ -14,6 +14,7 @@
#include <botan/internal/mp_core.h>
#include <botan/internal/ct_utils.h>
#include <botan/internal/monty_exp.h>
#include <botan/internal/primality.h>
#include <algorithm>
namespace Botan {
@@ -434,78 +435,43 @@ BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod)
}
}
namespace {
bool mr_witness(BigInt&& y,
const Modular_Reducer& reducer_n,
const BigInt& n_minus_1, size_t s)
BigInt is_perfect_square(const BigInt& C)
{
if(y == 1 || y == n_minus_1)
return false;
if(C < 1)
throw Invalid_Argument("is_perfect_square requires C >= 1");
if(C == 1)
return 1;
for(size_t i = 1; i != s; ++i)
const size_t n = C.bits();
const size_t m = (n + 1) / 2;
const BigInt B = C + BigInt::power_of_2(m);
BigInt X = BigInt::power_of_2(m) - 1;
BigInt X2 = (X*X);
for(;;)
{
y = reducer_n.square(y);
X = (X2 + C) / (2*X);
X2 = (X*X);
if(y == 1) // found a non-trivial square root
return true;
/*
-1 is the trivial square root of unity, so ``a`` is not a
witness for this number - give up
*/
if(y == n_minus_1)
return false;
if(X2 < B)
break;
}
return true; // is a witness
if(X2 == C)
return X;
else
return 0;
}
size_t mr_test_iterations(size_t n_bits, size_t prob, bool random)
{
const size_t base = (prob + 2) / 2; // worst case 4^-t error rate
/*
* If the candidate prime was maliciously constructed, we can't rely
* on arguments based on p being random.
*/
if(random == false)
return base;
/*
* For randomly chosen numbers we can use the estimates from
* http://www.math.dartmouth.edu/~carlp/PDF/paper88.pdf
*
* These values are derived from the inequality for p(k,t) given on
* the second page.
*/
if(prob <= 128)
{
if(n_bits >= 1536)
return 4; // < 2^-133
if(n_bits >= 1024)
return 6; // < 2^-133
if(n_bits >= 512)
return 12; // < 2^-129
if(n_bits >= 256)
return 29; // < 2^-128
}
/*
If the user desires a smaller error probability than we have
precomputed error estimates for, just fall back to using the worst
case error rate.
*/
return base;
}
}
/*
* Test for primality using Miller-Rabin
*/
bool is_prime(const BigInt& n, RandomNumberGenerator& rng,
size_t prob, bool is_random)
bool is_prime(const BigInt& n,
RandomNumberGenerator& rng,
size_t prob,
bool is_random)
{
if(n == 2)
return true;
@@ -520,47 +486,21 @@ bool is_prime(const BigInt& n, RandomNumberGenerator& rng,
return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num);
}
const size_t test_iterations =
mr_test_iterations(n.bits(), prob, is_random && rng.is_seeded());
const size_t t = miller_rabin_test_iterations(n.bits(), prob, is_random);
const BigInt n_minus_1 = n - 1;
const size_t s = low_zero_bits(n_minus_1);
const BigInt nm1_s = n_minus_1 >> s;
const size_t n_bits = n.bits();
Modular_Reducer mod_n(n);
const Modular_Reducer mod_n(n);
auto monty_n = std::make_shared<Montgomery_Params>(n, mod_n);
const size_t powm_window = 4;
for(size_t i = 0; i != test_iterations; ++i)
if(rng.is_seeded())
{
BigInt a;
if(rng.is_seeded())
{
a = BigInt::random_integer(rng, 2, n_minus_1);
}
else
{
/*
* If passed a null RNG just use 2,3,5, ... as bases
*
* This is not ideal but in certain circumstances we need to
* test for primality but have no RNG available.
*/
a = PRIMES[i];
}
auto powm_a_n = monty_precompute(monty_n, a, powm_window);
BigInt y = monty_execute(*powm_a_n, nm1_s, n_bits);
if(mr_witness(std::move(y), mod_n, n_minus_1, s))
if(is_miller_rabin_probable_prime(n, mod_n, rng, t) == false)
return false;
}
return true;
return is_lucas_probable_prime(n, mod_n);
}
else
{
return is_bailie_psw_probable_prime(n, mod_n);
}
}
}

View File

@@ -1,6 +1,6 @@
/*
* Number Theory Functions
* (C) 1999-2007 Jack Lloyd
* (C) 1999-2007,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -22,8 +22,8 @@ class RandomNumberGenerator;
* @return (a*b)+c
*/
BigInt BOTAN_PUBLIC_API(2,0) mul_add(const BigInt& a,
const BigInt& b,
const BigInt& c);
const BigInt& b,
const BigInt& c);
/**
* Fused subtract-multiply
@@ -33,8 +33,8 @@ BigInt BOTAN_PUBLIC_API(2,0) mul_add(const BigInt& a,
* @return (a-b)*c
*/
BigInt BOTAN_PUBLIC_API(2,0) sub_mul(const BigInt& a,
const BigInt& b,
const BigInt& c);
const BigInt& b,
const BigInt& c);
/**
* Fused multiply-subtract
@@ -44,8 +44,8 @@ BigInt BOTAN_PUBLIC_API(2,0) sub_mul(const BigInt& a,
* @return (a*b)-c
*/
BigInt BOTAN_PUBLIC_API(2,0) mul_sub(const BigInt& a,
const BigInt& b,
const BigInt& c);
const BigInt& b,
const BigInt& c);
/**
* Return the absolute value
@@ -108,8 +108,8 @@ BigInt BOTAN_PUBLIC_API(2,0) ct_inverse_mod_odd_modulus(const BigInt& n, const B
* Not const time
*/
size_t BOTAN_PUBLIC_API(2,0) almost_montgomery_inverse(BigInt& result,
const BigInt& a,
const BigInt& b);
const BigInt& a,
const BigInt& b);
/**
* Call almost_montgomery_inverse and correct the result to a^-1 mod b
@@ -126,8 +126,7 @@ BigInt BOTAN_PUBLIC_API(2,0) normalized_montgomery_inverse(const BigInt& a, cons
* @param n is an odd integer > 1
* @return (n / m)
*/
int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a,
const BigInt& n);
int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a, const BigInt& n);
/**
* Modular exponentation
@@ -137,8 +136,8 @@ int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a,
* @return (b^x) % m
*/
BigInt BOTAN_PUBLIC_API(2,0) power_mod(const BigInt& b,
const BigInt& x,
const BigInt& m);
const BigInt& x,
const BigInt& m);
/**
* Compute the square root of x modulo a prime using the
@@ -175,9 +174,18 @@ size_t BOTAN_PUBLIC_API(2,0) low_zero_bits(const BigInt& x);
*/
bool BOTAN_PUBLIC_API(2,0) is_prime(const BigInt& n,
RandomNumberGenerator& rng,
size_t prob = 56,
size_t prob = 64,
bool is_random = false);
/**
* Test if the positive integer x is a perfect square ie if there
* exists some positive integer y st y*y == x
* See FIPS 186-4 sec C.4
* @return 0 if the integer is not a perfect square, otherwise
* returns the positive y st y*y == x
*/
BigInt BOTAN_PUBLIC_API(2,8) is_perfect_square(const BigInt& x);
inline bool quick_check_prime(const BigInt& n, RandomNumberGenerator& rng)
{ return is_prime(n, rng, 32); }
@@ -187,7 +195,6 @@ inline bool check_prime(const BigInt& n, RandomNumberGenerator& rng)
inline bool verify_prime(const BigInt& n, RandomNumberGenerator& rng)
{ return is_prime(n, rng, 80); }
/**
* Randomly generate a prime suitable for discrete logarithm parameters
* @param rng a random number generator

View File

@@ -25,7 +25,7 @@ void Fixed_Window_Exponentiator::set_base(const BigInt& base)
{
m_window_bits = Power_Mod::window_bits(m_exp.bits(), base.bits(), m_hints);
m_g.resize(1U << m_window_bits);
m_g.resize(static_cast<size_t>(1) << m_window_bits);
m_g[0] = 1;
m_g[1] = base;

View File

@@ -0,0 +1,206 @@
/*
* (C) 2016,2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/internal/primality.h>
#include <botan/internal/monty_exp.h>
#include <botan/bigint.h>
#include <botan/monty.h>
#include <botan/reducer.h>
#include <botan/rng.h>
#include <algorithm>
namespace Botan {
bool is_lucas_probable_prime(const BigInt& C, const Modular_Reducer& mod_C)
{
if(C <= 1)
return false;
else if(C == 2)
return true;
else if(C.is_even())
return false;
else if(C == 3 || C == 5 || C == 7 || C == 11 || C == 13)
return true;
BigInt D = 5;
for(;;)
{
int32_t j = jacobi(D, C);
if(j == 0)
return false;
if(j == -1)
break;
// Check 5, -7, 9, -11, 13, -15, 17, ...
if(D.is_negative())
{
D.flip_sign();
D += 2;
}
else
{
D += 2;
D.flip_sign();
}
if(D == 17 && is_perfect_square(C).is_nonzero())
return false;
}
const BigInt K = C + 1;
const size_t K_bits = K.bits() - 1;
BigInt U = 1;
BigInt V = 1;
BigInt Ut, Vt, U2, V2;
for(size_t i = 0; i != K_bits; ++i)
{
const uint8_t k_bit = K.get_bit(K_bits - 1 - i);
Ut = mod_C.multiply(U, V);
Vt = mod_C.reduce(mod_C.square(V) + mod_C.multiply(D, mod_C.square(U)));
if(Vt.is_odd())
Vt += C;
Vt >>= 1;
Vt = mod_C.reduce(Vt);
U = Ut;
V = Vt;
U2 = mod_C.reduce(Ut + Vt);
if(U2.is_odd())
U2 += C;
U2 >>= 1;
V2 = mod_C.reduce(Vt + Ut*D);
if(V2.is_odd())
V2 += C;
V2 >>= 1;
U.ct_cond_assign(k_bit, U2);
V.ct_cond_assign(k_bit, V2);
}
return (U == 0);
}
bool is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n)
{
auto monty_n = std::make_shared<Montgomery_Params>(n, mod_n);
return passes_miller_rabin_test(n, mod_n, monty_n, 2) && is_lucas_probable_prime(n, mod_n);
}
bool is_bailie_psw_probable_prime(const BigInt& n)
{
Modular_Reducer mod_n(n);
return is_bailie_psw_probable_prime(n, mod_n);
}
bool passes_miller_rabin_test(const BigInt& n,
const Modular_Reducer& mod_n,
const std::shared_ptr<Montgomery_Params>& monty_n,
const BigInt& a)
{
BOTAN_ASSERT_NOMSG(n > 1);
const BigInt n_minus_1 = n - 1;
const size_t s = low_zero_bits(n_minus_1);
const BigInt nm1_s = n_minus_1 >> s;
const size_t n_bits = n.bits();
const size_t powm_window = 4;
auto powm_a_n = monty_precompute(monty_n, a, powm_window);
BigInt y = monty_execute(*powm_a_n, nm1_s, n_bits);
if(y == 1 || y == n_minus_1)
return true;
for(size_t i = 1; i != s; ++i)
{
y = mod_n.square(y);
if(y == 1) // found a non-trivial square root
return false;
/*
-1 is the trivial square root of unity, so ``a`` is not a
witness for this number - give up
*/
if(y == n_minus_1)
return true;
}
return false;
}
bool is_miller_rabin_probable_prime(const BigInt& n,
const Modular_Reducer& mod_n,
RandomNumberGenerator& rng,
size_t test_iterations)
{
BOTAN_ASSERT_NOMSG(n > 1);
auto monty_n = std::make_shared<Montgomery_Params>(n, mod_n);
for(size_t i = 0; i != test_iterations; ++i)
{
const BigInt a = BigInt::random_integer(rng, 2, n);
if(!passes_miller_rabin_test(n, mod_n, monty_n, a))
return false;
}
// Failed to find a counterexample
return true;
}
size_t miller_rabin_test_iterations(size_t n_bits, size_t prob, bool random)
{
const size_t base = (prob + 2) / 2; // worst case 4^-t error rate
/*
* If the candidate prime was maliciously constructed, we can't rely
* on arguments based on p being random.
*/
if(random == false)
return base;
/*
* For randomly chosen numbers we can use the estimates from
* http://www.math.dartmouth.edu/~carlp/PDF/paper88.pdf
*
* These values are derived from the inequality for p(k,t) given on
* the second page.
*/
if(prob <= 128)
{
if(n_bits >= 1536)
return 4; // < 2^-133
if(n_bits >= 1024)
return 6; // < 2^-133
if(n_bits >= 512)
return 12; // < 2^-129
if(n_bits >= 256)
return 29; // < 2^-128
}
/*
If the user desires a smaller error probability than we have
precomputed error estimates for, just fall back to using the worst
case error rate.
*/
return base;
}
}

View File

@@ -0,0 +1,100 @@
/*
* (C) 2018 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#ifndef BOTAN_PRIMALITY_TEST_H_
#define BOTAN_PRIMALITY_TEST_H_
#include <botan/types.h>
#include <memory>
namespace Botan {
class BigInt;
class Modular_Reducer;
class Montgomery_Params;
class RandomNumberGenerator;
/**
* Perform Lucas primality test
* @see FIPS 186-4 C.3.3
*
* @warning it is possible to construct composite integers which pass
* this test alone.
*
* @param n the positive integer to test
* @param mod_n a pre-created Modular_Reducer for n
* @return true if n seems probably prime, false if n is composite
*/
bool BOTAN_TEST_API is_lucas_probable_prime(const BigInt& n, const Modular_Reducer& mod_n);
/**
* Perform Bailie-PSW primality test
*
* This is a combination of Miller-Rabin with base 2 and a Lucas test. No known
* composite integer passes both tests, though it is conjectured that infinitely
* many composite counterexamples exist.
*
* @param n the positive integer to test
* @param mod_n a pre-created Modular_Reducer for n
* @return true if n seems probably prime, false if n is composite
*/
bool BOTAN_TEST_API is_bailie_psw_probable_prime(const BigInt& n, const Modular_Reducer& mod_n);
/**
* Perform Bailie-PSW primality test
*
* This is a combination of Miller-Rabin with base 2 and a Lucas test. No known
* composite integer passes both tests, though it is conjectured that infinitely
* many composite counterexamples exist.
*
* @param n the positive integer to test
* @return true if n seems probably prime, false if n is composite
*/
bool is_bailie_psw_probable_prime(const BigInt& n);
/**
* Return required number of Miller-Rabin tests in order to
* reach the specified probability of error.
*
* @param n_bits the bit-length of the integer being tested
* @param prob chance of false positive is bounded by 1/2**prob
* @param random is set if (and only if) the integer was randomly generated by us
* and thus cannot have been maliciously constructed.
*/
size_t miller_rabin_test_iterations(size_t n_bits, size_t prob, bool random);
/**
* Perform a single Miller-Rabin test with specified base
*
* @param n the positive integer to test
* @param mod_n a pre-created Modular_Reducer for n
* @param monty_n Montgomery parameters for n
* @param a the base to check
* @return result of primality test
*/
bool passes_miller_rabin_test(const BigInt& n,
const Modular_Reducer& mod_n,
const std::shared_ptr<Montgomery_Params>& monty_n,
const BigInt& a);
/**
* Perform t iterations of a Miller-Rabin primality test with random bases
*
* @param n the positive integer to test
* @param mod_n a pre-created Modular_Reducer for n
* @param rng a random number generator
* @param t number of tests to perform
*
* @return result of primality test
*/
bool BOTAN_TEST_API is_miller_rabin_probable_prime(const BigInt& n,
const Modular_Reducer& mod_n,
RandomNumberGenerator& rng,
size_t t);
}
#endif

View File

@@ -32,11 +32,18 @@ Modular_Reducer::Modular_Reducer(const BigInt& mod)
}
}
/*
* Barrett Reduction
*/
BigInt Modular_Reducer::reduce(const BigInt& x) const
{
BigInt r;
secure_vector<word> ws;
reduce(r, x, ws);
return r;
}
void Modular_Reducer::reduce(BigInt& t1, const BigInt& x, secure_vector<word>& ws) const
{
if(&t1 == &x)
throw Invalid_State("Modular_Reducer arguments cannot alias");
if(m_mod_words == 0)
throw Invalid_State("Modular_Reducer: Never initalized");
@@ -45,12 +52,11 @@ BigInt Modular_Reducer::reduce(const BigInt& x) const
if(x_sw >= (2*m_mod_words - 1) && x.cmp(m_modulus_2, false) >= 0)
{
// too big, fall back to normal division
return (x % m_modulus);
t1 = x % m_modulus;
return;
}
secure_vector<word> ws;
BigInt t1 = x;
t1 = x;
t1.set_sign(BigInt::Positive);
t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words - 1));
@@ -83,8 +89,6 @@ BigInt Modular_Reducer::reduce(const BigInt& x) const
{
t1.rev_sub(m_modulus.data(), m_modulus.size(), ws);
}
return t1;
}
}

View File

@@ -47,6 +47,8 @@ class BOTAN_PUBLIC_API(2,0) Modular_Reducer
BigInt cube(const BigInt& x) const
{ return multiply(x, this->square(x)); }
void reduce(BigInt& out, const BigInt& x, secure_vector<word>& ws) const;
bool initialized() const { return (m_mod_words != 0); }
Modular_Reducer() { m_mod_words = 0; }

View File

@@ -2,6 +2,7 @@
* CBC Mode
* (C) 1999-2007,2013,2017 Jack Lloyd
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
* (C) 2018 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -15,9 +16,9 @@ namespace Botan {
CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
m_cipher(cipher),
m_padding(padding),
m_state(m_cipher->block_size())
m_block_size(cipher->block_size())
{
if(m_padding && !m_padding->valid_blocksize(cipher->block_size()))
if(m_padding && !m_padding->valid_blocksize(m_block_size))
throw Invalid_Argument("Padding " + m_padding->name() +
" cannot be used with " +
cipher->name() + "/CBC");
@@ -31,7 +32,7 @@ void CBC_Mode::clear()
void CBC_Mode::reset()
{
zeroise(m_state);
m_state.clear();
}
std::string CBC_Mode::name() const
@@ -65,6 +66,7 @@ bool CBC_Mode::valid_nonce_length(size_t n) const
void CBC_Mode::key_schedule(const uint8_t key[], size_t length)
{
m_cipher->set_key(key, length);
m_state.clear();
}
void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
@@ -79,6 +81,9 @@ void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len)
*/
if(nonce_len)
m_state.assign(nonce, nonce + nonce_len);
else if(m_state.empty())
m_state.resize(m_cipher->block_size());
// else leave the state alone
}
size_t CBC_Encryption::minimum_final_size() const
@@ -96,6 +101,7 @@ size_t CBC_Encryption::output_length(size_t input_length) const
size_t CBC_Encryption::process(uint8_t buf[], size_t sz)
{
BOTAN_STATE_CHECK(state().empty() == false);
const size_t BS = block_size();
BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks");
@@ -120,6 +126,7 @@ size_t CBC_Encryption::process(uint8_t buf[], size_t sz)
void CBC_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
{
BOTAN_STATE_CHECK(state().empty() == false);
BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
const size_t BS = block_size();
@@ -151,6 +158,7 @@ size_t CTS_Encryption::output_length(size_t input_length) const
void CTS_Encryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
{
BOTAN_STATE_CHECK(state().empty() == false);
BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
uint8_t* buf = buffer.data() + offset;
const size_t sz = buffer.size() - offset;
@@ -205,6 +213,8 @@ size_t CBC_Decryption::minimum_final_size() const
size_t CBC_Decryption::process(uint8_t buf[], size_t sz)
{
BOTAN_STATE_CHECK(state().empty() == false);
const size_t BS = block_size();
BOTAN_ASSERT(sz % BS == 0, "Input is full blocks");
@@ -231,6 +241,7 @@ size_t CBC_Decryption::process(uint8_t buf[], size_t sz)
void CBC_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
{
BOTAN_STATE_CHECK(state().empty() == false);
BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
const size_t sz = buffer.size() - offset;
@@ -251,7 +262,7 @@ void CBC_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
void CBC_Decryption::reset()
{
zeroise(state());
CBC_Mode::reset();
zeroise(m_tempbuf);
}
@@ -267,6 +278,7 @@ size_t CTS_Decryption::minimum_final_size() const
void CTS_Decryption::finish(secure_vector<uint8_t>& buffer, size_t offset)
{
BOTAN_STATE_CHECK(state().empty() == false);
BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
const size_t sz = buffer.size() - offset;
uint8_t* buf = buffer.data() + offset;

View File

@@ -46,9 +46,9 @@ class BOTAN_PUBLIC_API(2,0) CBC_Mode : public Cipher_Mode
return *m_padding;
}
secure_vector<uint8_t>& state() { return m_state; }
size_t block_size() const { return m_block_size; }
size_t block_size() const { return m_state.size(); }
secure_vector<uint8_t>& state() { return m_state; }
uint8_t* state_ptr() { return m_state.data(); }
@@ -60,6 +60,7 @@ class BOTAN_PUBLIC_API(2,0) CBC_Mode : public Cipher_Mode
std::unique_ptr<BlockCipher> m_cipher;
std::unique_ptr<BlockCipherModePaddingMethod> m_padding;
secure_vector<uint8_t> m_state;
size_t m_block_size;
};
/**

View File

@@ -35,6 +35,10 @@
#include <botan/internal/openssl.h>
#endif
#if defined(BOTAN_HAS_COMMONCRYPTO)
#include <botan/internal/commoncrypto.h>
#endif
namespace Botan {
std::unique_ptr<Cipher_Mode> Cipher_Mode::create_or_throw(const std::string& algo,
@@ -51,6 +55,19 @@ std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo,
Cipher_Dir direction,
const std::string& provider)
{
#if defined(BOTAN_HAS_COMMONCRYPTO)
if(provider.empty() || provider == "commoncrypto")
{
std::unique_ptr<Cipher_Mode> commoncrypto_cipher(make_commoncrypto_cipher_mode(algo, direction));
if(commoncrypto_cipher)
return commoncrypto_cipher;
if(!provider.empty())
return std::unique_ptr<Cipher_Mode>();
}
#endif
#if defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl")
{
@@ -172,7 +189,7 @@ std::unique_ptr<Cipher_Mode> Cipher_Mode::create(const std::string& algo,
//static
std::vector<std::string> Cipher_Mode::providers(const std::string& algo_spec)
{
const std::vector<std::string>& possible = { "base", "openssl" };
const std::vector<std::string>& possible = { "base", "openssl", "commoncrypto" };
std::vector<std::string> providers;
for(auto&& prov : possible)
{

View File

@@ -9,9 +9,8 @@
#define BOTAN_CIPHER_MODE_H_
#include <botan/secmem.h>
#include <botan/key_spec.h>
#include <botan/sym_algo.h>
#include <botan/exceptn.h>
#include <botan/symkey.h>
#include <string>
#include <vector>
@@ -26,11 +25,9 @@ enum Cipher_Dir : int { ENCRYPTION, DECRYPTION };
/**
* Interface for cipher modes
*/
class BOTAN_PUBLIC_API(2,0) Cipher_Mode
class BOTAN_PUBLIC_API(2,0) Cipher_Mode : public SymmetricAlgorithm
{
public:
virtual ~Cipher_Mode() = default;
/**
* @return list of available providers for this algorithm, empty if not available
* @param algo_spec algorithm name
@@ -133,8 +130,9 @@ class BOTAN_PUBLIC_API(2,0) Cipher_Mode
/**
* Returns the size of the output if this transform is used to process a
* message with input_length bytes. Will throw if unable to give a precise
* answer.
* message with input_length bytes. In most cases the answer is precise.
* If it is not possible to precise (namely for CBC decryption) instead a
* lower bound is returned.
*/
virtual size_t output_length(size_t input_length) const = 0;
@@ -159,14 +157,6 @@ class BOTAN_PUBLIC_API(2,0) Cipher_Mode
*/
virtual bool valid_nonce_length(size_t nonce_len) const = 0;
virtual std::string name() const = 0;
/**
* Zeroise all state
* See also reset_msg()
*/
virtual void clear() = 0;
/**
* Resets just the message specific state and allows encrypting again under the existing key
*/
@@ -183,60 +173,11 @@ class BOTAN_PUBLIC_API(2,0) Cipher_Mode
*/
virtual size_t tag_size() const { return 0; }
/**
* @return object describing limits on key size
*/
virtual Key_Length_Specification key_spec() const = 0;
/**
* Check whether a given key length is valid for this algorithm.
* @param length the key length to be checked.
* @return true if the key length is valid.
*/
bool valid_keylength(size_t length) const
{
return key_spec().valid_keylength(length);
}
/**
* Set the symmetric key of this transform
* @param key contains the key material
*/
template<typename Alloc>
void set_key(const std::vector<uint8_t, Alloc>& key)
{
set_key(key.data(), key.size());
}
/**
* Set the symmetric key of this transform
* @param key contains the key material
*/
void set_key(const SymmetricKey& key)
{
set_key(key.begin(), key.length());
}
/**
* Set the symmetric key of this transform
* @param key contains the key material
* @param length in bytes of key param
*/
void set_key(const uint8_t key[], size_t length)
{
if(!valid_keylength(length))
throw Invalid_Key_Length(name(), length);
key_schedule(key, length);
}
/**
* @return provider information about this implementation. Default is "base",
* might also return "sse2", "avx2", "openssl", or some other arbitrary string.
*/
virtual std::string provider() const { return "base"; }
private:
virtual void key_schedule(const uint8_t key[], size_t length) = 0;
};
/**

View File

@@ -1,6 +1,6 @@
/*
* CBC Padding Methods
* (C) 1999-2007,2013 Jack Lloyd
* (C) 1999-2007,2013,2018 Jack Lloyd
* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
*
* Botan is released under the Simplified BSD License (see license.txt)
@@ -51,26 +51,27 @@ void PKCS7_Padding::add_padding(secure_vector<uint8_t>& buffer,
/*
* Unpad with PKCS #7 Method
*/
size_t PKCS7_Padding::unpad(const uint8_t block[], size_t size) const
size_t PKCS7_Padding::unpad(const uint8_t input[], size_t input_length) const
{
CT::poison(block,size);
if(input_length <= 2)
return input_length;
CT::poison(input, input_length);
size_t bad_input = 0;
const uint8_t last_byte = block[size-1];
const uint8_t last_byte = input[input_length-1];
bad_input |= CT::expand_mask<size_t>(last_byte > size);
bad_input |= CT::expand_mask<size_t>(last_byte > input_length);
size_t pad_pos = size - last_byte;
size_t i = size - 2;
while(i)
const size_t pad_pos = input_length - last_byte;
for(size_t i = 0; i != input_length - 1; ++i)
{
bad_input |= (~CT::is_equal(block[i],last_byte)) & CT::expand_mask<uint8_t>(i >= pad_pos);
--i;
const uint8_t in_range = CT::expand_mask<uint8_t>(i >= pad_pos);
bad_input |= in_range & (~CT::is_equal(input[i], last_byte));
}
CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1);
CT::unpoison(block,size);
CT::unpoison(pad_pos);
return pad_pos;
CT::unpoison(input, input_length);
return CT::conditional_return(bad_input, input_length, pad_pos);
}
/*
@@ -92,25 +93,27 @@ void ANSI_X923_Padding::add_padding(secure_vector<uint8_t>& buffer,
/*
* Unpad with ANSI X9.23 Method
*/
size_t ANSI_X923_Padding::unpad(const uint8_t block[], size_t size) const
size_t ANSI_X923_Padding::unpad(const uint8_t input[], size_t input_length) const
{
CT::poison(block,size);
size_t bad_input = 0;
const size_t last_byte = block[size-1];
if(input_length <= 2)
return input_length;
bad_input |= CT::expand_mask<size_t>(last_byte > size);
CT::poison(input, input_length);
const size_t last_byte = input[input_length-1];
size_t pad_pos = size - last_byte;
size_t i = size - 2;
while(i)
uint8_t bad_input = 0;
bad_input |= CT::expand_mask<uint8_t>(last_byte > input_length);
const size_t pad_pos = input_length - last_byte;
for(size_t i = 0; i != input_length - 1; ++i)
{
bad_input |= (~CT::is_zero(block[i])) & CT::expand_mask<uint8_t>(i >= pad_pos);
--i;
const uint8_t in_range = CT::expand_mask<uint8_t>(i >= pad_pos);
bad_input |= CT::expand_mask(input[i]) & in_range;
}
CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1);
CT::unpoison(block,size);
CT::unpoison(pad_pos);
return pad_pos;
CT::unpoison(input, input_length);
return CT::conditional_return(bad_input, input_length, pad_pos);
}
/*
@@ -129,28 +132,29 @@ void OneAndZeros_Padding::add_padding(secure_vector<uint8_t>& buffer,
/*
* Unpad with One and Zeros Method
*/
size_t OneAndZeros_Padding::unpad(const uint8_t block[], size_t size) const
size_t OneAndZeros_Padding::unpad(const uint8_t input[], size_t input_length) const
{
CT::poison(block, size);
if(input_length <= 2)
return input_length;
CT::poison(input, input_length);
uint8_t bad_input = 0;
uint8_t seen_one = 0;
size_t pad_pos = size - 1;
size_t i = size;
size_t pad_pos = input_length - 1;
size_t i = input_length;
while(i)
{
seen_one |= CT::is_equal<uint8_t>(block[i-1],0x80);
seen_one |= CT::is_equal<uint8_t>(input[i-1], 0x80);
pad_pos -= CT::select<uint8_t>(~seen_one, 1, 0);
bad_input |= ~CT::is_zero<uint8_t>(block[i-1]) & ~seen_one;
bad_input |= ~CT::is_zero<uint8_t>(input[i-1]) & ~seen_one;
i--;
}
bad_input |= ~seen_one;
CT::conditional_copy_mem(size_t(bad_input),&pad_pos,&size,&pad_pos,1);
CT::unpoison(block, size);
CT::unpoison(pad_pos);
return pad_pos;
CT::unpoison(input, input_length);
return CT::conditional_return(bad_input, input_length, pad_pos);
}
/*
@@ -171,25 +175,28 @@ void ESP_Padding::add_padding(secure_vector<uint8_t>& buffer,
/*
* Unpad with ESP Padding Method
*/
size_t ESP_Padding::unpad(const uint8_t block[], size_t size) const
size_t ESP_Padding::unpad(const uint8_t input[], size_t input_length) const
{
CT::poison(block,size);
if(input_length <= 2)
return input_length;
const size_t last_byte = block[size-1];
size_t bad_input = 0;
bad_input |= CT::expand_mask<size_t>(last_byte > size);
CT::poison(input, input_length);
size_t pad_pos = size - last_byte;
size_t i = size - 1;
const size_t last_byte = input[input_length-1];
uint8_t bad_input = 0;
bad_input |= CT::is_zero(last_byte) | CT::expand_mask<uint8_t>(last_byte > input_length);
const size_t pad_pos = input_length - last_byte;
size_t i = input_length - 1;
while(i)
{
bad_input |= ~CT::is_equal<uint8_t>(size_t(block[i-1]),size_t(block[i])-1) & CT::expand_mask<uint8_t>(i > pad_pos);
const uint8_t in_range = CT::expand_mask<uint8_t>(i > pad_pos);
bad_input |= (~CT::is_equal<uint8_t>(input[i-1], input[i]-1)) & in_range;
--i;
}
CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1);
CT::unpoison(block, size);
CT::unpoison(pad_pos);
return pad_pos;
CT::unpoison(input, input_length);
return CT::conditional_return(bad_input, input_length, pad_pos);
}

View File

@@ -39,11 +39,10 @@ class BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod
/**
* Remove padding bytes from block
* @param block the last block
* @param size the size of the block in bytes
* @return number of padding bytes
* @param len the size of the block in bytes
* @return number of data bytes, or if the padding is invalid returns len
*/
virtual size_t unpad(const uint8_t block[],
size_t size) const = 0;
virtual size_t unpad(const uint8_t block[], size_t len) const = 0;
/**
* @param block_size of the cipher
@@ -74,7 +73,7 @@ class BOTAN_PUBLIC_API(2,0) PKCS7_Padding final : public BlockCipherModePaddingM
size_t unpad(const uint8_t[], size_t) const override;
bool valid_blocksize(size_t bs) const override { return (bs > 0 && bs < 256); }
bool valid_blocksize(size_t bs) const override { return (bs > 2 && bs < 256); }
std::string name() const override { return "PKCS7"; }
};
@@ -91,7 +90,7 @@ class BOTAN_PUBLIC_API(2,0) ANSI_X923_Padding final : public BlockCipherModePadd
size_t unpad(const uint8_t[], size_t) const override;
bool valid_blocksize(size_t bs) const override { return (bs > 0 && bs < 256); }
bool valid_blocksize(size_t bs) const override { return (bs > 2 && bs < 256); }
std::string name() const override { return "X9.23"; }
};
@@ -108,7 +107,7 @@ class BOTAN_PUBLIC_API(2,0) OneAndZeros_Padding final : public BlockCipherModePa
size_t unpad(const uint8_t[], size_t) const override;
bool valid_blocksize(size_t bs) const override { return (bs > 0); }
bool valid_blocksize(size_t bs) const override { return (bs > 2); }
std::string name() const override { return "OneAndZeros"; }
};
@@ -125,7 +124,7 @@ class BOTAN_PUBLIC_API(2,0) ESP_Padding final : public BlockCipherModePaddingMet
size_t unpad(const uint8_t[], size_t) const override;
bool valid_blocksize(size_t bs) const override { return (bs > 0); }
bool valid_blocksize(size_t bs) const override { return (bs > 2 && bs < 256); }
std::string name() const override { return "ESP"; }
};

View File

@@ -1,5 +1,5 @@
<defines>
PBKDF -> 20150626
PBKDF -> 20180902
</defines>
<requires>
@@ -8,5 +8,6 @@ hash
</requires>
<header:public>
pwdhash.h
pbkdf.h
</header:public>

View File

@@ -17,6 +17,9 @@ namespace Botan {
* Base class for PBKDF (password based key derivation function)
* implementations. Converts a password into a key using a salt
* and iterated hashing to make brute force attacks harder.
*
* Starting in 2.8 this functionality is also offered by PasswordHash.
* The PBKDF interface may be removed in a future release.
*/
class BOTAN_PUBLIC_API(2,0) PBKDF
{
@@ -216,7 +219,7 @@ class BOTAN_PUBLIC_API(2,0) PBKDF
};
/*
* Compatability typedef
* Compatibility typedef
*/
typedef PBKDF S2K;

View File

@@ -1,5 +1,5 @@
<defines>
PBKDF2 -> 20131128
PBKDF2 -> 20180902
</defines>
<requires>

View File

@@ -1,6 +1,7 @@
/*
* PBKDF2
* (C) 1999-2007 Jack Lloyd
* (C) 2018 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -8,42 +9,116 @@
#include <botan/pbkdf2.h>
#include <botan/exceptn.h>
#include <botan/internal/rounding.h>
#include <botan/internal/timer.h>
namespace Botan {
namespace {
void pbkdf2_set_key(MessageAuthenticationCode& prf,
const char* password,
size_t password_len)
{
try
{
prf.set_key(cast_char_ptr_to_uint8(password), password_len);
}
catch(Invalid_Key_Length&)
{
throw Exception("PBKDF2 cannot accept passphrase of the given size");
}
}
}
size_t
pbkdf2(MessageAuthenticationCode& prf,
uint8_t out[],
size_t out_len,
const std::string& passphrase,
const std::string& password,
const uint8_t salt[], size_t salt_len,
size_t iterations,
std::chrono::milliseconds msec)
{
if(iterations == 0)
{
iterations = PBKDF2(prf, out_len, msec).iterations();
}
PBKDF2 pbkdf2(prf, iterations);
pbkdf2.derive_key(out, out_len,
password.c_str(), password.size(),
salt, salt_len);
return iterations;
}
namespace {
size_t tune_pbkdf2(MessageAuthenticationCode& prf,
size_t output_length,
uint32_t msec)
{
const size_t prf_sz = prf.output_length();
BOTAN_ASSERT_NOMSG(prf_sz > 0);
secure_vector<uint8_t> U(prf_sz);
const size_t trial_iterations = 10000;
// Short output ensures we only need a single PBKDF2 block
Timer timer("PBKDF2");
const std::chrono::milliseconds tune_msec(30);
prf.set_key(nullptr, 0);
timer.run_until_elapsed(tune_msec, [&]() {
uint8_t out[16] = { 0 };
uint8_t salt[16] = { 0 };
pbkdf2(prf, out, sizeof(out), salt, sizeof(salt), trial_iterations);
});
if(timer.events() == 0)
return trial_iterations;
const uint64_t duration_nsec = timer.value() / timer.events();
const uint64_t desired_nsec = static_cast<uint64_t>(msec) * 1000000;
if(duration_nsec > desired_nsec)
return trial_iterations;
const size_t blocks_needed = (output_length + prf_sz - 1) / prf_sz;
const size_t multiplier = (desired_nsec / duration_nsec / blocks_needed);
if(multiplier == 0)
return trial_iterations;
else
return trial_iterations * multiplier;
}
}
void pbkdf2(MessageAuthenticationCode& prf,
uint8_t out[],
size_t out_len,
const uint8_t salt[],
size_t salt_len,
size_t iterations)
{
clear_mem(out, out_len);
if(out_len == 0)
return 0;
try
{
prf.set_key(cast_char_ptr_to_uint8(passphrase.data()), passphrase.size());
}
catch(Invalid_Key_Length&)
{
throw Exception("PBKDF2 with " + prf.name() +
" cannot accept passphrases of length " +
std::to_string(passphrase.size()));
}
return;
const size_t prf_sz = prf.output_length();
BOTAN_ASSERT_NOMSG(prf_sz > 0);
secure_vector<uint8_t> U(prf_sz);
const size_t blocks_needed = round_up(out_len, prf_sz) / prf_sz;
std::chrono::microseconds usec_per_block =
std::chrono::duration_cast<std::chrono::microseconds>(msec) / blocks_needed;
uint32_t counter = 1;
while(out_len)
{
@@ -55,64 +130,93 @@ pbkdf2(MessageAuthenticationCode& prf,
xor_buf(out, U.data(), prf_output);
if(iterations == 0)
for(size_t i = 1; i != iterations; ++i)
{
/*
If no iterations set, run the first block to calibrate based
on how long hashing takes on whatever machine we're running on.
*/
const auto start = std::chrono::high_resolution_clock::now();
iterations = 1; // the first iteration we did above
while(true)
{
prf.update(U);
prf.final(U.data());
xor_buf(out, U.data(), prf_output);
iterations++;
/*
Only break on relatively 'even' iterations. For one it
avoids confusion, and likely some broken implementations
break on getting completely randomly distributed values
*/
if(iterations % 10000 == 0)
{
auto time_taken = std::chrono::high_resolution_clock::now() - start;
auto usec_taken = std::chrono::duration_cast<std::chrono::microseconds>(time_taken);
if(usec_taken > usec_per_block)
break;
}
}
}
else
{
for(size_t i = 1; i != iterations; ++i)
{
prf.update(U);
prf.final(U.data());
xor_buf(out, U.data(), prf_output);
}
prf.update(U);
prf.final(U.data());
xor_buf(out, U.data(), prf_output);
}
out_len -= prf_output;
out += prf_output;
}
return iterations;
}
// PBKDF interface
size_t
PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len,
const std::string& passphrase,
const std::string& password,
const uint8_t salt[], size_t salt_len,
size_t iterations,
std::chrono::milliseconds msec) const
{
return pbkdf2(*m_mac.get(), key, key_len, passphrase, salt, salt_len, iterations, msec);
if(iterations == 0)
{
iterations = PBKDF2(*m_mac, key_len, msec).iterations();
}
PBKDF2 pbkdf2(*m_mac, iterations);
pbkdf2.derive_key(key, key_len,
password.c_str(), password.size(),
salt, salt_len);
return iterations;
}
std::string PKCS5_PBKDF2::name() const
{
return "PBKDF2(" + m_mac->name() + ")";
}
PBKDF* PKCS5_PBKDF2::clone() const
{
return new PKCS5_PBKDF2(m_mac->clone());
}
// PasswordHash interface
PBKDF2::PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec) :
m_prf(prf.clone()),
m_iterations(tune_pbkdf2(*m_prf, olen, static_cast<uint32_t>(msec.count())))
{}
std::string PBKDF2::to_string() const
{
return "PBKDF2(" + m_prf->name() + "," + std::to_string(m_iterations) + ")";
}
void PBKDF2::derive_key(uint8_t out[], size_t out_len,
const char* password, const size_t password_len,
const uint8_t salt[], size_t salt_len) const
{
pbkdf2_set_key(*m_prf, password, password_len);
pbkdf2(*m_prf, out, out_len, salt, salt_len, m_iterations);
}
std::string PBKDF2_Family::name() const
{
return "PBKDF2(" + m_prf->name() + ")";
}
std::unique_ptr<PasswordHash> PBKDF2_Family::tune(size_t output_len, std::chrono::milliseconds msec, size_t) const
{
return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, output_len, msec));
}
std::unique_ptr<PasswordHash> PBKDF2_Family::default_params() const
{
return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, 150000));
}
std::unique_ptr<PasswordHash> PBKDF2_Family::from_params(size_t iter, size_t, size_t) const
{
return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, iter));
}
std::unique_ptr<PasswordHash> PBKDF2_Family::from_iterations(size_t iter) const
{
return std::unique_ptr<PasswordHash>(new PBKDF2(*m_prf, iter));
}
}

View File

@@ -1,6 +1,7 @@
/*
* PBKDF2
* (C) 1999-2007,2012 Jack Lloyd
* (C) 2018 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -9,6 +10,7 @@
#define BOTAN_PBKDF2_H_
#include <botan/pbkdf.h>
#include <botan/pwdhash.h>
#include <botan/mac.h>
namespace Botan {
@@ -22,20 +24,76 @@ BOTAN_PUBLIC_API(2,0) size_t pbkdf2(MessageAuthenticationCode& prf,
std::chrono::milliseconds msec);
/**
* PKCS #5 PBKDF2
* Perform PBKDF2. The prf is assumed to be keyed already.
*/
BOTAN_PUBLIC_API(2,8) void pbkdf2(MessageAuthenticationCode& prf,
uint8_t out[], size_t out_len,
const uint8_t salt[], size_t salt_len,
size_t iterations);
/**
* PBKDF2
*/
class BOTAN_PUBLIC_API(2,8) PBKDF2 final : public PasswordHash
{
public:
PBKDF2(const MessageAuthenticationCode& prf, size_t iter) :
m_prf(prf.clone()),
m_iterations(iter)
{}
PBKDF2(const MessageAuthenticationCode& prf, size_t olen, std::chrono::milliseconds msec);
size_t iterations() const override { return m_iterations; }
std::string to_string() const override;
void derive_key(uint8_t out[], size_t out_len,
const char* password, size_t password_len,
const uint8_t salt[], size_t salt_len) const override;
private:
std::unique_ptr<MessageAuthenticationCode> m_prf;
size_t m_iterations;
};
/**
* Family of PKCS #5 PBKDF2 operations
*/
class BOTAN_PUBLIC_API(2,8) PBKDF2_Family final : public PasswordHashFamily
{
public:
PBKDF2_Family(MessageAuthenticationCode* prf) : m_prf(prf) {}
std::string name() const override;
std::unique_ptr<PasswordHash> tune(size_t output_len,
std::chrono::milliseconds msec,
size_t max_memory) const override;
/**
* Return some default parameter set for this PBKDF that should be good
* enough for most users. The value returned may change over time as
* processing power and attacks improve.
*/
std::unique_ptr<PasswordHash> default_params() const override;
std::unique_ptr<PasswordHash> from_iterations(size_t iter) const override;
std::unique_ptr<PasswordHash> from_params(
size_t iter, size_t, size_t) const override;
private:
std::unique_ptr<MessageAuthenticationCode> m_prf;
};
/**
* PKCS #5 PBKDF2 (old interface)
*/
class BOTAN_PUBLIC_API(2,0) PKCS5_PBKDF2 final : public PBKDF
{
public:
std::string name() const override
{
return "PBKDF2(" + m_mac->name() + ")";
}
std::string name() const override;
PBKDF* clone() const override
{
return new PKCS5_PBKDF2(m_mac->clone());
}
PBKDF* clone() const override;
size_t pbkdf(uint8_t output_buf[], size_t output_len,
const std::string& passphrase,

View File

@@ -0,0 +1,88 @@
/*
* (C) 2018 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#include <botan/pbkdf.h>
#include <botan/exceptn.h>
#include <botan/scan_name.h>
#if defined(BOTAN_HAS_PBKDF2)
#include <botan/pbkdf2.h>
#endif
#if defined(BOTAN_HAS_PGP_S2K)
#include <botan/pgp_s2k.h>
#endif
#if defined(BOTAN_HAS_SCRYPT)
#include <botan/scrypt.h>
#endif
namespace Botan {
std::unique_ptr<PasswordHashFamily> PasswordHashFamily::create(const std::string& algo_spec,
const std::string& provider)
{
const SCAN_Name req(algo_spec);
#if defined(BOTAN_HAS_PBKDF2)
if(req.algo_name() == "PBKDF2")
{
// TODO OpenSSL
if(provider.empty() || provider == "base")
{
if(auto mac = MessageAuthenticationCode::create(req.arg(0)))
return std::unique_ptr<PasswordHashFamily>(new PBKDF2_Family(mac.release()));
if(auto mac = MessageAuthenticationCode::create("HMAC(" + req.arg(0) + ")"))
return std::unique_ptr<PasswordHashFamily>(new PBKDF2_Family(mac.release()));
}
return nullptr;
}
#endif
#if defined(BOTAN_HAS_SCRYPT)
if(req.algo_name() == "Scrypt")
{
return std::unique_ptr<PasswordHashFamily>(new Scrypt_Family);
}
#endif
#if defined(BOTAN_HAS_PGP_S2K)
if(req.algo_name() == "OpenPGP-S2K" && req.arg_count() == 1)
{
if(auto hash = HashFunction::create(req.arg(0)))
{
return std::unique_ptr<PasswordHashFamily>(new RFC4880_S2K_Family(hash.release()));
}
}
#endif
BOTAN_UNUSED(req);
BOTAN_UNUSED(provider);
return nullptr;
}
//static
std::unique_ptr<PasswordHashFamily>
PasswordHashFamily::create_or_throw(const std::string& algo,
const std::string& provider)
{
if(auto pbkdf = PasswordHashFamily::create(algo, provider))
{
return pbkdf;
}
throw Lookup_Error("PasswordHashFamily", algo, provider);
}
std::vector<std::string> PasswordHashFamily::providers(const std::string& algo_spec)
{
return probe_providers_of<PasswordHashFamily>(algo_spec, { "base", "openssl" });
}
}

View File

@@ -0,0 +1,162 @@
/*
* (C) 2018 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
#ifndef BOTAN_PWDHASH_H_
#define BOTAN_PWDHASH_H_
#include <botan/types.h>
#include <string>
#include <memory>
#include <vector>
#include <chrono>
namespace Botan {
/**
* Base class for password based key derivation functions.
*
* Converts a password into a key using a salt and iterated hashing to
* make brute force attacks harder.
*/
class BOTAN_PUBLIC_API(2,8) PasswordHash
{
public:
virtual ~PasswordHash() = default;
virtual std::string to_string() const = 0;
/**
* Most password hashes have some notion of iterations.
*/
virtual size_t iterations() const = 0;
/**
* Some password hashing algorithms have a parameter which controls how
* much memory is used. If not supported by some algorithm, returns 0.
*/
virtual size_t memory_param() const { return 0; }
/**
* Some password hashing algorithms have a parallelism parameter.
* If the algorithm does not support this notion, then the
* function returns zero. This allows distinguishing between a
* password hash which just does not support parallel operation,
* vs one that does support parallel operation but which has been
* configured to use a single lane.
*/
virtual size_t parallelism() const { return 0; }
/**
* Returns an estimate of the total memory usage required to perform this
* key derivation.
*
* If this algorithm uses a small and constant amount of memory, with no
* effort made towards being memory hard, this function returns 0.
*/
virtual size_t total_memory_usage() const { return 0; }
/**
* Derive a key from a password
*
* @param out buffer to store the derived key, must be of out_len bytes
* @param out_len the desired length of the key to produce
* @param password the password to derive the key from
* @param password_len the length of password in bytes
* @param salt a randomly chosen salt
* @param salt_len length of salt in bytes
*
* This function is const, but is not thread safe. Different threads should
* either use unique objects, or serialize all access.
*/
virtual void derive_key(uint8_t out[], size_t out_len,
const char* password, size_t password_len,
const uint8_t salt[], size_t salt_len) const = 0;
};
class BOTAN_PUBLIC_API(2,8) PasswordHashFamily
{
public:
/**
* Create an instance based on a name
* If provider is empty then best available is chosen.
* @param algo_spec algorithm name
* @param provider provider implementation to choose
* @return a null pointer if the algo/provider combination cannot be found
*/
static std::unique_ptr<PasswordHashFamily> create(const std::string& algo_spec,
const std::string& provider = "");
/**
* Create an instance based on a name, or throw if the
* algo/provider combination cannot be found. If provider is
* empty then best available is chosen.
*/
static std::unique_ptr<PasswordHashFamily>
create_or_throw(const std::string& algo_spec,
const std::string& provider = "");
/**
* @return list of available providers for this algorithm, empty if not available
*/
static std::vector<std::string> providers(const std::string& algo_spec);
virtual ~PasswordHashFamily() = default;
/**
* @return name of this PasswordHash
*/
virtual std::string name() const = 0;
/**
* Return a new parameter set tuned for this machine
* @param output_length how long the output length will be
* @param msec the desired execution time in milliseconds
*
* @param max_memory_usage_mb some password hash functions can use a tunable
* amount of memory, in this case max_memory_usage limits the amount of RAM
* the returned parameters will require, in mebibytes (2**20 bytes). It may
* require some small amount above the request. Set to zero to place no
* limit at all.
*/
virtual std::unique_ptr<PasswordHash> tune(size_t output_length,
std::chrono::milliseconds msec,
size_t max_memory_usage_mb = 0) const = 0;
/**
* Return some default parameter set for this PBKDF that should be good
* enough for most users. The value returned may change over time as
* processing power and attacks improve.
*/
virtual std::unique_ptr<PasswordHash> default_params() const = 0;
/**
* Return a parameter chosen based on a rough approximation with the
* specified iteration count. The exact value this returns for a particular
* algorithm may change from over time. Think of it as an alternative to
* tune, where time is expressed in terms of PBKDF2 iterations rather than
* milliseconds.
*/
virtual std::unique_ptr<PasswordHash> from_iterations(size_t iterations) const = 0;
/**
* Create a password hash using some scheme specific format.
* Eg PBKDF2 and PGP-S2K set iterations in i1
* Scrypt uses N,r,p in i{1-3}
* Bcrypt-PBKDF just has iterations
* Argon2{i,d,id} would use iterations, memory, parallelism for i{1-3},
* and Argon2 type is part of the family.
*
* Values not needed should be set to 0
*/
virtual std::unique_ptr<PasswordHash> from_params(
size_t i1,
size_t i2 = 0,
size_t i3 = 0) const = 0;
};
}
#endif

View File

@@ -55,8 +55,9 @@ EMSA* get_emsa(const std::string& algo_spec)
#if defined(BOTAN_HAS_EMSA_PKCS1)
if(req.algo_name() == "EMSA_PKCS1" ||
req.algo_name() == "EMSA-PKCS1-v1_5" ||
req.algo_name() == "EMSA3")
req.algo_name() == "PKCS1v15" ||
req.algo_name() == "EMSA-PKCS1-v1_5" ||
req.algo_name() == "EMSA3")
{
if(req.arg_count() == 2 && req.arg(0) == "Raw")
{
@@ -80,25 +81,45 @@ EMSA* get_emsa(const std::string& algo_spec)
#endif
#if defined(BOTAN_HAS_EMSA_PSSR)
if(req.algo_name() == "PSSR" ||
req.algo_name() == "EMSA-PSS" ||
req.algo_name() == "PSS-MGF1" ||
req.algo_name() == "EMSA4" ||
if(req.algo_name() == "PSS_Raw" ||
req.algo_name() == "PSSR_Raw")
{
if(req.arg_count_between(1, 3))
if(req.arg_count_between(1, 3) && req.arg(1, "MGF1") == "MGF1")
{
if(req.arg(1, "MGF1") != "MGF1")
return nullptr; // not supported
if(auto h = HashFunction::create(req.arg(0)))
{
const size_t salt_size = req.arg_as_integer(2, h->output_length());
if(req.algo_name() == "PSSR_Raw")
if(req.arg_count() == 3)
{
const size_t salt_size = req.arg_as_integer(2, 0);
return new PSSR_Raw(h.release(), salt_size);
}
else
{
return new PSSR_Raw(h.release());
}
}
}
}
if(req.algo_name() == "PSS" ||
req.algo_name() == "PSSR" ||
req.algo_name() == "EMSA-PSS" ||
req.algo_name() == "PSS-MGF1" ||
req.algo_name() == "EMSA4")
{
if(req.arg_count_between(1, 3) && req.arg(1, "MGF1") == "MGF1")
{
if(auto h = HashFunction::create(req.arg(0)))
{
if(req.arg_count() == 3)
{
const size_t salt_size = req.arg_as_integer(2, 0);
return new PSSR(h.release(), salt_size);
}
else
{
return new PSSR(h.release());
}
}
}
}

View File

@@ -55,9 +55,10 @@ secure_vector<uint8_t> pss_encode(HashFunction& hash,
}
bool pss_verify(HashFunction& hash,
const secure_vector<uint8_t>& const_coded,
const secure_vector<uint8_t>& raw,
size_t key_bits)
const secure_vector<uint8_t>& pss_repr,
const secure_vector<uint8_t>& message_hash,
size_t key_bits,
size_t* out_salt_size)
{
const size_t HASH_SIZE = hash.output_length();
const size_t KEY_BYTES = (key_bits + 7) / 8;
@@ -65,16 +66,16 @@ bool pss_verify(HashFunction& hash,
if(key_bits < 8*HASH_SIZE + 9)
return false;
if(raw.size() != HASH_SIZE)
if(message_hash.size() != HASH_SIZE)
return false;
if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1)
if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
return false;
if(const_coded[const_coded.size()-1] != 0xBC)
if(pss_repr[pss_repr.size()-1] != 0xBC)
return false;
secure_vector<uint8_t> coded = const_coded;
secure_vector<uint8_t> coded = pss_repr;
if(coded.size() < KEY_BYTES)
{
secure_vector<uint8_t> temp(KEY_BYTES);
@@ -110,23 +111,32 @@ bool pss_verify(HashFunction& hash,
for(size_t j = 0; j != 8; ++j)
hash.update(0);
hash.update(raw);
hash.update(message_hash);
hash.update(&DB[salt_offset], salt_size);
secure_vector<uint8_t> H2 = hash.final();
const secure_vector<uint8_t> H2 = hash.final();
return constant_time_compare(H, H2.data(), HASH_SIZE);
const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE);
if(out_salt_size && ok)
*out_salt_size = salt_size;
return ok;
}
}
PSSR::PSSR(HashFunction* h) :
m_hash(h), m_SALT_SIZE(m_hash->output_length())
m_hash(h),
m_salt_size(m_hash->output_length()),
m_required_salt_len(false)
{
}
PSSR::PSSR(HashFunction* h, size_t salt_size) :
m_hash(h), m_SALT_SIZE(salt_size)
m_hash(h),
m_salt_size(salt_size),
m_required_salt_len(true)
{
}
@@ -150,7 +160,7 @@ secure_vector<uint8_t> PSSR::encoding_of(const secure_vector<uint8_t>& msg,
size_t output_bits,
RandomNumberGenerator& rng)
{
secure_vector<uint8_t> salt = rng.random_vec(m_SALT_SIZE);
const secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
return pss_encode(*m_hash, msg, salt, output_bits);
}
@@ -161,12 +171,23 @@ bool PSSR::verify(const secure_vector<uint8_t>& coded,
const secure_vector<uint8_t>& raw,
size_t key_bits)
{
return pss_verify(*m_hash, coded, raw, key_bits);
size_t salt_size = 0;
const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
if(m_required_salt_len && salt_size != m_salt_size)
return false;
return ok;
}
EMSA* PSSR::clone()
{
return new PSSR(m_hash->clone(), m_salt_size);
}
std::string PSSR::name() const
{
return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_SALT_SIZE) + ")";
return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
}
AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
@@ -193,7 +214,7 @@ AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
.start_cons(SEQUENCE)
.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).encode(hash_id).end_cons()
.start_cons(ASN1_Tag(1), CONTEXT_SPECIFIC).encode(mgf_id).end_cons()
.start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_SALT_SIZE).end_cons()
.start_cons(ASN1_Tag(2), CONTEXT_SPECIFIC).encode(m_salt_size).end_cons()
.start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
.end_cons();
@@ -201,12 +222,16 @@ AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
}
PSSR_Raw::PSSR_Raw(HashFunction* h) :
m_hash(h), m_SALT_SIZE(m_hash->output_length())
m_hash(h),
m_salt_size(m_hash->output_length()),
m_required_salt_len(false)
{
}
PSSR_Raw::PSSR_Raw(HashFunction* h, size_t salt_size) :
m_hash(h), m_SALT_SIZE(salt_size)
m_hash(h),
m_salt_size(salt_size),
m_required_salt_len(true)
{
}
@@ -236,7 +261,7 @@ secure_vector<uint8_t> PSSR_Raw::encoding_of(const secure_vector<uint8_t>& msg,
size_t output_bits,
RandomNumberGenerator& rng)
{
secure_vector<uint8_t> salt = rng.random_vec(m_SALT_SIZE);
secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
return pss_encode(*m_hash, msg, salt, output_bits);
}
@@ -247,12 +272,23 @@ bool PSSR_Raw::verify(const secure_vector<uint8_t>& coded,
const secure_vector<uint8_t>& raw,
size_t key_bits)
{
return pss_verify(*m_hash, coded, raw, key_bits);
size_t salt_size = 0;
const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
if(m_required_salt_len && salt_size != m_salt_size)
return false;
return ok;
}
EMSA* PSSR_Raw::clone()
{
return new PSSR_Raw(m_hash->clone(), m_salt_size);
}
std::string PSSR_Raw::name() const
{
return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_SALT_SIZE) + ")";
return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
}
}

View File

@@ -31,7 +31,7 @@ class BOTAN_PUBLIC_API(2,0) PSSR final : public EMSA
*/
PSSR(HashFunction* hash, size_t salt_size);
EMSA* clone() override { return new PSSR(m_hash->clone(), m_SALT_SIZE); }
EMSA* clone() override;
std::string name() const override;
@@ -51,7 +51,8 @@ class BOTAN_PUBLIC_API(2,0) PSSR final : public EMSA
size_t key_bits) override;
std::unique_ptr<HashFunction> m_hash;
size_t m_SALT_SIZE;
size_t m_salt_size;
bool m_required_salt_len;
};
/**
@@ -73,7 +74,7 @@ class BOTAN_PUBLIC_API(2,3) PSSR_Raw final : public EMSA
*/
PSSR_Raw(HashFunction* hash, size_t salt_size);
EMSA* clone() override { return new PSSR_Raw(m_hash->clone(), m_SALT_SIZE); }
EMSA* clone() override;
std::string name() const override;
private:
@@ -90,8 +91,9 @@ class BOTAN_PUBLIC_API(2,3) PSSR_Raw final : public EMSA
size_t key_bits) override;
std::unique_ptr<HashFunction> m_hash;
size_t m_SALT_SIZE;
secure_vector<uint8_t> m_msg;
size_t m_salt_size;
bool m_required_salt_len;
};
}

View File

@@ -2,8 +2,6 @@
PK_PADDING -> 20131128
</defines>
load_on auto
<requires>
asn1
rng

View File

@@ -17,13 +17,14 @@ void mgf1_mask(HashFunction& hash,
{
uint32_t counter = 0;
secure_vector<uint8_t> buffer(hash.output_length());
while(out_len)
{
hash.update(in, in_len);
hash.update_be(counter);
secure_vector<uint8_t> buffer = hash.final();
hash.final(buffer.data());
size_t xored = std::min<size_t>(buffer.size(), out_len);
const size_t xored = std::min<size_t>(buffer.size(), out_len);
xor_buf(out, buffer.data(), xored);
out += xored;
out_len -= xored;

View File

@@ -93,6 +93,8 @@ class DH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF
[this](const BigInt& k) { return m_powermod_x_p(inverse_mod(k, m_p)); })
{}
size_t agreed_value_size() const override { return m_p.bytes(); }
secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override;
private:
const BigInt& m_p;

View File

@@ -67,6 +67,7 @@ class DL_Group_Data final
size_t p_bits() const { return m_p_bits; }
size_t q_bits() const { return m_q_bits; }
size_t p_bytes() const { return (m_p_bits + 7) / 8; }
size_t q_bytes() const { return (m_q_bits + 7) / 8; }
size_t estimated_strength() const { return m_estimated_strength; }
@@ -448,6 +449,12 @@ size_t DL_Group::q_bits() const
return data().q_bits();
}
size_t DL_Group::q_bytes() const
{
data().assert_q_is_set("q_bytes");
return data().q_bytes();
}
size_t DL_Group::estimated_strength() const
{
return data().estimated_strength();

View File

@@ -268,6 +268,13 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
*/
size_t q_bits() const;
/**
* Return the size of q in bytes
* Same as get_q().bytes()
* Throws if q is unset
*/
size_t q_bytes() const;
/**
* Return size in bits of a secret exponent
*

View File

@@ -89,7 +89,8 @@ class DSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA
m_b_inv = m_group.inverse_mod_q(m_b);
}
size_t max_input_bits() const override { return m_group.get_q().bits(); }
size_t signature_length() const override { return 2*m_group.q_bytes(); }
size_t max_input_bits() const override { return m_group.q_bits(); }
secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
RandomNumberGenerator& rng) override;
@@ -157,7 +158,7 @@ class DSA_Verification_Operation final : public PK_Ops::Verification_with_EMSA
{
}
size_t max_input_bits() const override { return m_group.get_q().bits(); }
size_t max_input_bits() const override { return m_group.q_bits(); }
bool with_recovery() const override { return false; }

View File

@@ -10,6 +10,7 @@
#include <botan/ec_group.h>
#include <botan/internal/point_mul.h>
#include <botan/internal/primality.h>
#include <botan/ber_dec.h>
#include <botan/der_enc.h>
#include <botan/oids.h>
@@ -19,12 +20,6 @@
#include <botan/rng.h>
#include <vector>
#if defined(BOTAN_HAS_SYSTEM_RNG)
#include <botan/system_rng.h>
#elif defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32)
#include <botan/hmac_drbg.h>
#endif
namespace Botan {
class EC_Group_Data final
@@ -318,23 +313,7 @@ std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[
.end_cons()
.verify_end();
#if defined(BOTAN_HAS_SYSTEM_RNG)
System_RNG rng;
#elif defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32)
/*
* This is not ideal because the data is attacker controlled, but
* it seems like it would be difficult for someone to come up
* with an valid ASN.1 encoding where the prime happened to pass
* Miller-Rabin test with exactly the values chosen when
* HMAC_DRBG is seeded with the overall data.
*/
HMAC_DRBG rng("SHA-256");
rng.add_entropy(bits, len);
#else
Null_RNG rng;
#endif
if(p.bits() < 64 || p.is_negative() || (is_prime(p, rng) == false))
if(p.bits() < 64 || p.is_negative() || !is_bailie_psw_probable_prime(p))
throw Decoding_Error("Invalid ECC p parameter");
if(a.is_negative() || a >= p)
@@ -343,7 +322,7 @@ std::shared_ptr<EC_Group_Data> EC_Group::BER_decode_EC_group(const uint8_t bits[
if(b <= 0 || b >= p)
throw Decoding_Error("Invalid ECC b parameter");
if(order <= 0)
if(order <= 0 || !is_bailie_psw_probable_prime(order))
throw Decoding_Error("Invalid ECC order parameter");
if(cofactor <= 0 || cofactor >= 16)
@@ -547,6 +526,15 @@ const OID& EC_Group::get_curve_oid() const
return data().oid();
}
size_t EC_Group::point_size(PointGFp::Compression_Type format) const
{
// Hybrid and standard format are (x,y), compressed is y, +1 format byte
if(format == PointGFp::COMPRESSED)
return (1 + get_p_bytes());
else
return (1 + 2*get_p_bytes());
}
PointGFp EC_Group::OS2ECP(const uint8_t bits[], size_t len) const
{
return Botan::OS2ECP(bits, len, data().curve());

View File

@@ -302,6 +302,8 @@ class BOTAN_PUBLIC_API(2,0) EC_Group final
*/
PointGFp zero_point() const;
size_t point_size(PointGFp::Compression_Type format) const;
PointGFp OS2ECP(const uint8_t bits[], size_t len) const;
template<typename Alloc>

View File

@@ -170,7 +170,7 @@ PointGFp_Var_Point_Precompute::PointGFp_Var_Point_Precompute(const PointGFp& poi
if(ws.size() < PointGFp::WORKSPACE_SIZE)
ws.resize(PointGFp::WORKSPACE_SIZE);
std::vector<PointGFp> U(1U << m_window_bits);
std::vector<PointGFp> U(static_cast<size_t>(1) << m_window_bits);
U[0] = point.zero();
U[1] = point;
@@ -354,10 +354,10 @@ PointGFp PointGFp_Multi_Point_Precompute::multi_exp(const BigInt& z1,
H.mult2i(2, ws);
}
const uint8_t z1_b = z1.get_substring(z_bits - i - 2, 2);
const uint8_t z2_b = z2.get_substring(z_bits - i - 2, 2);
const uint32_t z1_b = z1.get_substring(z_bits - i - 2, 2);
const uint32_t z2_b = z2.get_substring(z_bits - i - 2, 2);
const uint8_t z12 = (4*z2_b) + z1_b;
const uint32_t z12 = (4*z2_b) + z1_b;
// This function is not intended to be const time
if(z12)

View File

@@ -147,8 +147,10 @@ secure_vector<uint8_t> EC_PrivateKey::private_key_bits() const
return DER_Encoder()
.start_cons(SEQUENCE)
.encode(static_cast<size_t>(1))
.encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()),
OCTET_STRING)
.encode(BigInt::encode_1363(m_private_key, m_private_key.bytes()), OCTET_STRING)
.start_cons(ASN1_Tag(1), PRIVATE)
.encode(m_public_key.encode(PointGFp::Compression_Type::UNCOMPRESSED), BIT_STRING)
.end_cons()
.end_cons()
.get_contents();
}

View File

@@ -34,6 +34,8 @@ class ECDH_KA_Operation final : public PK_Ops::Key_Agreement_with_KDF
m_l_times_priv = m_group.inverse_mod_order(m_group.get_cofactor()) * key.private_value();
}
size_t agreed_value_size() const override { return m_group.get_p_bytes(); }
secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override
{
PointGFp input_point = m_group.get_cofactor() * m_group.OS2ECP(w, w_len);

View File

@@ -65,6 +65,8 @@ class ECDSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA
m_b_inv = m_group.inverse_mod_order(m_b);
}
size_t signature_length() const override { return 2*m_group.get_order_bytes(); }
size_t max_input_bits() const override { return m_group.get_order_bits(); }
secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
@@ -106,10 +108,10 @@ ECDSA_Signature_Operation::raw_sign(const uint8_t msg[], size_t msg_len,
m_b = m_group.square_mod_order(m_b);
m_b_inv = m_group.square_mod_order(m_b_inv);
m = m_group.multiply_mod_order(m_b, m);
const BigInt xr = m_group.multiply_mod_order(m_x, m_b, r);
m = m_group.multiply_mod_order(m_b, m_group.mod_order(m));
const BigInt xr_m = m_group.mod_order(m_group.multiply_mod_order(m_x, m_b, r) + m);
const BigInt s = m_group.multiply_mod_order(k_inv, xr + m, m_b_inv);
const BigInt s = m_group.multiply_mod_order(k_inv, xr_m, m_b_inv);
// With overwhelming probability, a bug rather than actual zero r/s
if(r.is_zero() || s.is_zero())

View File

@@ -1,6 +1,7 @@
/*
* PKCS #5 PBES2
* (C) 1999-2008,2014 Jack Lloyd
* (C) 2018 Ribose Inc
*
* Botan is released under the Simplified BSD License (see license.txt)
*/
@@ -23,6 +24,11 @@ namespace Botan {
namespace {
bool known_pbes_cipher_mode(const std::string& mode)
{
return (mode == "CBC" || mode == "GCM" || mode == "SIV");
}
SymmetricKey derive_key(const std::string& passphrase,
const AlgorithmIdentifier& kdf_algo,
size_t default_key_size)
@@ -46,13 +52,11 @@ SymmetricKey derive_key(const std::string& passphrase,
if(salt.size() < 8)
throw Decoding_Error("PBE-PKCS5 v2.0: Encoded salt is too small");
const std::string prf = OIDS::lookup(prf_algo.get_oid());
std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
if(key_length == 0)
key_length = default_key_size;
const std::string prf = OIDS::lookup(prf_algo.get_oid());
std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
return pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations);
}
#if defined(BOTAN_HAS_SCRYPT)
@@ -101,24 +105,39 @@ secure_vector<uint8_t> derive_key(const std::string& passphrase,
{
#if defined(BOTAN_HAS_SCRYPT)
Scrypt_Params params(32768, 8, 4);
std::unique_ptr<PasswordHashFamily> pwhash_fam = PasswordHashFamily::create_or_throw("Scrypt");
std::unique_ptr<PasswordHash> pwhash;
if(msec_in_iterations_out)
params = Scrypt_Params(std::chrono::milliseconds(*msec_in_iterations_out));
{
const std::chrono::milliseconds msec(*msec_in_iterations_out);
pwhash = pwhash_fam->tune(key_length, msec);
}
else
params = Scrypt_Params(iterations_if_msec_null);
{
pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
}
secure_vector<uint8_t> key(key_length);
scrypt(key.data(), key.size(), passphrase,
salt.data(), salt.size(), params);
pwhash->derive_key(key.data(), key.size(),
passphrase.c_str(), passphrase.size(),
salt.data(), salt.size());
const size_t N = pwhash->memory_param();
const size_t r = pwhash->iterations();
const size_t p = pwhash->parallelism();
if(msec_in_iterations_out)
*msec_in_iterations_out = 0;
std::vector<uint8_t> scrypt_params;
DER_Encoder(scrypt_params)
.start_cons(SEQUENCE)
.encode(salt, OCTET_STRING)
.encode(params.N())
.encode(params.r())
.encode(params.p())
.encode(N)
.encode(r)
.encode(p)
.encode(key_length)
.end_cons();
@@ -131,26 +150,36 @@ secure_vector<uint8_t> derive_key(const std::string& passphrase,
else
{
const std::string prf = "HMAC(" + digest + ")";
const std::string pbkdf_name = "PBKDF2(" + prf + ")";
std::unique_ptr<PBKDF> pbkdf(get_pbkdf("PBKDF2(" + prf + ")"));
std::unique_ptr<PasswordHashFamily> pwhash_fam = PasswordHashFamily::create(pbkdf_name);
if(!pwhash_fam)
throw Invalid_Argument("Unknown password hash digest " + digest);
size_t iterations = iterations_if_msec_null;
secure_vector<uint8_t> key;
std::unique_ptr<PasswordHash> pwhash;
if(msec_in_iterations_out)
{
std::chrono::milliseconds msec(*msec_in_iterations_out);
key = pbkdf->derive_key(key_length, passphrase, salt.data(), salt.size(), msec, iterations).bits_of();
*msec_in_iterations_out = iterations;
const std::chrono::milliseconds msec(*msec_in_iterations_out);
pwhash = pwhash_fam->tune(key_length, msec);
}
else
{
key = pbkdf->pbkdf_iterations(key_length, passphrase, salt.data(), salt.size(), iterations);
pwhash = pwhash_fam->from_iterations(iterations_if_msec_null);
}
secure_vector<uint8_t> key(key_length);
pwhash->derive_key(key.data(), key.size(),
passphrase.c_str(), passphrase.size(),
salt.data(), salt.size());
std::vector<uint8_t> pbkdf2_params;
const size_t iterations = pwhash->iterations();
if(msec_in_iterations_out)
*msec_in_iterations_out = iterations;
DER_Encoder(pbkdf2_params)
.start_cons(SEQUENCE)
.encode(salt, OCTET_STRING)
@@ -181,7 +210,7 @@ pbes2_encrypt_shared(const secure_vector<uint8_t>& key_bits,
if(cipher_spec.size() != 2)
throw Encoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
if(!known_pbes_cipher_mode(cipher_spec[1]))
throw Encoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
const OID cipher_oid = OIDS::lookup(cipher);
@@ -289,7 +318,7 @@ pbes2_decrypt(const secure_vector<uint8_t>& key_bits,
const std::vector<std::string> cipher_spec = split_on(cipher, '/');
if(cipher_spec.size() != 2)
throw Decoding_Error("PBE-PKCS5 v2.0: Invalid cipher spec " + cipher);
if(cipher_spec[1] != "CBC" && cipher_spec[1] != "GCM")
if(!known_pbes_cipher_mode(cipher_spec[1]))
throw Decoding_Error("PBE-PKCS5 v2.0: Don't know param format for " + cipher);
secure_vector<uint8_t> iv;

View File

@@ -71,7 +71,6 @@
#if defined(BOTAN_HAS_SM2)
#include <botan/sm2.h>
#include <botan/sm2_enc.h>
#endif
#if defined(BOTAN_HAS_OPENSSL)
@@ -152,10 +151,8 @@ load_public_key(const AlgorithmIdentifier& alg_id,
#endif
#if defined(BOTAN_HAS_SM2)
if(alg_name == "SM2_Sig")
return std::unique_ptr<Public_Key>(new SM2_Signature_PublicKey(alg_id, key_bits));
if(alg_name == "SM2_Enc")
return std::unique_ptr<Public_Key>(new SM2_Encryption_PublicKey(alg_id, key_bits));
if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc")
return std::unique_ptr<Public_Key>(new SM2_PublicKey(alg_id, key_bits));
#endif
#if defined(BOTAN_HAS_XMSS)
@@ -230,10 +227,8 @@ load_private_key(const AlgorithmIdentifier& alg_id,
#endif
#if defined(BOTAN_HAS_SM2)
if(alg_name == "SM2_Sig")
return std::unique_ptr<Private_Key>(new SM2_Signature_PrivateKey(alg_id, key_bits));
if(alg_name == "SM2_Enc")
return std::unique_ptr<Private_Key>(new SM2_Encryption_PrivateKey(alg_id, key_bits));
if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc")
return std::unique_ptr<Private_Key>(new SM2_PrivateKey(alg_id, key_bits));
#endif
#if defined(BOTAN_HAS_ELGAMAL)
@@ -255,7 +250,7 @@ namespace {
std::string default_ec_group_for(const std::string& alg_name)
{
if(alg_name == "SM2_Enc" || alg_name == "SM2_Sig")
if(alg_name == "SM2" || alg_name == "SM2_Enc" || alg_name == "SM2_Sig")
return "sm2p256v1";
if(alg_name == "GOST-34.10")
return "gost_256A";
@@ -341,6 +336,7 @@ create_private_key(const std::string& alg_name,
alg_name == "ECDH" ||
alg_name == "ECKCDSA" ||
alg_name == "ECGDSA" ||
alg_name == "SM2" ||
alg_name == "SM2_Sig" ||
alg_name == "SM2_Enc" ||
alg_name == "GOST-34.10")
@@ -368,10 +364,8 @@ create_private_key(const std::string& alg_name,
#endif
#if defined(BOTAN_HAS_SM2)
if(alg_name == "SM2_Sig")
return std::unique_ptr<Private_Key>(new SM2_Signature_PrivateKey(rng, ec_group));
if(alg_name == "SM2_Enc")
return std::unique_ptr<Private_Key>(new SM2_Encryption_PrivateKey(rng, ec_group));
if(alg_name == "SM2" || alg_name == "SM2_Sig" || alg_name == "SM2_Enc")
return std::unique_ptr<Private_Key>(new SM2_PrivateKey(rng, ec_group));
#endif
#if defined(BOTAN_HAS_ECGDSA)

View File

@@ -42,6 +42,8 @@ class BOTAN_PUBLIC_API(2,0) Encryption
virtual size_t max_input_bits() const = 0;
virtual size_t ciphertext_length(size_t ptext_len) const = 0;
virtual ~Encryption() = default;
};
@@ -55,6 +57,8 @@ class BOTAN_PUBLIC_API(2,0) Decryption
const uint8_t ciphertext[],
size_t ciphertext_len) = 0;
virtual size_t plaintext_length(size_t ctext_len) const = 0;
virtual ~Decryption() = default;
};
@@ -99,6 +103,11 @@ class BOTAN_PUBLIC_API(2,0) Signature
*/
virtual secure_vector<uint8_t> sign(RandomNumberGenerator& rng) = 0;
/*
* Return an upper bound on the length of the output signature
*/
virtual size_t signature_length() const = 0;
virtual ~Signature() = default;
};
@@ -109,8 +118,10 @@ class BOTAN_PUBLIC_API(2,0) Key_Agreement
{
public:
virtual secure_vector<uint8_t> agree(size_t key_len,
const uint8_t other_key[], size_t other_key_len,
const uint8_t salt[], size_t salt_len) = 0;
const uint8_t other_key[], size_t other_key_len,
const uint8_t salt[], size_t salt_len) = 0;
virtual size_t agreed_value_size() const = 0;
virtual ~Key_Agreement() = default;
};

View File

@@ -97,7 +97,7 @@ secure_vector<uint8_t> PKCS8_decode(
}
catch(Decoding_Error& e)
{
throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
throw Decoding_Error("PKCS #8 private key decoding", e);
}
try
@@ -126,7 +126,7 @@ secure_vector<uint8_t> PKCS8_decode(
}
catch(std::exception& e)
{
throw Decoding_Error("PKCS #8 private key decoding failed: " + std::string(e.what()));
throw Decoding_Error("PKCS #8 private key decoding", e);
}
return key;
}
@@ -167,7 +167,9 @@ choose_pbe_params(const std::string& pbe_algo, const std::string& key_algo)
}
SCAN_Name request(pbe_algo);
if(request.algo_name() != "PBE-PKCS5v20" || request.arg_count() != 2)
if(request.arg_count() != 2)
throw Exception("Unsupported PBE " + pbe_algo);
if(request.algo_name() != "PBE-PKCS5v20" && request.algo_name() != "PBES2")
throw Exception("Unsupported PBE " + pbe_algo);
return std::make_pair(request.arg(0), request.arg(1));
}

View File

@@ -180,7 +180,7 @@ PEM_encode_encrypted_pbkdf_msec(const Private_Key& key,
/**
* Load an encrypted key from a data source.
* @param source the data source providing the encoded key
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @param get_passphrase a function that returns passphrases
* @return loaded private key object
*/
@@ -190,7 +190,7 @@ BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source,
/** Load an encrypted key from a data source.
* @param source the data source providing the encoded key
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @param pass the passphrase to decrypt the key
* @return loaded private key object
*/
@@ -200,7 +200,7 @@ BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source,
/** Load an unencrypted key from a data source.
* @param source the data source providing the encoded key
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @return loaded private key object
*/
BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source,
@@ -210,7 +210,7 @@ BOTAN_PUBLIC_API(2,0) Private_Key* load_key(DataSource& source,
/**
* Load an encrypted key from a file.
* @param filename the path to the file containing the encoded key
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @param get_passphrase a function that returns passphrases
* @return loaded private key object
*/
@@ -220,7 +220,7 @@ BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename,
/** Load an encrypted key from a file.
* @param filename the path to the file containing the encoded key
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @param pass the passphrase to decrypt the key
* @return loaded private key object
*/
@@ -230,7 +230,7 @@ BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename,
/** Load an unencrypted key from a file.
* @param filename the path to the file containing the encoded key
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @return loaded private key object
*/
BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename,
@@ -240,7 +240,7 @@ BOTAN_PUBLIC_API(2,0) Private_Key* load_key(const std::string& filename,
/**
* Copy an existing encoded key object.
* @param key the key to copy
* @param rng ignored for compatability
* @param rng ignored for compatibility
* @return new copy of the key
*/
BOTAN_PUBLIC_API(2,0) Private_Key* copy_key(const Private_Key& key,

View File

@@ -96,6 +96,11 @@ PK_Encryptor_EME::PK_Encryptor_EME(const Public_Key& key,
PK_Encryptor_EME::~PK_Encryptor_EME() { /* for unique_ptr */ }
size_t PK_Encryptor_EME::ciphertext_length(size_t ptext_len) const
{
return m_op->ciphertext_length(ptext_len);
}
std::vector<uint8_t>
PK_Encryptor_EME::enc(const uint8_t in[], size_t length, RandomNumberGenerator& rng) const
{
@@ -119,6 +124,11 @@ PK_Decryptor_EME::PK_Decryptor_EME(const Private_Key& key,
PK_Decryptor_EME::~PK_Decryptor_EME() { /* for unique_ptr */ }
size_t PK_Decryptor_EME::plaintext_length(size_t ctext_len) const
{
return m_op->plaintext_length(ctext_len);
}
secure_vector<uint8_t> PK_Decryptor_EME::do_decrypt(uint8_t& valid_mask,
const uint8_t in[], size_t in_len) const
{
@@ -200,6 +210,11 @@ PK_Key_Agreement::PK_Key_Agreement(PK_Key_Agreement&& other) :
m_op(std::move(other.m_op))
{}
size_t PK_Key_Agreement::agreed_value_size() const
{
return m_op->agreed_value_size();
}
SymmetricKey PK_Key_Agreement::derive_key(size_t key_len,
const uint8_t in[], size_t in_len,
const uint8_t salt[],
@@ -252,6 +267,22 @@ std::vector<uint8_t> der_encode_signature(const std::vector<uint8_t>& sig,
}
size_t PK_Signer::signature_length() const
{
if(m_sig_format == IEEE_1363)
{
return m_op->signature_length();
}
else if(m_sig_format == DER_SEQUENCE)
{
// This is a large over-estimate but its easier than computing
// the exact value
return m_op->signature_length() + (8 + 4*m_parts);
}
else
throw Internal_Error("PK_Signer: Invalid signature format enum");
}
std::vector<uint8_t> PK_Signer::signature(RandomNumberGenerator& rng)
{
const std::vector<uint8_t> sig = unlock(m_op->sign(rng));

View File

@@ -66,6 +66,11 @@ class BOTAN_PUBLIC_API(2,0) PK_Encryptor
*/
virtual size_t maximum_input_size() const = 0;
/**
* Return an upper bound on the ciphertext length
*/
virtual size_t ciphertext_length(size_t ctext_len) const = 0;
PK_Encryptor() = default;
virtual ~PK_Encryptor() = default;
@@ -140,6 +145,12 @@ class BOTAN_PUBLIC_API(2,0) PK_Decryptor
const uint8_t required_content_offsets[],
size_t required_contents) const;
/**
* Return an upper bound on the plaintext length for a particular
* ciphertext input length
*/
virtual size_t plaintext_length(size_t ctext_len) const = 0;
PK_Decryptor() = default;
virtual ~PK_Decryptor() = default;
@@ -217,19 +228,12 @@ class BOTAN_PUBLIC_API(2,0) PK_Signer final
* @param rng the rng to use
* @return signature
*/
std::vector<uint8_t> sign_message(const std::vector<uint8_t>& in,
RandomNumberGenerator& rng)
{ return sign_message(in.data(), in.size(), rng); }
/**
* Sign a message.
* @param in the message to sign
* @param rng the rng to use
* @return signature
*/
std::vector<uint8_t> sign_message(const secure_vector<uint8_t>& in,
RandomNumberGenerator& rng)
{ return sign_message(in.data(), in.size(), rng); }
template<typename Alloc>
std::vector<uint8_t> sign_message(const std::vector<uint8_t, Alloc>& in,
RandomNumberGenerator& rng)
{
return sign_message(in.data(), in.size(), rng);
}
/**
* Add a message part (single byte).
@@ -248,7 +252,11 @@ class BOTAN_PUBLIC_API(2,0) PK_Signer final
* Add a message part.
* @param in the message part to add
*/
void update(const std::vector<uint8_t>& in) { update(in.data(), in.size()); }
template<typename Alloc>
void update(const std::vector<uint8_t, Alloc>& in)
{
update(in.data(), in.size());
}
/**
* Add a message part.
@@ -267,11 +275,19 @@ class BOTAN_PUBLIC_API(2,0) PK_Signer final
*/
std::vector<uint8_t> signature(RandomNumberGenerator& rng);
/**
* Set the output format of the signature.
* @param format the signature format to use
*/
void set_output_format(Signature_Format format) { m_sig_format = format; }
/**
* Return an upper bound on the length of the signatures this
* PK_Signer will produce
*/
size_t signature_length() const;
private:
std::unique_ptr<PK_Ops::Signature> m_op;
Signature_Format m_sig_format;
@@ -347,8 +363,11 @@ class BOTAN_PUBLIC_API(2,0) PK_Verifier final
* signature to be verified.
* @param in the new message part
*/
void update(const std::vector<uint8_t>& in)
{ update(in.data(), in.size()); }
template<typename Alloc>
void update(const std::vector<uint8_t, Alloc>& in)
{
update(in.data(), in.size());
}
/**
* Add a message part of the message corresponding to the
@@ -393,7 +412,7 @@ class BOTAN_PUBLIC_API(2,0) PK_Verifier final
};
/**
* Key used for key agreement
* Object used for key agreement
*/
class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final
{
@@ -435,7 +454,7 @@ class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final
PK_Key_Agreement& operator=(const PK_Key_Agreement&) = delete;
PK_Key_Agreement(const PK_Key_Agreement&) = delete;
/*
/**
* Perform Key Agreement Operation
* @param key_len the desired key output size
* @param in the other parties key
@@ -449,11 +468,10 @@ class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final
const uint8_t params[],
size_t params_len) const;
/*
/**
* Perform Key Agreement Operation
* @param key_len the desired key output size
* @param in the other parties key
* @param in_len the length of in in bytes
* @param params extra derivation params
* @param params_len the length of params in bytes
*/
@@ -466,7 +484,7 @@ class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final
params, params_len);
}
/*
/**
* Perform Key Agreement Operation
* @param key_len the desired key output size
* @param in the other parties key
@@ -482,7 +500,7 @@ class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final
params.length());
}
/*
/**
* Perform Key Agreement Operation
* @param key_len the desired key output size
* @param in the other parties key
@@ -497,6 +515,13 @@ class BOTAN_PUBLIC_API(2,0) PK_Key_Agreement final
params.length());
}
/**
* Return the underlying size of the value that is agreed.
* If derive_key is called with a length of 0 with a "Raw"
* KDF, it will return a value of this size.
*/
size_t agreed_value_size() const;
private:
std::unique_ptr<PK_Ops::Key_Agreement> m_op;
};
@@ -539,6 +564,12 @@ class BOTAN_PUBLIC_API(2,0) PK_Encryptor_EME final : public PK_Encryptor
PK_Encryptor_EME& operator=(const PK_Encryptor_EME&) = delete;
PK_Encryptor_EME(const PK_Encryptor_EME&) = delete;
/**
* Return an upper bound on the ciphertext length for a particular
* plaintext input length
*/
size_t ciphertext_length(size_t ptext_len) const override;
private:
std::vector<uint8_t> enc(const uint8_t[], size_t,
RandomNumberGenerator& rng) const override;
@@ -578,6 +609,8 @@ class BOTAN_PUBLIC_API(2,0) PK_Decryptor_EME final : public PK_Decryptor
PK_Decryptor_EME(key, system_rng(), eme, provider) {}
#endif
size_t plaintext_length(size_t ptext_len) const override;
~PK_Decryptor_EME();
PK_Decryptor_EME& operator=(const PK_Decryptor_EME&) = delete;
PK_Decryptor_EME(const PK_Decryptor_EME&) = delete;

View File

@@ -298,6 +298,8 @@ class RSA_Signature_Operation final : public PK_Ops::Signature_with_EMSA,
size_t max_input_bits() const override { return get_max_input_bits(); }
size_t signature_length() const override { return m_key.get_n().bytes(); }
RSA_Signature_Operation(const RSA_PrivateKey& rsa, const std::string& emsa, RandomNumberGenerator& rng) :
PK_Ops::Signature_with_EMSA(emsa),
RSA_Private_Operation(rsa, rng)
@@ -326,6 +328,8 @@ class RSA_Decryption_Operation final : public PK_Ops::Decryption_with_EME,
{
}
size_t plaintext_length(size_t) const override { return m_mod_bytes; }
secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override
{
const BigInt m(msg, msg_len);
@@ -403,6 +407,8 @@ class RSA_Encryption_Operation final : public PK_Ops::Encryption_with_EME,
{
}
size_t ciphertext_length(size_t) const override { return m_n.bytes(); }
size_t max_raw_input_bits() const override { return get_max_input_bits(); }
secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t msg_len,

View File

@@ -62,13 +62,13 @@ Public_Key* load_key(DataSource& source)
}
if(key_bits.empty())
throw Decoding_Error("X.509 public key decoding failed");
throw Decoding_Error("X.509 public key decoding");
return load_public_key(alg_id, key_bits).release();
}
catch(Decoding_Error& e)
{
throw Decoding_Error("X.509 public key decoding failed: " + std::string(e.what()));
throw Decoding_Error("X.509 public key decoding", e);
}
}

View File

@@ -100,7 +100,7 @@ size_t AutoSeeded_RNG::reseed(Entropy_Sources& srcs,
void AutoSeeded_RNG::randomize(uint8_t output[], size_t output_len)
{
randomize_with_ts_input(output, output_len);
m_rng->randomize_with_ts_input(output, output_len);
}
void AutoSeeded_RNG::randomize_with_input(uint8_t output[], size_t output_len,

Some files were not shown because too many files have changed in this diff Show More