Merge remote-tracking branch 'origin/4.8' into master

Change-Id: I6ecd3732a147960681c6135e8752cbd046bad65b
This commit is contained in:
Orgad Shaneh
2018-10-12 17:21:14 +03:00
185 changed files with 4302 additions and 1493 deletions

View File

@@ -37,7 +37,8 @@
\title Connecting Android Devices
You can connect Android devices to the development PC to run, debug,
and analyze applications built for them from \QC.
and analyze applications built for them from \QC. Devices with Android
version 4.1 (API level 16) or later are supported.
If you have a tool chain for building applications for Android devices
installed on the development PC, you can add it to \QC. You can then add a
@@ -59,7 +60,10 @@
\list
\li \l{http://www.oracle.com/technetwork/java/javase/downloads/index.html}
{Java SE Development Kit (JDK)} version 6, or later
{Java SE Development Kit (JDK)} version 6, or later.
You can also use \l{http://openjdk.java.net/}{OpenJDK} on Linux.
\note Android SDK Tools have issues with JDK versions later than 8.
\li \l{http://www.gradle.org}{Gradle} for building application packages
for Android devices (APK). Gradle is delivered with Qt 5.9, and
@@ -71,7 +75,7 @@
\li A tool chain for building applications for Android devices provided
by the \l{http://developer.android.com/tools/sdk/ndk/index.html}
{Android NDK} from Google.
{Android NDK} from Google. The recommended version is 10e.
\li \l{http://developer.android.com/sdk/index.html}{Android SDK Tools}
@@ -106,9 +110,12 @@
\section1 Setting Up the Development Environment
You must download and install the latest Android NDK and SDK, and then
update or install the tools and packages needed for development. The SDK
tool used to update and install the other SDK tools and packages depends on
the Android SDK Tools version that you have installed:
update or install the tools and packages needed for development. However,
if your Qt version is earlier than v5.9, use the SDK tools package v25.2.5
or earlier.
The SDK tool used to update and install the other SDK tools and packages
depends on the Android SDK Tools version that you have installed:
\list
@@ -135,6 +142,10 @@
In addition, you must install Qt for Android as part of Qt 5.2, or later.
\note You can build a 64-bit version of Qt for Android yourself. However,
for such a Qt version, the minimum required Android version on devices
is 5.0 (API level 21).
For more information, see \l{Qt for Android}.
\section2 Specifying Android Device Settings
@@ -287,22 +298,11 @@
\section1 Debugging on Android Devices
Android devices support debugging multi-thread applications in version
2.2.1 and later. If you use AVD, select Android 2.3, or later. For more
information, see the Android documentation.
In addition, debugging is supported at android-10 API level, or higher. In
the run settings for the project, in the \uicontrol {Android build SDK} field,
select android-10, or higher. For more information about Android API levels,
see \l{http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels}
{What is API Level?}.
\note Select a \l{glossary-build-config}{debug build configuration} to build
Select a \l{glossary-build-config}{debug build configuration} to build
the application for debugging.
\note \QC cannot debug applications on Android devices if Android Studio is
running. If the following message is displayed in the \uicontrol Output
pane, close Android Studio and try again: \e {Ignoring second debugger -
accepting and dropping.}
*/

View File

@@ -60,7 +60,7 @@
first-letter case-sensitivity, select \uicontrol Full or
\uicontrol {First Letter} in the \uicontrol {Case-sensitivity} field.
\section2 Summary of Available Types
\section1 Summary of Available Types
The following table lists available types for code completion and icon used
for each.
@@ -132,7 +132,7 @@
\endif
\endtable
\section2 Completing Code Snippets
\section1 Completing Code Snippets
Code snippets can consist of multiple variables that you specify values for.
Select an item in the list and press \key Tab or \key Enter to complete the
@@ -189,7 +189,7 @@
\endlist
\section3 Adding and Editing Snippets
\section2 Adding and Editing Snippets
Select a snippet in the list to edit it in the snippet editor. To add a new
snippet, select \uicontrol Add. Specify a trigger and, if the trigger is
@@ -268,7 +268,7 @@
To discard the changes you made to a built-in snippet, select
\uicontrol {Revert Built-in}.
\section3 Removing Snippets
\section2 Removing Snippets
Several similar built-in snippets might be provided for different use cases.
To make the list of suggestions shorter when you write code, remove the
@@ -279,7 +279,7 @@
\uicontrol Remove. To restore the removed snippets, select
\uicontrol {Restore Removed Built-ins}.
\section3 Resetting Snippets
\section2 Resetting Snippets
To remove all added snippets and to restore all removed snippets, select
\uicontrol {Reset All}.

View File

@@ -56,8 +56,9 @@
This is totally transparent to users. As Qt is composed of libraries
referencing each other, Qt 4 applications are only supported on
Android version 1.6, or later, and Qt 5 applications on version
2.3.3, or later. You must install a Qt version targeting Android and
the Android SDK and NDK to develop for Android devices.
4.1 (API level 16), or later. You must install a Qt version
targeting Android and the Android SDK and NDK to develop for
Android devices.
\if defined(qtcreator)
\li \l{Connecting Bare Metal Devices}

View File

@@ -4,16 +4,16 @@ import qbs.FileInfo
import "qtc.js" as HelperFunctions
Module {
property string qtcreator_display_version: '4.8.0-beta1'
property string qtcreator_display_version: '4.8.0-beta2'
property string ide_version_major: '4'
property string ide_version_minor: '7'
property string ide_version_release: '82'
property string ide_version_release: '83'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release
property string ide_compat_version_major: '4'
property string ide_compat_version_minor: '7'
property string ide_compat_version_release: '82'
property string ide_compat_version_release: '83'
property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release

View File

@@ -1,10 +1,10 @@
!isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included")
QTCREATOR_PRI_INCLUDED = 1
QTCREATOR_VERSION = 4.7.82
QTCREATOR_COMPAT_VERSION = 4.7.82
QTCREATOR_VERSION = 4.7.83
QTCREATOR_COMPAT_VERSION = 4.7.83
VERSION = $$QTCREATOR_VERSION
QTCREATOR_DISPLAY_VERSION = 4.8.0-beta1
QTCREATOR_DISPLAY_VERSION = 4.8.0-beta2
QTCREATOR_COPYRIGHT_YEAR = 2018
BINARY_ARTIFACTS_BRANCH = master

View File

@@ -2795,7 +2795,7 @@ def qdump__qfloat16(d, value):
elif exp == 0b11111:
res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan'
else:
res = (-1)**sign * (1 + fraction / 2**10) * 2**(exp - 15)
res = (-1)**sign * (1 + 1. * fraction / 2**10) * 2**(exp - 15)
d.putValue(res)
d.putNumChild(1)
d.putPlainChildren(value)

View File

@@ -25,7 +25,9 @@
<style name="Function"/>
<style name="Keyword" foreground="#45c6d6" italic="true"/>
<style name="PrimitiveType" foreground="#d69aa7"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#d6bb9a"/>
<style name="Overloaded Operator"/>
<style name="Preprocessor" foreground="#ff6aad"/>
<style name="Label" foreground="#d6c540"/>
<style name="Comment" foreground="#a8abb0" italic="true"/>

View File

@@ -25,7 +25,9 @@
<style name="Number" foreground="#ff55ff"/>
<style name="Occurrences" background="#363636"/>
<style name="Occurrences.Rename" foreground="#ffaaaa" background="#553636"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#aaaaaa"/>
<style name="Overloaded Operator"/>
<style name="Parentheses" foreground="#ff5555" background="#333333"/>
<style name="ParenthesesMismatch" background="#800080"/>
<style name="AutoComplete" foreground="#a0a0ff" background="#333333"/>

View File

@@ -25,7 +25,9 @@
<style name="Function" background="#ffffff"/>
<style name="Keyword" foreground="#808000"/>
<style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/>
<style name="Operator"/>
<style name="Overloaded Operator" background="#ffffff"/>
<style name="Preprocessor" foreground="#000080"/>
<style name="Label" foreground="#800000"/>
<style name="Comment" foreground="#008000"/>

View File

@@ -22,7 +22,9 @@
<style name="Link" foreground="#0000ff"/>
<style name="Local"/>
<style name="Number" foreground="#3f3f3f"/>
<style name="Punctuation"/>
<style name="Operator"/>
<style name="Overloaded Operator"/>
<style name="Parentheses" background="#e3e3e3" bold="true"/>
<style name="ParenthesesMismatch" background="#808080"/>
<style name="AutoComplete" foreground="#303030" background="#d0d0d0"/>

View File

@@ -31,7 +31,9 @@
<style name="Occurrences" foreground="#000000" background="#616161"/>
<style name="Occurrences.Rename" foreground="#000000" background="#ff6464"/>
<style name="Occurrences.Unused" foreground="#808000"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#cfbfad"/>
<style name="Overloaded Operator"/>
<style name="Parentheses" foreground="#ffff00" background="#4e4e8f"/>
<style name="ParenthesesMismatch" background="#404040"/>
<style name="AutoComplete" foreground="#ffff00" background="#4e4e8f"/>

View File

@@ -15,6 +15,7 @@
<style name="Local" foreground="#000000"/>
<style name="Number" foreground="#0000ff"/>
<style name="Operator" foreground="#000000"/>
<style name="Overloaded Operator" foreground="#000000"/>
<style name="Parentheses" foreground="#ff0000" background="#c3e1ff"/>
<style name="ParenthesesMismatch" background="#ff00ff"/>
<style name="AutoComplete" foreground="#ff0000" background="#c3e1ff"/>

View File

@@ -31,7 +31,9 @@
<style name="Function"/>
<style name="Keyword" foreground="#78d7ec" italic="true"/>
<style name="PrimitiveType" foreground="#ff8080"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#a6e22e"/>
<style name="Overloaded Operator"/>
<style name="Preprocessor" foreground="#f92672"/>
<style name="Label" foreground="#ffff55"/>
<style name="Comment" foreground="#75715e" italic="true"/>

View File

@@ -31,7 +31,9 @@
<style name="Function" foreground="#839496"/>
<style name="Keyword" foreground="#709d06"/>
<style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#839496"/>
<style name="Overloaded Operator" foreground="#839496"/>
<style name="Preprocessor" foreground="#cb4b16"/>
<style name="Label" foreground="#268bd2" bold="true"/>
<style name="Comment" foreground="#586e75" italic="true"/>

View File

@@ -31,7 +31,9 @@
<style name="Function" foreground="#657b83"/>
<style name="Keyword" foreground="#709d06"/>
<style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#657b83"/>
<style name="Overloaded Operator" foreground="#657b83"/>
<style name="Preprocessor" foreground="#cb4b16"/>
<style name="Label" foreground="#268bd2" bold="true"/>
<style name="Comment" foreground="#93a1a1" italic="true"/>

View File

@@ -1757,6 +1757,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+A</source>
<translation>Alt+Shift+T,Alt+A</translation>
</message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+A</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+A</translation>
</message>
<message>
<source>&amp;Run Selected Tests</source>
<translation>&amp;Запустить выбранные</translation>
@@ -1769,6 +1773,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+R</source>
<translation>Alt+Shift+T,Alt+R</translation>
</message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+R</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+R</translation>
</message>
<message>
<source>Run Tests for Current &amp;File</source>
<translation>Запустить тесты для текущего &amp;файла</translation>
@@ -1781,6 +1789,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+F</source>
<translation>Alt+Shift+T,Alt+F</translation>
</message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+F</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+F</translation>
</message>
<message>
<source>Re&amp;scan Tests</source>
<translation>&amp;Пересканировать</translation>
@@ -1789,6 +1801,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+S</source>
<translation>Alt+Shift+T,Alt+S</translation>
</message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+S</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+S</translation>
</message>
<message>
<source>&amp;Run Test Under Cursor</source>
<translation>&amp;Запустить тест под курсором</translation>
@@ -11195,7 +11211,7 @@ Flags: %3</source>
<name>CppTools::TidyChecksTreeModel</name>
<message>
<source>Web Page</source>
<translation>Вэб-страница</translation>
<translation>Веб-страница</translation>
</message>
</context>
<context>
@@ -13312,7 +13328,7 @@ Affected are breakpoints %1</source>
</message>
<message>
<source>Start Debugging Without Deployment</source>
<translation>Начать отладку с установкой</translation>
<translation>Начать отладку без установки</translation>
</message>
<message>
<source>Start and Debug External Application...</source>
@@ -26820,6 +26836,10 @@ to project &quot;%2&quot;.</source>
<source>Alt+Shift+L</source>
<translation>Alt+Shift+L</translation>
</message>
<message>
<source>Meta+Shift+L</source>
<translation>Meta+Shift+L</translation>
</message>
<message>
<source>Hide Empty Directories</source>
<translation>Скрывать пустые каталоги</translation>
@@ -36383,7 +36403,7 @@ For more details, see /etc/sysctl.d/10-ptrace.conf
</message>
<message>
<source>Classes for displaying and editing Web content</source>
<translation>Классы для отображения и правки вэб-страниц</translation>
<translation>Классы для отображения и правки веб-страниц</translation>
</message>
<message>
<source>WebKit1 and QWidget-based classes from Qt 4 (Qt 5)</source>
@@ -45318,6 +45338,10 @@ should a repository require SSH-authentication (see documentation on SSH and the
<source>No executable to deploy found in %1.</source>
<translation>В %1 не обнаружен исполняемый файл для установки.</translation>
</message>
<message>
<source>Cannot find windeployqt.exe in &quot;%1&quot;.</source>
<translation>Не удалось найти windeployqt.exe в «%1».</translation>
</message>
<message>
<source>Cannot parse manifest file %1.</source>
<translation>Не удалось разобрать файл манифеста %1.</translation>

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; }

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