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

This commit is contained in:
Orgad Shaneh
2018-10-13 16:32:20 +00:00
committed by The Qt Project
185 changed files with 4302 additions and 1493 deletions

View File

@@ -37,7 +37,8 @@
\title Connecting Android Devices \title Connecting Android Devices
You can connect Android devices to the development PC to run, debug, 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 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 installed on the development PC, you can add it to \QC. You can then add a
@@ -59,7 +60,10 @@
\list \list
\li \l{http://www.oracle.com/technetwork/java/javase/downloads/index.html} \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 \li \l{http://www.gradle.org}{Gradle} for building application packages
for Android devices (APK). Gradle is delivered with Qt 5.9, and 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 \li A tool chain for building applications for Android devices provided
by the \l{http://developer.android.com/tools/sdk/ndk/index.html} 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} \li \l{http://developer.android.com/sdk/index.html}{Android SDK Tools}
@@ -106,9 +110,12 @@
\section1 Setting Up the Development Environment \section1 Setting Up the Development Environment
You must download and install the latest Android NDK and SDK, and then 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 update or install the tools and packages needed for development. However,
tool used to update and install the other SDK tools and packages depends on if your Qt version is earlier than v5.9, use the SDK tools package v25.2.5
the Android SDK Tools version that you have installed: 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 \list
@@ -135,6 +142,10 @@
In addition, you must install Qt for Android as part of Qt 5.2, or later. 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}. For more information, see \l{Qt for Android}.
\section2 Specifying Android Device Settings \section2 Specifying Android Device Settings
@@ -287,22 +298,11 @@
\section1 Debugging on Android Devices \section1 Debugging on Android Devices
Android devices support debugging multi-thread applications in version Select a \l{glossary-build-config}{debug build configuration} to build
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
the application for debugging. the application for debugging.
\note \QC cannot debug applications on Android devices if Android Studio is \note \QC cannot debug applications on Android devices if Android Studio is
running. If the following message is displayed in the \uicontrol Output running. If the following message is displayed in the \uicontrol Output
pane, close Android Studio and try again: \e {Ignoring second debugger - pane, close Android Studio and try again: \e {Ignoring second debugger -
accepting and dropping.} accepting and dropping.}
*/ */

View File

@@ -60,7 +60,7 @@
first-letter case-sensitivity, select \uicontrol Full or first-letter case-sensitivity, select \uicontrol Full or
\uicontrol {First Letter} in the \uicontrol {Case-sensitivity} field. \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 The following table lists available types for code completion and icon used
for each. for each.
@@ -132,7 +132,7 @@
\endif \endif
\endtable \endtable
\section2 Completing Code Snippets \section1 Completing Code Snippets
Code snippets can consist of multiple variables that you specify values for. 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 Select an item in the list and press \key Tab or \key Enter to complete the
@@ -189,7 +189,7 @@
\endlist \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 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 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 To discard the changes you made to a built-in snippet, select
\uicontrol {Revert Built-in}. \uicontrol {Revert Built-in}.
\section3 Removing Snippets \section2 Removing Snippets
Several similar built-in snippets might be provided for different use cases. 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 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 Remove. To restore the removed snippets, select
\uicontrol {Restore Removed Built-ins}. \uicontrol {Restore Removed Built-ins}.
\section3 Resetting Snippets \section2 Resetting Snippets
To remove all added snippets and to restore all removed snippets, select To remove all added snippets and to restore all removed snippets, select
\uicontrol {Reset All}. \uicontrol {Reset All}.

View File

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

View File

@@ -4,16 +4,16 @@ import qbs.FileInfo
import "qtc.js" as HelperFunctions import "qtc.js" as HelperFunctions
Module { 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_major: '4'
property string ide_version_minor: '7' 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 + '.' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release + ide_version_release
property string ide_compat_version_major: '4' property string ide_compat_version_major: '4'
property string ide_compat_version_minor: '7' 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 + '.' property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release + ide_compat_version_minor + '.' + ide_compat_version_release

View File

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

View File

@@ -2795,7 +2795,7 @@ def qdump__qfloat16(d, value):
elif exp == 0b11111: elif exp == 0b11111:
res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan' res = ('-inf' if sign else 'inf') if fraction == 0 else 'nan'
else: 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.putValue(res)
d.putNumChild(1) d.putNumChild(1)
d.putPlainChildren(value) d.putPlainChildren(value)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -31,7 +31,9 @@
<style name="Function" foreground="#657b83"/> <style name="Function" foreground="#657b83"/>
<style name="Keyword" foreground="#709d06"/> <style name="Keyword" foreground="#709d06"/>
<style name="PrimitiveType" foreground="#808000"/> <style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/>
<style name="Operator" foreground="#657b83"/> <style name="Operator" foreground="#657b83"/>
<style name="Overloaded Operator" foreground="#657b83"/>
<style name="Preprocessor" foreground="#cb4b16"/> <style name="Preprocessor" foreground="#cb4b16"/>
<style name="Label" foreground="#268bd2" bold="true"/> <style name="Label" foreground="#268bd2" bold="true"/>
<style name="Comment" foreground="#93a1a1" italic="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> <source>Alt+Shift+T,Alt+A</source>
<translation>Alt+Shift+T,Alt+A</translation> <translation>Alt+Shift+T,Alt+A</translation>
</message> </message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+A</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+A</translation>
</message>
<message> <message>
<source>&amp;Run Selected Tests</source> <source>&amp;Run Selected Tests</source>
<translation>&amp;Запустить выбранные</translation> <translation>&amp;Запустить выбранные</translation>
@@ -1769,6 +1773,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+R</source> <source>Alt+Shift+T,Alt+R</source>
<translation>Alt+Shift+T,Alt+R</translation> <translation>Alt+Shift+T,Alt+R</translation>
</message> </message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+R</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+R</translation>
</message>
<message> <message>
<source>Run Tests for Current &amp;File</source> <source>Run Tests for Current &amp;File</source>
<translation>Запустить тесты для текущего &amp;файла</translation> <translation>Запустить тесты для текущего &amp;файла</translation>
@@ -1781,6 +1789,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+F</source> <source>Alt+Shift+T,Alt+F</source>
<translation>Alt+Shift+T,Alt+F</translation> <translation>Alt+Shift+T,Alt+F</translation>
</message> </message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+F</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+F</translation>
</message>
<message> <message>
<source>Re&amp;scan Tests</source> <source>Re&amp;scan Tests</source>
<translation>&amp;Пересканировать</translation> <translation>&amp;Пересканировать</translation>
@@ -1789,6 +1801,10 @@ Install an SDK of at least API version %1.</source>
<source>Alt+Shift+T,Alt+S</source> <source>Alt+Shift+T,Alt+S</source>
<translation>Alt+Shift+T,Alt+S</translation> <translation>Alt+Shift+T,Alt+S</translation>
</message> </message>
<message>
<source>Ctrl+Meta+T, Ctrl+Meta+S</source>
<translation>Ctrl+Meta+T, Ctrl+Meta+S</translation>
</message>
<message> <message>
<source>&amp;Run Test Under Cursor</source> <source>&amp;Run Test Under Cursor</source>
<translation>&amp;Запустить тест под курсором</translation> <translation>&amp;Запустить тест под курсором</translation>
@@ -11195,7 +11211,7 @@ Flags: %3</source>
<name>CppTools::TidyChecksTreeModel</name> <name>CppTools::TidyChecksTreeModel</name>
<message> <message>
<source>Web Page</source> <source>Web Page</source>
<translation>Вэб-страница</translation> <translation>Веб-страница</translation>
</message> </message>
</context> </context>
<context> <context>
@@ -13312,7 +13328,7 @@ Affected are breakpoints %1</source>
</message> </message>
<message> <message>
<source>Start Debugging Without Deployment</source> <source>Start Debugging Without Deployment</source>
<translation>Начать отладку с установкой</translation> <translation>Начать отладку без установки</translation>
</message> </message>
<message> <message>
<source>Start and Debug External Application...</source> <source>Start and Debug External Application...</source>
@@ -26820,6 +26836,10 @@ to project &quot;%2&quot;.</source>
<source>Alt+Shift+L</source> <source>Alt+Shift+L</source>
<translation>Alt+Shift+L</translation> <translation>Alt+Shift+L</translation>
</message> </message>
<message>
<source>Meta+Shift+L</source>
<translation>Meta+Shift+L</translation>
</message>
<message> <message>
<source>Hide Empty Directories</source> <source>Hide Empty Directories</source>
<translation>Скрывать пустые каталоги</translation> <translation>Скрывать пустые каталоги</translation>
@@ -36383,7 +36403,7 @@ For more details, see /etc/sysctl.d/10-ptrace.conf
</message> </message>
<message> <message>
<source>Classes for displaying and editing Web content</source> <source>Classes for displaying and editing Web content</source>
<translation>Классы для отображения и правки вэб-страниц</translation> <translation>Классы для отображения и правки веб-страниц</translation>
</message> </message>
<message> <message>
<source>WebKit1 and QWidget-based classes from Qt 4 (Qt 5)</source> <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> <source>No executable to deploy found in %1.</source>
<translation>В %1 не обнаружен исполняемый файл для установки.</translation> <translation>В %1 не обнаружен исполняемый файл для установки.</translation>
</message> </message>
<message>
<source>Cannot find windeployqt.exe in &quot;%1&quot;.</source>
<translation>Не удалось найти windeployqt.exe в «%1».</translation>
</message>
<message> <message>
<source>Cannot parse manifest file %1.</source> <source>Cannot parse manifest file %1.</source>
<translation>Не удалось разобрать файл манифеста %1.</translation> <translation>Не удалось разобрать файл манифеста %1.</translation>

View File

@@ -276,7 +276,7 @@ class BuildPaths(object): # pylint: disable=too-many-instance-attributes
else: else:
raise InternalError("Unknown src info type '%s'" % (typ)) 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 Handle command line options
Do not use logging in this method as command line options need to be 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, build_group.add_option('--with-debug-asserts', action='store_true', default=False,
help=optparse.SUPPRESS_HELP) 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 = optparse.OptionGroup(parser, 'Documentation Options')
docs_group.add_option('--with-documentation', action='store_true', 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') help='minimize build')
# Should be derived from info.txt but this runs too early # 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: for mod in third_party:
mods_group.add_option('--with-%s' % (mod), mods_group.add_option('--with-%s' % (mod),
@@ -754,6 +757,7 @@ class ModuleInfo(InfoObject):
""" """
def __init__(self, infofile): def __init__(self, infofile):
# pylint: disable=too-many-statements
super(ModuleInfo, self).__init__(infofile) super(ModuleInfo, self).__init__(infofile)
lex = lex_me_harder( lex = lex_me_harder(
infofile, infofile,
@@ -850,7 +854,7 @@ class ModuleInfo(InfoObject):
for key, value in defines.items(): for key, value in defines.items():
if not re.match('^[0-9A-Za-z_]{3,30}$', key): if not re.match('^[0-9A-Za-z_]{3,30}$', key):
raise InternalError('Module defines key has invalid format: "%s"' % 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) raise InternalError('Module defines value has invalid format: "%s"' % value)
def cross_check(self, arch_info, cc_info, all_os_features): def cross_check(self, arch_info, cc_info, all_os_features):
@@ -959,7 +963,7 @@ class ModuleInfo(InfoObject):
def dependencies(self, osinfo): def dependencies(self, osinfo):
# base is an implicit dep for all submodules # base is an implicit dep for all submodules
deps = ['base'] deps = ['base']
if self.parent_module != None: if self.parent_module is not None:
deps.append(self.parent_module) deps.append(self.parent_module)
for req in self.requires: for req in self.requires:
@@ -1173,22 +1177,22 @@ class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes
return self.visibility_attribute return self.visibility_attribute
return '' 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 #pylint: disable=too-many-branches
""" """
Return the machine specific ABI flags Return the machine specific ABI flags
""" """
if with_debug_info is None: if debug_mode is None:
with_debug_info = options.with_debug_info debug_mode = options.debug_mode
def mach_abi_groups(): def mach_abi_groups():
yield 'all' yield 'all'
if options.msvc_runtime is None: if options.msvc_runtime is None:
if with_debug_info: if debug_mode:
yield 'rt-debug' yield 'rt-debug'
else: else:
yield 'rt' yield 'rt'
@@ -1205,7 +1209,7 @@ class CompilerInfo(InfoObject): # pylint: disable=too-many-instance-attributes
for what in mach_abi_groups(): for what in mach_abi_groups():
if what in self.mach_abi_linking: if what in self.mach_abi_linking:
flag = self.mach_abi_linking.get(what) 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) abi_link.add(flag)
if options.msvc_runtime: if options.msvc_runtime:
@@ -1418,7 +1422,7 @@ class OsInfo(InfoObject): # pylint: disable=too-many-instance-attributes
return False return False
def building_shared_supported(self): def building_shared_supported(self):
return self.soname_pattern_base != None return self.soname_pattern_base is not None
def enabled_features(self, options): def enabled_features(self, options):
feats = [] feats = []
@@ -1466,7 +1470,7 @@ def guess_processor(archinfo):
for info_part in system_cpu_info(): for info_part in system_cpu_info():
if info_part: if info_part:
match = canon_processor(archinfo, 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)) logging.debug("Matched '%s' to processor '%s'" % (info_part, match))
return match, info_part return match, info_part
else: 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 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") raise InternalError("Invalid argument")
libs = set() libs = set()
for module in modules: for module in modules:
for (osname, module_link_to) in getattr(module, module_member_name).items(): 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) libs |= set(module_link_to)
else: else:
match = re.match('^all!(.*)', osname) 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 return osinfo.ar_command
def choose_endian(arch_info, options): def choose_endian(arch_info, options):
if options.with_endian != None: if options.with_endian is not None:
return options.with_endian return options.with_endian
if options.cpu.endswith('eb') or options.cpu.endswith('be'): 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'): elif options.cpu.endswith('el') or options.cpu.endswith('le'):
return 'little' 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 return arch_info.endian
build_dir = options.with_build_dir or os.path.curdir 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, 'with_rst2man': options.with_rst2man,
'sphinx_config_dir': source_paths.sphinx_config_dir, 'sphinx_config_dir': source_paths.sphinx_config_dir,
'with_doxygen': options.with_doxygen, 'with_doxygen': options.with_doxygen,
'maintainer_mode': options.maintainer_mode,
'out_dir': build_dir, 'out_dir': build_dir,
'build_dir': build_paths.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_openmp': options.with_openmp,
'with_debug_asserts': options.with_debug_asserts, 'with_debug_asserts': options.with_debug_asserts,
'test_mode': options.test_mode, 'test_mode': options.test_mode,
'optimize_for_size': options.optimize_for_size,
'mod_list': sorted([m.basename for m in modules]) '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']) variables['static_suffix'])
if options.build_shared_lib: 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['soname_base'] = osinfo.soname_pattern_base.format(**variables)
variables['shared_lib_name'] = variables['soname_base'] 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['soname_abi'] = osinfo.soname_pattern_abi.format(**variables)
variables['shared_lib_name'] = variables['soname_abi'] 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['soname_patch'] = osinfo.soname_pattern_patch.format(**variables)
variables['lib_link_cmd'] = variables['lib_link_cmd'].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) self._modules, self._options.enabled_modules, self._options.disabled_modules)
def _check_usable(self, module, modname): 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) self._not_using_because['incompatible OS'].add(modname)
return False return False
elif not module.compatible_compiler(self._ccinfo, self._cc_min_version, self._archinfo.basename): elif not module.compatible_compiler(self._ccinfo, self._cc_min_version, self._archinfo.basename):
self._not_using_because['incompatible compiler'].add(modname) self._not_using_because['incompatible compiler'].add(modname)
return False return False
elif not module.compatible_cpu(self._archinfo, self._options):
self._not_using_because['incompatible CPU'].add(modname)
return False
return True return True
@staticmethod @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 # 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 # Furthermore the SeCreateSymbolicLinkPrivilege is required in order to successfully create symlinks
# So only try to use symlinks on Windows if explicitly requested # So only try to use symlinks on Windows if explicitly requested
if req == 'symlink' and options.os == 'windows':
yield 'symlink' if options.os in ['windows', 'mingw', 'cygwin']:
# otherwise keep old conservative behavior if req == 'symlink':
if 'symlink' in os.__dict__ and options.os != 'windows': yield 'symlink'
elif 'symlink' in os.__dict__:
yield 'symlink' yield 'symlink'
if 'link' in os.__dict__: if 'link' in os.__dict__:
yield 'hardlink' yield 'hardlink'
yield 'copy' yield 'copy'
@@ -2352,16 +2361,10 @@ class AmalgamationHeader(object):
self.included_already = set() self.included_already = set()
self.all_std_includes = set() self.all_std_includes = set()
encoding_kwords = {}
if sys.version_info[0] == 3:
encoding_kwords['encoding'] = 'utf8'
self.file_contents = {} self.file_contents = {}
for filepath in sorted(input_filepaths): for filepath in sorted(input_filepaths):
try: try:
with open(filepath, **encoding_kwords) as f: contents = AmalgamationGenerator.read_header(filepath)
raw_content = f.readlines()
contents = AmalgamationGenerator.strip_header_goop(filepath, raw_content)
self.file_contents[os.path.basename(filepath)] = contents self.file_contents[os.path.basename(filepath)] = contents
except IOError as e: except IOError as e:
logging.error('Error processing file %s for amalgamation: %s' % (filepath, 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_$') _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 @staticmethod
def strip_header_goop(header_name, header_lines): def strip_header_goop(header_name, header_lines):
lines = copy.copy(header_lines) # defensive copy lines = copy.copy(header_lines) # defensive copy
@@ -2505,16 +2517,32 @@ class AmalgamationGenerator(object):
logging.info('Writing amalgamation header to %s' % (header_name)) logging.info('Writing amalgamation header to %s' % (header_name))
pub_header_amalag.write_to_file(header_name, "BOTAN_AMALGAMATION_H_") 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) header_int_name = '%s_internal.h' % (AmalgamationGenerator.filename_prefix)
logging.info('Writing amalgamation header to %s' % (header_int_name)) logging.info('Writing amalgamation header to %s' % (header_int_name))
internal_headers.write_to_file(header_int_name, "BOTAN_AMALGAMATION_INTERNAL_H_") internal_headers.write_to_file(header_int_name, "BOTAN_AMALGAMATION_INTERNAL_H_")
header_files = [header_name, header_int_name] header_files = [header_name, header_int_name]
included_in_headers = pub_header_amalag.all_std_includes | internal_headers.all_std_includes 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 = {} encoding_kwords = {}
if sys.version_info[0] == 3: if sys.version_info[0] == 3:
encoding_kwords['encoding'] = 'utf8' encoding_kwords['encoding'] = 'utf8'
@@ -2533,6 +2561,14 @@ class AmalgamationGenerator(object):
logging.info('Writing amalgamation source to %s' % (filepath)) logging.info('Writing amalgamation source to %s' % (filepath))
amalgamation_files[target] = open(filepath, 'w', **encoding_kwords) 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(): for target, f in amalgamation_files.items():
AmalgamationHeader.write_banner(f) AmalgamationHeader.write_banner(f)
f.write('\n') f.write('\n')
@@ -2542,13 +2578,11 @@ class AmalgamationGenerator(object):
for isa in self._isas_for_target(target): for isa in self._isas_for_target(target):
if isa == 'sse41': if isa in isa_headers:
isa = 'sse4.1' f.write(isa_headers[isa])
elif isa == 'sse42':
isa = 'ssse4.2'
f.write('#if defined(__GNUG__) && !defined(__clang__)\n') 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') f.write('#endif\n')
# target to include header map # target to include header map
@@ -2580,8 +2614,8 @@ class AmalgamationGenerator(object):
return set(amalgamation_sources.values()) return set(amalgamation_sources.values())
def generate(self): def generate(self):
amalgamation_headers, included_in_headers = self._generate_headers() amalgamation_headers, included_in_headers, isa_headers = self._generate_headers()
amalgamation_sources = self._generate_sources(amalgamation_headers, included_in_headers) amalgamation_sources = self._generate_sources(amalgamation_headers, included_in_headers, isa_headers)
return (sorted(amalgamation_sources), sorted(amalgamation_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 'gcc'
return None 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) options.compiler = deduce_compiler_type_from_cc_bin(options.compiler_binary)
if options.compiler is None: 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: if options.os != options.cpu:
raise UserError('LLVM target requires both CPU and OS be set to llvm') 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']: if options.build_fuzzers not in ['libfuzzer', 'afl', 'klee', 'test']:
raise UserError('Bad value to --build-fuzzers') 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 ccinfo.basename == 'msvc':
if major_version == 18: 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 return cc_version
def check_compiler_arch(options, ccinfo, archinfo, source_paths): 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(' ') abi_flags = ccinfo.mach_abi_link_flags(options).split(' ')
cc_output = run_compiler_preproc(options, ccinfo, detect_version_source, 'UNKNOWN', abi_flags).lower() 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') logging.warning('Unable to detect target architecture via compiler macro checks')
return None return None
@@ -2954,7 +2994,7 @@ def check_compiler_arch(options, ccinfo, archinfo, source_paths):
return cc_output return cc_output
def do_io_for_build(cc, arch, osinfo, using_mods, build_paths, source_paths, template_vars, options): 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: try:
robust_rmtree(build_paths.build_dir) robust_rmtree(build_paths.build_dir)
@@ -3165,10 +3205,8 @@ if __name__ == '__main__':
logging.error("""%s logging.error("""%s
An internal error occurred. An internal error occurred.
Don't panic, this is probably not your fault! Don't panic, this is probably not your fault! Please open an issue
with the entire output at https://github.com/randombit/botan
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
You'll meet friendly people happy to help!""" % traceback.format_exc()) 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 Botan (Japanese for peony flower) is a C++ cryptography library released under the
and released under the permissive `Simplified BSD permissive `Simplified BSD <https://botan.randombit.net/license.txt>`_ license.
<https://botan.randombit.net/license.txt>`_ license.
Botan's goal is to be the best option for cryptography in C++ by offering the 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, 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 password hashing, and post quantum crypto schemes.
specifically designed to be easy to call from other languages. A Python binding See the `documentation <https://botan.randombit.net/manual>`_ for more information.
using ctypes is included, and several other `language bindings
A Python binding is included, and several other `language bindings
<https://github.com/randombit/botan/wiki/Language-Bindings>`_ are available. <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>`_ Development is coordinated on `GitHub <https://github.com/randombit/botan>`_
and contributions are welcome (read `doc/contributing.rst` for more info). and contributions are welcome. If you need help, please open an issue on
`GitHub <https://github.com/randombit/botan/issues>`_ or email the
If you need help with a problem, please open an `issue on GitHub `botan-devel mailing list <https://lists.randombit.net/mailman/listinfo/botan-devel/>`_.
<https://github.com/randombit/botan/issues>`_ or email the New releases are announced on the `botan-announce mailing list
`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/>`_. <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 The latest release is
Jack Lloyd by emailing jack@randombit.net. His PGP public key with `2.8.0 <https://botan.randombit.net/releases/Botan-2.8.0.tgz>`_
fingerprint 4E60C73551AF2188DF0A5A6278E9804357123B60 can can be found `(sig) <https://botan.randombit.net/releases/Botan-2.8.0.tgz.asc>`_,
in ``doc/pgpkey.txt`` in the distribution, released on 2018-10-01.
https://keybase.io/jacklloyd, and some public PGP key servers. 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
.. highlight:: none what is new. Botan is also available through most
`distributions <https://github.com/randombit/botan/wiki/Distros>`_
For all the details on building the library, read the such as Fedora, Debian, Arch and Homebrew.
`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.
.. image:: https://travis-ci.org/randombit/botan.svg?branch=master .. image:: https://travis-ci.org/randombit/botan.svg?branch=master
:target: https://travis-ci.org/randombit/botan :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 :target: https://scan.coverity.com/projects/624
:alt: Coverity results :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 .. image:: https://bestpractices.coreinfrastructure.org/projects/531/badge
:target: https://bestpractices.coreinfrastructure.org/projects/531 :target: https://bestpractices.coreinfrastructure.org/projects/531
:alt: CII Best Practices statement :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 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. * 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. * DTLS v1.0 and v1.2 are adaptations of TLS to datagram operation.
* Extensions include session tickets, SNI, ALPN, OCSP staple requests (client * Supported extensions include session tickets, SNI, ALPN, OCSP stapling,
side only right now), encrypt-then-mac CBC, and extended master secret. encrypt-then-mac CBC, and extended master secret.
* Supports authentication using preshared keys (PSK) or passwords (SRP) * Supports authentication using preshared keys (PSK) or passwords (SRP)
* Supports record encryption with ChaCha20Poly1305, AES/OCB, AES/GCM, AES/CCM, * Supports record encryption with ChaCha20Poly1305, AES/OCB, AES/GCM, AES/CCM,
Camellia/GCM as well as legacy CBC ciphersuites. Camellia/GCM as well as legacy CBC ciphersuites.
@@ -144,7 +85,7 @@ Public Key Cryptography
* RSA signatures and encryption * RSA signatures and encryption
* DH and ECDH key agreement * 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 signature scheme XMSS
* Post-quantum key agreement schemes McEliece and NewHope * Post-quantum key agreement schemes McEliece and NewHope
* ElGamal encryption * ElGamal encryption
@@ -153,17 +94,15 @@ Public Key Cryptography
Ciphers, hashes, MACs, and checksums Ciphers, hashes, MACs, and checksums
---------------------------------------- ----------------------------------------
* Authenticated cipher modes EAX, OCB, GCM, SIV, CCM, and ChaCha20Poly1305 * Authenticated cipher modes EAX, OCB, GCM, SIV, CCM, (X)ChaCha20Poly1305
* Cipher modes CTR, CBC, XTS, CFB, and OFB * Cipher modes CTR, CBC, XTS, CFB, OFB
* Block ciphers AES, ARIA, Blowfish, Camellia, CAST-128, CAST-256, * Block ciphers AES, ARIA, Blowfish, Camellia, CAST-128, DES/3DES, GOST 28147,
DES/3DES, GOST 28147, IDEA, KASUMI, Lion, MISTY1, Noekeon, SEED, IDEA, Lion, Noekeon, SEED, Serpent, SHACAL2, SM4, Threefish-512, Twofish, XTEA
Serpent, SHACAL2, SM4, Threefish-512, Twofish, XTEA * Stream ciphers (X)ChaCha20, (X)Salsa20, SHAKE-128, RC4
* Stream ciphers ChaCha20, Salsa20/XSalsa20, SHAKE-128, and RC4 * Hash functions SHA-1, SHA-2, SHA-3, MD4, MD5, RIPEMD-160, BLAKE2b,
* Hash functions SHA-1, SHA-2, SHA-3, RIPEMD-160, Skein-512, Skein-512, SM3, Tiger, Whirlpool, GOST 34.11
BLAKE2b, SM3, Tiger, Whirlpool, GOST 34.11, MD5, MD4 * Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, X9.19 DES-MAC
* Hash function combiners Parallel and Comb4P * Non-cryptographic checksums Adler32, CRC24, CRC32
* Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, CBC-MAC, X9.19 DES-MAC
* Non-cryptographic checksums Adler32, CRC24, and CRC32
Other Useful Things Other Useful Things
---------------------------------------- ----------------------------------------
@@ -173,8 +112,7 @@ Other Useful Things
* Simple compression API wrapping zlib, bzip2, and lzma libraries * Simple compression API wrapping zlib, bzip2, and lzma libraries
* RNG wrappers for system RNG and hardware RNGs * RNG wrappers for system RNG and hardware RNGs
* HMAC_DRBG and entropy collection system for userspace RNGs * HMAC_DRBG and entropy collection system for userspace RNGs
* Password based key derivation functions PBKDF2 and Scrypt * Password hashing schemes PBKDF2, Scrypt, bcrypt
* Password hashing function bcrypt and passhash9 (custom PBKDF scheme)
* SRP-6a password authenticated key exchange * SRP-6a password authenticated key exchange
* Key derivation functions including HKDF, KDF2, SP 800-108, SP 800-56A, SP 800-56C * Key derivation functions including HKDF, KDF2, SP 800-108, SP 800-56A, SP 800-56C
* HOTP and TOTP algorithms * HOTP and TOTP algorithms

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ default -> address,undefined
address -> "-fsanitize=address" address -> "-fsanitize=address"
undefined -> "-fsanitize=undefined -fno-sanitize-recover=undefined" 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" memory -> "-fsanitize=memory"
</sanitizers> </sanitizers>

View File

@@ -65,6 +65,10 @@ altivec -> "-maltivec"
ppccrypto -> "-mcrypto" ppccrypto -> "-mcrypto"
arm64:armv8crypto -> "" 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 Aarch32 -mfpu=neon is required
# For Aarch64 NEON is enabled by default # For Aarch64 NEON is enabled by default

View File

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

View File

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

View File

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

View File

@@ -54,7 +54,7 @@ distclean:
$(PYTHON_EXE) $(SCRIPTS_DIR)/cleanup.py --build-dir="%{build_dir}" --distclean $(PYTHON_EXE) $(SCRIPTS_DIR)/cleanup.py --build-dir="%{build_dir}" --distclean
install: libs cli docs 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 # Object Files
LIBOBJS = %{join lib_objs} LIBOBJS = %{join lib_objs}

View File

@@ -21,6 +21,7 @@
1.3.132.1.12 = ECDH 1.3.132.1.12 = ECDH
1.2.156.10197.1.301.1 = SM2_Sig 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.2 = SM2_Kex
1.2.156.10197.1.301.3 = SM2_Enc 1.2.156.10197.1.301.3 = SM2_Enc
@@ -40,7 +41,6 @@
# Cipher modes # Cipher modes
1.3.14.3.2.7 = DES/CBC 1.3.14.3.2.7 = DES/CBC
1.2.840.113549.3.7 = TripleDES/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 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.2 = AES-128/CBC
2.16.840.1.101.3.4.1.22 = AES-192/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.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.4 = Serpent/OCB
1.3.6.1.4.1.25258.3.2.5 = Twofish/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]
# Hash functions # Hash functions
@@ -115,11 +130,11 @@
1.2.840.113549.2.9 = HMAC(SHA-256) 1.2.840.113549.2.9 = HMAC(SHA-256)
1.2.840.113549.2.10 = HMAC(SHA-384) 1.2.840.113549.2.10 = HMAC(SHA-384)
1.2.840.113549.2.11 = HMAC(SHA-512) 1.2.840.113549.2.11 = HMAC(SHA-512)
1.2.840.113549.2.13 = HMAC(SHA-512-256)
[keywrap] [keywrap]
# Keywrap algorithms # Keywrap algorithms
1.2.840.113549.1.9.16.3.6 = KeyWrap.TripleDES 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 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.5 = KeyWrap.AES-128
2.16.840.1.101.3.4.1.25 = KeyWrap.AES-192 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.14 = RSA/EMSA3(SHA-224)
1.2.840.113549.1.1.16 = RSA/EMSA3(SHA-512-256) 1.2.840.113549.1.1.16 = RSA/EMSA3(SHA-512-256)
1.3.36.3.3.1.2 = RSA/EMSA3(RIPEMD-160) 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.156.10197.1.504 = RSA/EMSA3(SM3)
1.2.840.10040.4.3 = DSA/EMSA1(SHA-160) 1.2.840.10040.4.3 = DSA/EMSA1(SHA-160)
@@ -208,6 +225,7 @@
[pbe] [pbe]
1.2.840.113549.1.5.12 = PKCS5.PBKDF2 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.2.840.113549.1.5.13 = PBE-PKCS5v20
1.3.6.1.4.1.11591.4.11 = Scrypt 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.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.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 sets
[ecc_param] [ecc_param]

View File

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

View File

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

View File

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

View File

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

View File

@@ -174,7 +174,7 @@ void ASN1_Formatter::decode(std::ostream& output,
data.decode(number, ENUMERATED, class_tag); 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 if(rep.empty()) // if zero
rep.resize(1); 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(); 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 * 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 /// Returns a STL timepoint object
std::chrono::system_clock::time_point to_std_timepoint() const; std::chrono::system_clock::time_point to_std_timepoint() const;
/// Return time since epoch
uint64_t time_since_epoch() const;
private: private:
void set_to(const std::string& t_spec, ASN1_Tag); void set_to(const std::string& t_spec, ASN1_Tag);
bool passes_sanity_check() const; bool passes_sanity_check() const;

View File

@@ -1,7 +1,7 @@
/* /*
* OID maps * 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 * All manual edits to this file will be lost. Edit the script
* then regenerate this source file. * 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.46", "Camellia-256/GCM" },
{ "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" }, { "0.3.4401.5.3.1.9.6", "Camellia-128/GCM" },
{ "1.0.14888.3.0.5", "ECKCDSA" }, { "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.2", "SM4/CBC" },
{ "1.2.156.10197.1.104.8", "SM4/GCM" }, { "1.2.156.10197.1.104.8", "SM4/GCM" },
{ "1.2.156.10197.1.301", "sm2p256v1" }, { "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.2", "SM2_Kex" },
{ "1.2.156.10197.1.301.3", "SM2_Enc" }, { "1.2.156.10197.1.301.3", "SM2_Enc" },
{ "1.2.156.10197.1.401", "SM3" }, { "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.156.10197.1.504", "RSA/EMSA3(SM3)" },
{ "1.2.250.1.223.101.256.1", "frp256v1" }, { "1.2.250.1.223.101.256.1", "frp256v1" },
{ "1.2.392.200011.61.1.1.1.2", "Camellia-128/CBC" }, { "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.14", "PKCS9.ExtensionRequest" },
{ "1.2.840.113549.1.9.16.3.18", "ChaCha20Poly1305" }, { "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.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.16.3.8", "Compression.Zlib" },
{ "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" }, { "1.2.840.113549.1.9.2", "PKCS9.UnstructuredName" },
{ "1.2.840.113549.1.9.3", "PKCS9.ContentType" }, { "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.1.9.7", "PKCS9.ChallengePassword" },
{ "1.2.840.113549.2.10", "HMAC(SHA-384)" }, { "1.2.840.113549.2.10", "HMAC(SHA-384)" },
{ "1.2.840.113549.2.11", "HMAC(SHA-512)" }, { "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.5", "MD5" },
{ "1.2.840.113549.2.7", "HMAC(SHA-160)" }, { "1.2.840.113549.2.7", "HMAC(SHA-160)" },
{ "1.2.840.113549.2.8", "HMAC(SHA-224)" }, { "1.2.840.113549.2.8", "HMAC(SHA-224)" },
{ "1.2.840.113549.2.9", "HMAC(SHA-256)" }, { "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.2.840.113549.3.7", "TripleDES/CBC" },
{ "1.3.101.110", "Curve25519" }, { "1.3.101.110", "Curve25519" },
{ "1.3.101.112", "Ed25519" }, { "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.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.4", "Serpent/OCB" },
{ "1.3.6.1.4.1.25258.3.2.5", "Twofish/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.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.2.1", "ElGamal" },
{ "1.3.6.1.4.1.3029.1.5.1", "OpenPGP.Curve25519" }, { "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.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.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.1.1", "PKIX.AuthorityInformationAccess" },
{ "1.3.6.1.5.5.7.3.1", "PKIX.ServerAuth" }, { "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.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.8", "DSA/EMSA1(SHA-3(512))" },
{ "2.16.840.1.101.3.4.3.9", "ECDSA/EMSA1(SHA-3(224))" }, { "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.14", "X509v3.SubjectKeyIdentifier" },
{ "2.5.29.15", "X509v3.KeyUsage" }, { "2.5.29.15", "X509v3.KeyUsage" },
{ "2.5.29.17", "X509v3.SubjectAlternativeName" }, { "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/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/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/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/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/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/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/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/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/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/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/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}) }, { "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/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/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/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/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/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/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}) }, { "ChaCha20Poly1305", OID({1,2,840,113549,1,9,16,3,18}) },
{ "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) }, { "Compression.Zlib", OID({1,2,840,113549,1,9,16,3,8}) },
{ "Curve25519", OID({1,3,101,110}) }, { "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-256)", OID({1,2,840,113549,2,9}) },
{ "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) }, { "HMAC(SHA-384)", OID({1,2,840,113549,2,10}) },
{ "HMAC(SHA-512)", OID({1,2,840,113549,2,11}) }, { "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-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-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.AES-256", OID({2,16,840,1,101,3,4,1,45}) },
{ "KeyWrap.CAST-128", OID({1,2,840,113533,7,66,15}) }, { "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}) }, { "KeyWrap.TripleDES", OID({1,2,840,113549,1,9,16,3,6}) },
{ "MD5", OID({1,2,840,113549,2,5}) }, { "MD5", OID({1,2,840,113549,2,5}) },
{ "MGF1", OID({1,2,840,113549,1,1,8}) }, { "MGF1", OID({1,2,840,113549,1,1,8}) },
{ "McEliece", OID({1,3,6,1,4,1,25258,1,3}) }, { "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 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.Curve25519", OID({1,3,6,1,4,1,3029,1,5,1}) },
{ "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) }, { "OpenPGP.Ed25519", OID({1,3,6,1,4,1,11591,15,1}) },
{ "PBE-PKCS5v20", OID({1,2,840,113549,1,5,13}) }, { "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}) }, { "PKCS5.PBKDF2", OID({1,2,840,113549,1,5,12}) },
{ "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) }, { "PKCS9.ChallengePassword", OID({1,2,840,113549,1,9,7}) },
{ "PKCS9.ContentType", OID({1,2,840,113549,1,9,3}) }, { "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.ServerAuth", OID({1,3,6,1,5,5,7,3,1}) },
{ "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) }, { "PKIX.TimeStamping", OID({1,3,6,1,5,5,7,3,8}) },
{ "PKIX.XMPPAddr", OID({1,3,6,1,5,5,7,8,5}) }, { "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}) }, { "RIPEMD-160", OID({1,3,36,3,2,1}) },
{ "RSA", OID({1,2,840,113549,1,1,1}) }, { "RSA", OID({1,2,840,113549,1,1,1}) },
{ "RSA/EMSA3(MD5)", OID({1,2,840,113549,1,1,4}) }, { "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}) }, { "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-128", OID({2,16,840,1,101,3,4,2,11}) },
{ "SHAKE-256", OID({2,16,840,1,101,3,4,2,12}) }, { "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_Enc", OID({1,2,156,10197,1,301,3}) },
{ "SM2_Kex", OID({1,2,156,10197,1,301,2}) }, { "SM2_Kex", OID({1,2,156,10197,1,301,2}) },
{ "SM2_Sig", OID({1,2,156,10197,1,301,1}) }, { "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}) }, { "SM3", OID({1,2,156,10197,1,401}) },
{ "SM4/CBC", OID({1,2,156,10197,1,104,2}) }, { "SM4/CBC", OID({1,2,156,10197,1,104,2}) },
{ "SM4/GCM", OID({1,2,156,10197,1,104,8}) }, { "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}) }, { "Scrypt", OID({1,3,6,1,4,1,11591,4,11}) },
{ "Serpent/CBC", OID({1,3,6,1,4,1,25258,3,1}) }, { "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/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/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-256", OID({1,2,643,7,1,1,2,2}) },
{ "Streebog-512", OID({1,2,643,7,1,1,2,3}) }, { "Streebog-512", OID({1,2,643,7,1,1,2,3}) },
{ "Threefish-512/CBC", OID({1,3,6,1,4,1,25258,3,2}) }, { "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/CBC", OID({1,3,6,1,4,1,25258,3,3}) },
{ "Twofish/GCM", OID({1,3,6,1,4,1,25258,3,102}) }, { "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/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.AnyPolicy", OID({2,5,29,32,0}) },
{ "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) }, { "X509v3.AuthorityKeyIdentifier", OID({2,5,29,35}) },
{ "X509v3.BasicConstraints", OID({2,5,29,19}) }, { "X509v3.BasicConstraints", OID({2,5,29,19}) },

View File

@@ -14,7 +14,7 @@ namespace OIDS {
namespace { namespace {
class OID_Map class OID_Map final
{ {
public: public:
void add_oid(const OID& oid, const std::string& str) 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_vector = std::vector<T, secure_allocator<T>>;
template<typename T> using secure_deque = std::deque<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> using SecureVector = secure_vector<T>;
template<typename T> template<typename T>

View File

@@ -1,6 +1,6 @@
/* /*
* AES * 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 * Based on the public domain reference implementation by Paulo Baretto
* *
@@ -18,14 +18,14 @@
* countermeasures are used which may be helpful in some situations: * countermeasures are used which may be helpful in some situations:
* *
* - Only a single 256-word T-table is used, with rotations applied. * - Only a single 256-word T-table is used, with rotations applied.
* Most implementations use 4 T-tables which leaks much more * Most implementations use 4 (or sometimes 5) T-tables, which leaks
* information via cache usage. * much more information via cache usage.
* *
* - The TE and TD tables are computed at runtime to avoid flush+reload * - The TE and TD tables are computed at runtime to avoid flush+reload
* attacks using clflush. As different processes will not share the * attacks using clflush. As different processes will not share the
* same underlying table data, an attacker can't manipulate another * same underlying table data, an attacker can't manipulate another
* processes cache lines via their shared reference to the library * 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 * - Each cache line of the lookup tables is accessed at the beginning
* of each call to encrypt or decrypt. (See the Z variable below) * 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"); BOTAN_ASSERT(EK.size() && ME.size() == 16, "Key was set");
const size_t cache_line_size = CPUID::cache_line_size(); const size_t cache_line_size = CPUID::cache_line_size();
const uint32_t* TE = AES_TE(); const uint32_t* TE = AES_TE();
// Hit every cache line of 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]; 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 Z &= TD[99]; // this is zero, which hopefully the compiler cannot deduce
for(size_t i = 0; i != blocks; ++i) 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 // Can't happen, but make static analyzers happy
BOTAN_ARG_CHECK(X == 4 || X == 6 || X == 8, "Invalid AES key size"); 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) 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) 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) for(size_t i = 4; i != length + 24; ++i)
{ {
XDK[i] = SE_word(XDK[i]); XDK[i] = Z ^ SE_word(XDK[i]);
XDK[i] = AES_T(AES_TD(), 0, XDK[i], XDK[i], XDK[i], XDK[i]); XDK[i] = AES_T(TD, 0, XDK[i], XDK[i], XDK[i], XDK[i]);
} }
ME.resize(16); ME.resize(16);

View File

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

View File

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

View File

@@ -98,12 +98,27 @@
#include <botan/internal/openssl.h> #include <botan/internal/openssl.h>
#endif #endif
#if defined(BOTAN_HAS_COMMONCRYPTO)
#include <botan/internal/commoncrypto.h>
#endif
namespace Botan { namespace Botan {
std::unique_ptr<BlockCipher> std::unique_ptr<BlockCipher>
BlockCipher::create(const std::string& algo, BlockCipher::create(const std::string& algo,
const std::string& provider) 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 defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl") if(provider.empty() || provider == "openssl")
{ {
@@ -115,7 +130,6 @@ BlockCipher::create(const std::string& algo,
} }
#endif #endif
// TODO: CommonCrypto
// TODO: CryptoAPI // TODO: CryptoAPI
// TODO: /dev/crypto // 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) 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; 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 * 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> template<size_t BS, size_t KMIN, size_t KMAX = 0, size_t KMOD = 1, typename BaseClass = BlockCipher>
class Block_Cipher_Fixed_Params : public BlockCipher class Block_Cipher_Fixed_Params : public BaseClass
{ {
public: public:
enum { BLOCK_SIZE = BS }; 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 // override to take advantage of compile time constant block size
void encrypt_n_xex(uint8_t data[], void encrypt_n_xex(uint8_t data[],
const uint8_t mask[], const uint8_t mask[],
size_t blocks) const override size_t blocks) const final override
{ {
xor_buf(data, mask, blocks * BS); xor_buf(data, mask, blocks * BS);
encrypt_n(data, data, blocks); this->encrypt_n(data, data, blocks);
xor_buf(data, mask, blocks * BS); xor_buf(data, mask, blocks * BS);
} }
void decrypt_n_xex(uint8_t data[], void decrypt_n_xex(uint8_t data[],
const uint8_t mask[], const uint8_t mask[],
size_t blocks) const override size_t blocks) const final override
{ {
xor_buf(data, mask, blocks * BS); xor_buf(data, mask, blocks * BS);
decrypt_n(data, data, blocks); this->decrypt_n(data, data, blocks);
xor_buf(data, mask, blocks * BS); 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); return Key_Length_Specification(KMIN, KMAX, KMOD);
} }

View File

@@ -6,30 +6,156 @@
*/ */
#include <botan/base64.h> #include <botan/base64.h>
#include <botan/internal/codec_base.h>
#include <botan/exceptn.h> #include <botan/exceptn.h>
#include <botan/mem_ops.h>
#include <botan/internal/rounding.h> #include <botan/internal/rounding.h>
namespace Botan { namespace Botan {
namespace { 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', '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', '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', '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', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' '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]; 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80,
out[1] = BIN_TO_BASE64[((in[0] & 0x03) << 4) | (in[1] >> 4)]; 0x80, 0xFF, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
out[2] = BIN_TO_BASE64[((in[1] & 0x0F) << 2) | (in[2] >> 6)]; 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
out[3] = BIN_TO_BASE64[in[2] & 0x3F]; 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[], size_t base64_encode(char out[],
@@ -38,58 +164,24 @@ size_t base64_encode(char out[],
size_t& input_consumed, size_t& input_consumed,
bool final_inputs) bool final_inputs)
{ {
input_consumed = 0; return base_encode(Base64(), out, in, input_length, input_consumed, final_inputs);
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;
} }
std::string base64_encode(const uint8_t input[], std::string base64_encode(const uint8_t input[],
size_t input_length) 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); std::string output(output_length, 0);
size_t consumed = 0; size_t consumed = 0;
size_t produced = 0; size_t produced = 0;
if (output_length > 0) if(output_length > 0)
{ {
produced = base64_encode(&output.front(), produced = base64_encode(&output.front(),
input, input_length, input, input_length,
consumed, true); consumed, true);
} }
BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input"); BOTAN_ASSERT_EQUAL(consumed, input_length, "Consumed the entire input");
BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size"); BOTAN_ASSERT_EQUAL(produced, output.size(), "Produced expected size");
@@ -97,111 +189,14 @@ std::string base64_encode(const uint8_t input[],
return output; return output;
} }
size_t base64_decode(uint8_t output[], size_t base64_decode(uint8_t out[],
const char input[], const char in[],
size_t input_length, size_t input_length,
size_t& input_consumed, size_t& input_consumed,
bool final_inputs, bool final_inputs,
bool ignore_ws) bool ignore_ws)
{ {
/* return base_decode(Base64(), out, in, input_length, input_consumed, final_inputs, 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;
} }
size_t base64_decode(uint8_t output[], size_t base64_decode(uint8_t output[],
@@ -214,7 +209,7 @@ size_t base64_decode(uint8_t output[],
consumed, true, ignore_ws); consumed, true, ignore_ws);
if(consumed != input_length) 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; return written;
} }
@@ -227,10 +222,10 @@ size_t base64_decode(uint8_t output[],
} }
secure_vector<uint8_t> base64_decode(const char input[], secure_vector<uint8_t> base64_decode(const char input[],
size_t input_length, size_t input_length,
bool ignore_ws) 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); secure_vector<uint8_t> bin(output_length);
size_t written = base64_decode(bin.data(), 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, 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); return base64_decode(input.data(), input.size(), ignore_ws);
} }
size_t base64_encode_max_output(size_t input_length) 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) 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) #if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER)
#include <botan/internal/proc_walk.h> #include <botan/internal/proc_walk.h>
#endif #include <botan/internal/os_utils.h>
#if defined(BOTAN_HAS_ENTROPY_SRC_DARWIN_SECRANDOM)
#include <botan/internal/darwin_secrandom.h>
#endif #endif
#if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY) #if defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY)
@@ -86,13 +83,6 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
} }
#endif #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 defined(BOTAN_HAS_ENTROPY_SRC_GETENTROPY)
if(name == "getentropy") if(name == "getentropy")
{ {
@@ -108,7 +98,7 @@ std::unique_ptr<Entropy_Source> Entropy_Source::create(const std::string& name)
#endif #endif
#if defined(BOTAN_HAS_ENTROPY_SRC_PROC_WALKER) #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; const std::string root_dir = BOTAN_ENTROPY_PROC_FS_PATH;
if(!root_dir.empty()) if(!root_dir.empty())

View File

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

View File

@@ -15,7 +15,8 @@
namespace Botan { namespace Botan {
BOTAN_FUNC_ISA("rdseed") BOTAN_FUNC_ISA("rdseed")
size_t Intel_Rdseed::poll(RandomNumberGenerator& rng) { size_t Intel_Rdseed::poll(RandomNumberGenerator& rng)
{
if(CPUID::has_rdseed()) if(CPUID::has_rdseed())
{ {
for(size_t p = 0; p != BOTAN_ENTROPY_INTEL_RNG_POLLS; ++p) 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 * @param in some input for the filter
*/ */
void send(const secure_vector<uint8_t>& in) { send(in.data(), in.size()); } template<typename Alloc>
void send(const std::vector<uint8_t, Alloc>& in)
/**
* @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)
{ {
send(in.data(), length); send(in.data(), in.size());
} }
/** /**
* @param in some input for the filter * @param in some input for the filter
* @param length the number of bytes of in to send * @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); send(in.data(), length);
} }

View File

@@ -101,11 +101,27 @@
#include <botan/internal/openssl.h> #include <botan/internal/openssl.h>
#endif #endif
#if defined(BOTAN_HAS_COMMONCRYPTO)
#include <botan/internal/commoncrypto.h>
#endif
namespace Botan { namespace Botan {
std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec, std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec,
const std::string& provider) 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 defined(BOTAN_HAS_OPENSSL)
if(provider.empty() || provider == "openssl") if(provider.empty() || provider == "openssl")
{ {
@@ -128,8 +144,6 @@ std::unique_ptr<HashFunction> HashFunction::create(const std::string& algo_spec,
} }
#endif #endif
// TODO: CommonCrypto hashes
if(provider.empty() == false && provider != "base") if(provider.empty() == false && provider != "base")
return nullptr; // unknown provider 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) 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") BOTAN_FUNC_ISA("+crypto")
void SHA_160::sha1_armv8_compress_n(secure_vector<uint32_t>& digest, const uint8_t input8[], size_t blocks) 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;
uint32x4_t ABCD, ABCD_SAVED; uint32_t E0;
uint32_t E0, E0_SAVED, E1;
// Load initial values // Load magic constants
C0 = vdupq_n_u32(0x5A827999); const uint32x4_t C0 = vdupq_n_u32(0x5A827999);
C1 = vdupq_n_u32(0x6ED9EBA1); const uint32x4_t C1 = vdupq_n_u32(0x6ED9EBA1);
C2 = vdupq_n_u32(0x8F1BBCDC); const uint32x4_t C2 = vdupq_n_u32(0x8F1BBCDC);
C3 = vdupq_n_u32(0xCA62C1D6); const uint32x4_t C3 = vdupq_n_u32(0xCA62C1D6);
ABCD = vld1q_u32(&digest[0]); ABCD = vld1q_u32(&digest[0]);
E0 = digest[4]; E0 = digest[4];
@@ -38,12 +37,13 @@ void SHA_160::sha1_armv8_compress_n(secure_vector<uint32_t>& digest, const uint8
while (blocks) 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 MSG0, MSG1, MSG2, MSG3;
uint32x4_t TMP0, TMP1; uint32x4_t TMP0, TMP1;
uint32_t E1;
// Save current hash
ABCD_SAVED = ABCD;
E0_SAVED = E0;
MSG0 = vld1q_u32(input32 + 0); MSG0 = vld1q_u32(input32 + 0);
MSG1 = vld1q_u32(input32 + 4); MSG1 = vld1q_u32(input32 + 4);

View File

@@ -12,6 +12,42 @@
namespace Botan { 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 * 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) 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)); std::vector<uint8_t> output(n.encoded_size(base));
encode(output.data(), n, base); encode(output.data(), n, base);
if(base != Binary) for(size_t j = 0; j != output.size(); ++j)
for(size_t j = 0; j != output.size(); ++j) if(output[j] == 0)
if(output[j] == 0) output[j] = '0';
output[j] = '0';
return output; 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) 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)); secure_vector<uint8_t> output(n.encoded_size(base));
encode(output.data(), n, base); encode(output.data(), n, base);
if(base != Binary) for(size_t j = 0; j != output.size(); ++j)
for(size_t j = 0; j != output.size(); ++j) if(output[j] == 0)
if(output[j] == 0) output[j] = '0';
output[j] = '0';
return output; return output;
} }

View File

@@ -125,6 +125,24 @@ BigInt operator*(const BigInt& x, const BigInt& y)
return z; 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 * 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) 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); 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(); const size_t b = this->bits();
if(b > max_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 uint32_t BigInt::get_substring(size_t offset, size_t length) const
{ {
if(length > 32) if(length == 0 || length > 32)
throw Invalid_Argument("BigInt::get_substring: Substring size " + std::to_string(length) + " too big"); throw Invalid_Argument("BigInt::get_substring invalid substring length");
uint64_t piece = 0; const size_t byte_offset = offset / 8;
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 shift = (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); 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]; 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) #if defined(BOTAN_HAS_VALGRIND)
void BigInt::const_time_poison() const 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); 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 * Create a BigInt from an integer in a byte array
* @param buf the byte array holding the value * @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; 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 * @param n the offset to get a byte from
* @result byte at offset n * @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; 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) #if defined(BOTAN_HAS_VALGRIND)
void const_time_poison() const; void const_time_poison() const;
void const_time_unpoison() const; void const_time_unpoison() const;
@@ -646,13 +670,78 @@ class BOTAN_PUBLIC_API(2,0) BigInt final
return b; 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 * Encode the integer value from a BigInt to a std::vector of bytes
* @param n the BigInt to use as integer source * @param n the BigInt to use as integer source
* @param base number-base of resulting byte array representation * @param base number-base of resulting byte array representation
* @result secure_vector of bytes containing the integer with given base * @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 * 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 * @result secure_vector of bytes containing the integer with given base
*/ */
static secure_vector<uint8_t> encode_locked(const BigInt& n, 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 * 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 n the BigInt to use as integer source
* @param base number-base of resulting byte array representation * @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 * 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 * @result BigInt representing the integer in the byte array
*/ */
static BigInt decode(const uint8_t buf[], size_t length, 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 * 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 * @result BigInt representing the integer in the byte array
*/ */
static BigInt decode(const secure_vector<uint8_t>& buf, 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); 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 * @param base number-base of the integer in buf
* @result BigInt representing the integer in the byte array * @result BigInt representing the integer in the byte array
*/ */
static BigInt decode(const std::vector<uint8_t>& buf, static BigInt decode(const std::vector<uint8_t>& buf, Base base)
Base base = Binary)
{ {
if(base == Binary)
return BigInt(buf);
return BigInt::decode(buf.data(), buf.size(), base); 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,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,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& d);
BigInt BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, const BigInt& m); 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); word BOTAN_PUBLIC_API(2,0) operator%(const BigInt& x, word m);

View File

@@ -2,8 +2,6 @@
BIGINT -> 20131128 BIGINT -> 20131128
</defines> </defines>
load_on auto
<header:public> <header:public>
bigint.h bigint.h
divide.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 * Single Operand Right Shift
*/ */
void bigint_shr1(word x[], size_t x_size, size_t word_shift, size_t bit_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) if(x_size < word_shift)
{ {
clear_mem(x, x_size); clear_mem(x, x_size);

View File

@@ -14,15 +14,10 @@
namespace Botan { namespace Botan {
#if (BOTAN_MP_WORD_BITS == 8) #if (BOTAN_MP_WORD_BITS == 32)
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)
typedef uint64_t dword; typedef uint64_t dword;
#define BOTAN_HAS_MP_DWORD #define BOTAN_HAS_MP_DWORD
#elif (BOTAN_MP_WORD_BITS == 64) #elif (BOTAN_MP_WORD_BITS == 64)
#if defined(BOTAN_TARGET_HAS_NATIVE_UINT128) #if defined(BOTAN_TARGET_HAS_NATIVE_UINT128)
typedef uint128_t dword; typedef uint128_t dword;
@@ -32,21 +27,19 @@ namespace Botan {
#endif #endif
#else #else
#error BOTAN_MP_WORD_BITS must be 8, 16, 32, or 64 #error BOTAN_MP_WORD_BITS must be 32 or 64
#endif #endif
#if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32) #if defined(BOTAN_TARGET_ARCH_IS_X86_32) && (BOTAN_MP_WORD_BITS == 32)
#if defined(BOTAN_USE_GCC_INLINE_ASM) #if defined(BOTAN_USE_GCC_INLINE_ASM)
#define BOTAN_MP_USE_X86_32_ASM #define BOTAN_MP_USE_X86_32_ASM
#define ASM(x) x "\n\t"
#elif defined(BOTAN_BUILD_COMPILER_IS_MSVC) #elif defined(BOTAN_BUILD_COMPILER_IS_MSVC)
#define BOTAN_MP_USE_X86_32_MSVC_ASM #define BOTAN_MP_USE_X86_32_MSVC_ASM
#endif #endif
#elif defined(BOTAN_TARGET_ARCH_IS_X86_64) && (BOTAN_MP_WORD_BITS == 64) && (BOTAN_USE_GCC_INLINE_ASM) #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 BOTAN_MP_USE_X86_64_ASM
#define ASM(x) x "\n\t"
#endif #endif
#if defined(BOTAN_MP_USE_X86_32_ASM) || defined(BOTAN_MP_USE_X86_64_ASM) #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) const BigInt& prime_p521();
BOTAN_PUBLIC_API(2,0) void redc_p521(BigInt& x, secure_vector<word>& ws); 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 #define BOTAN_HAS_NIST_PRIME_REDUCERS_W32
BOTAN_PUBLIC_API(2,0) const BigInt& prime_p384(); 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) const BigInt& prime_p192();
BOTAN_PUBLIC_API(2,0) void redc_p192(BigInt& x, secure_vector<word>& ws); BOTAN_PUBLIC_API(2,0) void redc_p192(BigInt& x, secure_vector<word>& ws);
#endif
} }
#endif #endif

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ namespace Botan {
namespace { namespace {
class Prime_Sieve class Prime_Sieve final
{ {
public: public:
Prime_Sieve(const BigInt& init_value) : m_sieve(PRIME_TABLE_SIZE) 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, Montgomery_Params::Montgomery_Params(const BigInt& p,
const Modular_Reducer& mod_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"); throw Invalid_Argument("Montgomery_Params invalid modulus");
m_p = p; 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 ... if(m_window_bits < 1 || m_window_bits > 12) // really even 8 is too large ...
throw Invalid_Argument("Invalid window bits for Montgomery exponentiation"); 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); 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); H.square_this(ws);
} }
const uint8_t z1_b = z1.get_substring(z_bits - i - 2, 2); const uint32_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 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); 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"); BOTAN_ASSERT_EQUAL(carry, 0, "Final carry in P-521 reduction");
// Now find the actual carry in bit 522 // 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) #if (BOTAN_MP_WORD_BITS == 64)
static const word p521_words[9] = { 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) #if (BOTAN_MP_WORD_BITS == 32)
return x.word_at(i); 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 #else
#error "Not implemented" return static_cast<uint32_t>(x.word_at(i/2) >> ((i % 2)*32));
#endif #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) #if (BOTAN_MP_WORD_BITS == 32)
x.set_word_at(i, R0); x.set_word_at(i, R0);
x.set_word_at(i+1, R1); 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 #else
#error "Not implemented" x.set_word_at(i/2, (static_cast<uint64_t>(R1) << 32) | R0);
#endif #endif
} }

View File

@@ -14,6 +14,7 @@
#include <botan/internal/mp_core.h> #include <botan/internal/mp_core.h>
#include <botan/internal/ct_utils.h> #include <botan/internal/ct_utils.h>
#include <botan/internal/monty_exp.h> #include <botan/internal/monty_exp.h>
#include <botan/internal/primality.h>
#include <algorithm> #include <algorithm>
namespace Botan { namespace Botan {
@@ -434,78 +435,43 @@ BigInt power_mod(const BigInt& base, const BigInt& exp, const BigInt& mod)
} }
} }
namespace {
bool mr_witness(BigInt&& y, BigInt is_perfect_square(const BigInt& C)
const Modular_Reducer& reducer_n,
const BigInt& n_minus_1, size_t s)
{ {
if(y == 1 || y == n_minus_1) if(C < 1)
return false; 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 if(X2 < B)
return true; break;
/*
-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;
} }
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 * Test for primality using Miller-Rabin
*/ */
bool is_prime(const BigInt& n, RandomNumberGenerator& rng, bool is_prime(const BigInt& n,
size_t prob, bool is_random) RandomNumberGenerator& rng,
size_t prob,
bool is_random)
{ {
if(n == 2) if(n == 2)
return true; return true;
@@ -520,47 +486,21 @@ bool is_prime(const BigInt& n, RandomNumberGenerator& rng,
return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num); return std::binary_search(PRIMES, PRIMES + PRIME_TABLE_SIZE, num);
} }
const size_t test_iterations = const size_t t = miller_rabin_test_iterations(n.bits(), prob, is_random);
mr_test_iterations(n.bits(), prob, is_random && rng.is_seeded());
const BigInt n_minus_1 = n - 1; Modular_Reducer mod_n(n);
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 Modular_Reducer mod_n(n); if(rng.is_seeded())
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)
{ {
BigInt a; if(is_miller_rabin_probable_prime(n, mod_n, rng, t) == false)
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))
return 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 * 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) * Botan is released under the Simplified BSD License (see license.txt)
*/ */
@@ -22,8 +22,8 @@ class RandomNumberGenerator;
* @return (a*b)+c * @return (a*b)+c
*/ */
BigInt BOTAN_PUBLIC_API(2,0) mul_add(const BigInt& a, BigInt BOTAN_PUBLIC_API(2,0) mul_add(const BigInt& a,
const BigInt& b, const BigInt& b,
const BigInt& c); const BigInt& c);
/** /**
* Fused subtract-multiply * Fused subtract-multiply
@@ -33,8 +33,8 @@ BigInt BOTAN_PUBLIC_API(2,0) mul_add(const BigInt& a,
* @return (a-b)*c * @return (a-b)*c
*/ */
BigInt BOTAN_PUBLIC_API(2,0) sub_mul(const BigInt& a, BigInt BOTAN_PUBLIC_API(2,0) sub_mul(const BigInt& a,
const BigInt& b, const BigInt& b,
const BigInt& c); const BigInt& c);
/** /**
* Fused multiply-subtract * Fused multiply-subtract
@@ -44,8 +44,8 @@ BigInt BOTAN_PUBLIC_API(2,0) sub_mul(const BigInt& a,
* @return (a*b)-c * @return (a*b)-c
*/ */
BigInt BOTAN_PUBLIC_API(2,0) mul_sub(const BigInt& a, BigInt BOTAN_PUBLIC_API(2,0) mul_sub(const BigInt& a,
const BigInt& b, const BigInt& b,
const BigInt& c); const BigInt& c);
/** /**
* Return the absolute value * 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 * Not const time
*/ */
size_t BOTAN_PUBLIC_API(2,0) almost_montgomery_inverse(BigInt& result, size_t BOTAN_PUBLIC_API(2,0) almost_montgomery_inverse(BigInt& result,
const BigInt& a, const BigInt& a,
const BigInt& b); const BigInt& b);
/** /**
* Call almost_montgomery_inverse and correct the result to a^-1 mod 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 * @param n is an odd integer > 1
* @return (n / m) * @return (n / m)
*/ */
int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a, int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a, const BigInt& n);
const BigInt& n);
/** /**
* Modular exponentation * Modular exponentation
@@ -137,8 +136,8 @@ int32_t BOTAN_PUBLIC_API(2,0) jacobi(const BigInt& a,
* @return (b^x) % m * @return (b^x) % m
*/ */
BigInt BOTAN_PUBLIC_API(2,0) power_mod(const BigInt& b, BigInt BOTAN_PUBLIC_API(2,0) power_mod(const BigInt& b,
const BigInt& x, const BigInt& x,
const BigInt& m); const BigInt& m);
/** /**
* Compute the square root of x modulo a prime using the * 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, bool BOTAN_PUBLIC_API(2,0) is_prime(const BigInt& n,
RandomNumberGenerator& rng, RandomNumberGenerator& rng,
size_t prob = 56, size_t prob = 64,
bool is_random = false); 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) inline bool quick_check_prime(const BigInt& n, RandomNumberGenerator& rng)
{ return is_prime(n, rng, 32); } { 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) inline bool verify_prime(const BigInt& n, RandomNumberGenerator& rng)
{ return is_prime(n, rng, 80); } { return is_prime(n, rng, 80); }
/** /**
* Randomly generate a prime suitable for discrete logarithm parameters * Randomly generate a prime suitable for discrete logarithm parameters
* @param rng a random number generator * @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_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[0] = 1;
m_g[1] = base; 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 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) if(m_mod_words == 0)
throw Invalid_State("Modular_Reducer: Never initalized"); 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) if(x_sw >= (2*m_mod_words - 1) && x.cmp(m_modulus_2, false) >= 0)
{ {
// too big, fall back to normal division // too big, fall back to normal division
return (x % m_modulus); t1 = x % m_modulus;
return;
} }
secure_vector<word> ws; t1 = x;
BigInt t1 = x;
t1.set_sign(BigInt::Positive); t1.set_sign(BigInt::Positive);
t1 >>= (BOTAN_MP_WORD_BITS * (m_mod_words - 1)); 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); 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 BigInt cube(const BigInt& x) const
{ return multiply(x, this->square(x)); } { 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); } bool initialized() const { return (m_mod_words != 0); }
Modular_Reducer() { m_mod_words = 0; } Modular_Reducer() { m_mod_words = 0; }

View File

@@ -2,6 +2,7 @@
* CBC Mode * CBC Mode
* (C) 1999-2007,2013,2017 Jack Lloyd * (C) 1999-2007,2013,2017 Jack Lloyd
* (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity * (C) 2016 Daniel Neus, Rohde & Schwarz Cybersecurity
* (C) 2018 Ribose Inc
* *
* Botan is released under the Simplified BSD License (see license.txt) * 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) : CBC_Mode::CBC_Mode(BlockCipher* cipher, BlockCipherModePaddingMethod* padding) :
m_cipher(cipher), m_cipher(cipher),
m_padding(padding), 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() + throw Invalid_Argument("Padding " + m_padding->name() +
" cannot be used with " + " cannot be used with " +
cipher->name() + "/CBC"); cipher->name() + "/CBC");
@@ -31,7 +32,7 @@ void CBC_Mode::clear()
void CBC_Mode::reset() void CBC_Mode::reset()
{ {
zeroise(m_state); m_state.clear();
} }
std::string CBC_Mode::name() const 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) void CBC_Mode::key_schedule(const uint8_t key[], size_t length)
{ {
m_cipher->set_key(key, length); m_cipher->set_key(key, length);
m_state.clear();
} }
void CBC_Mode::start_msg(const uint8_t nonce[], size_t nonce_len) 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) if(nonce_len)
m_state.assign(nonce, nonce + 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 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) size_t CBC_Encryption::process(uint8_t buf[], size_t sz)
{ {
BOTAN_STATE_CHECK(state().empty() == false);
const size_t BS = block_size(); const size_t BS = block_size();
BOTAN_ASSERT(sz % BS == 0, "CBC input is full blocks"); 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) 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"); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
const size_t BS = block_size(); 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) 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"); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
uint8_t* buf = buffer.data() + offset; uint8_t* buf = buffer.data() + offset;
const size_t sz = buffer.size() - 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) size_t CBC_Decryption::process(uint8_t buf[], size_t sz)
{ {
BOTAN_STATE_CHECK(state().empty() == false);
const size_t BS = block_size(); const size_t BS = block_size();
BOTAN_ASSERT(sz % BS == 0, "Input is full blocks"); 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) 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"); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
const size_t sz = buffer.size() - offset; 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() void CBC_Decryption::reset()
{ {
zeroise(state()); CBC_Mode::reset();
zeroise(m_tempbuf); 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) 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"); BOTAN_ASSERT(buffer.size() >= offset, "Offset is sane");
const size_t sz = buffer.size() - offset; const size_t sz = buffer.size() - offset;
uint8_t* buf = buffer.data() + 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; 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(); } 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<BlockCipher> m_cipher;
std::unique_ptr<BlockCipherModePaddingMethod> m_padding; std::unique_ptr<BlockCipherModePaddingMethod> m_padding;
secure_vector<uint8_t> m_state; secure_vector<uint8_t> m_state;
size_t m_block_size;
}; };
/** /**

View File

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

View File

@@ -9,9 +9,8 @@
#define BOTAN_CIPHER_MODE_H_ #define BOTAN_CIPHER_MODE_H_
#include <botan/secmem.h> #include <botan/secmem.h>
#include <botan/key_spec.h> #include <botan/sym_algo.h>
#include <botan/exceptn.h> #include <botan/exceptn.h>
#include <botan/symkey.h>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -26,11 +25,9 @@ enum Cipher_Dir : int { ENCRYPTION, DECRYPTION };
/** /**
* Interface for cipher modes * Interface for cipher modes
*/ */
class BOTAN_PUBLIC_API(2,0) Cipher_Mode class BOTAN_PUBLIC_API(2,0) Cipher_Mode : public SymmetricAlgorithm
{ {
public: public:
virtual ~Cipher_Mode() = default;
/** /**
* @return list of available providers for this algorithm, empty if not available * @return list of available providers for this algorithm, empty if not available
* @param algo_spec algorithm name * @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 * 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 * message with input_length bytes. In most cases the answer is precise.
* answer. * 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; 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 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 * 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; } 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", * @return provider information about this implementation. Default is "base",
* might also return "sse2", "avx2", "openssl", or some other arbitrary string. * might also return "sse2", "avx2", "openssl", or some other arbitrary string.
*/ */
virtual std::string provider() const { return "base"; } 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 * CBC Padding Methods
* (C) 1999-2007,2013 Jack Lloyd * (C) 1999-2007,2013,2018 Jack Lloyd
* (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity * (C) 2016 René Korthaus, Rohde & Schwarz Cybersecurity
* *
* Botan is released under the Simplified BSD License (see license.txt) * 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 * 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; 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; const size_t pad_pos = input_length - last_byte;
size_t i = size - 2;
while(i) 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); const uint8_t in_range = CT::expand_mask<uint8_t>(i >= pad_pos);
--i; 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(input, input_length);
CT::unpoison(block,size); return CT::conditional_return(bad_input, input_length, pad_pos);
CT::unpoison(pad_pos);
return pad_pos;
} }
/* /*
@@ -92,25 +93,27 @@ void ANSI_X923_Padding::add_padding(secure_vector<uint8_t>& buffer,
/* /*
* Unpad with ANSI X9.23 Method * 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); if(input_length <= 2)
size_t bad_input = 0; return input_length;
const size_t last_byte = block[size-1];
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; uint8_t bad_input = 0;
size_t i = size - 2; bad_input |= CT::expand_mask<uint8_t>(last_byte > input_length);
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_zero(block[i])) & CT::expand_mask<uint8_t>(i >= pad_pos); const uint8_t in_range = CT::expand_mask<uint8_t>(i >= pad_pos);
--i; 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(input, input_length);
CT::unpoison(pad_pos); return CT::conditional_return(bad_input, input_length, pad_pos);
return pad_pos;
} }
/* /*
@@ -129,28 +132,29 @@ void OneAndZeros_Padding::add_padding(secure_vector<uint8_t>& buffer,
/* /*
* Unpad with One and Zeros Method * 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 bad_input = 0;
uint8_t seen_one = 0; uint8_t seen_one = 0;
size_t pad_pos = size - 1; size_t pad_pos = input_length - 1;
size_t i = size; size_t i = input_length;
while(i) 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); 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--; i--;
} }
bad_input |= ~seen_one; bad_input |= ~seen_one;
CT::conditional_copy_mem(size_t(bad_input),&pad_pos,&size,&pad_pos,1); CT::unpoison(input, input_length);
CT::unpoison(block, size); return CT::conditional_return(bad_input, input_length, pad_pos);
CT::unpoison(pad_pos);
return pad_pos;
} }
/* /*
@@ -171,25 +175,28 @@ void ESP_Padding::add_padding(secure_vector<uint8_t>& buffer,
/* /*
* Unpad with ESP Padding Method * 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]; CT::poison(input, input_length);
size_t bad_input = 0;
bad_input |= CT::expand_mask<size_t>(last_byte > size);
size_t pad_pos = size - last_byte; const size_t last_byte = input[input_length-1];
size_t i = size - 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) 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; --i;
} }
CT::conditional_copy_mem(bad_input,&pad_pos,&size,&pad_pos,1);
CT::unpoison(block, size); CT::unpoison(input, input_length);
CT::unpoison(pad_pos); return CT::conditional_return(bad_input, input_length, pad_pos);
return pad_pos;
} }

View File

@@ -39,11 +39,10 @@ class BOTAN_PUBLIC_API(2,0) BlockCipherModePaddingMethod
/** /**
* Remove padding bytes from block * Remove padding bytes from block
* @param block the last block * @param block the last block
* @param size the size of the block in bytes * @param len the size of the block in bytes
* @return number of padding bytes * @return number of data bytes, or if the padding is invalid returns len
*/ */
virtual size_t unpad(const uint8_t block[], virtual size_t unpad(const uint8_t block[], size_t len) const = 0;
size_t size) const = 0;
/** /**
* @param block_size of the cipher * @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; 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"; } 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; 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"; } 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; 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"; } 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; 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"; } std::string name() const override { return "ESP"; }
}; };

View File

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

View File

@@ -17,6 +17,9 @@ namespace Botan {
* Base class for PBKDF (password based key derivation function) * Base class for PBKDF (password based key derivation function)
* implementations. Converts a password into a key using a salt * implementations. Converts a password into a key using a salt
* and iterated hashing to make brute force attacks harder. * 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 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; typedef PBKDF S2K;

View File

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

View File

@@ -1,6 +1,7 @@
/* /*
* PBKDF2 * PBKDF2
* (C) 1999-2007 Jack Lloyd * (C) 1999-2007 Jack Lloyd
* (C) 2018 Ribose Inc
* *
* Botan is released under the Simplified BSD License (see license.txt) * Botan is released under the Simplified BSD License (see license.txt)
*/ */
@@ -8,42 +9,116 @@
#include <botan/pbkdf2.h> #include <botan/pbkdf2.h>
#include <botan/exceptn.h> #include <botan/exceptn.h>
#include <botan/internal/rounding.h> #include <botan/internal/rounding.h>
#include <botan/internal/timer.h>
namespace Botan { 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 size_t
pbkdf2(MessageAuthenticationCode& prf, pbkdf2(MessageAuthenticationCode& prf,
uint8_t out[], uint8_t out[],
size_t out_len, size_t out_len,
const std::string& passphrase, const std::string& password,
const uint8_t salt[], size_t salt_len, const uint8_t salt[], size_t salt_len,
size_t iterations, size_t iterations,
std::chrono::milliseconds msec) 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); clear_mem(out, out_len);
if(out_len == 0) if(out_len == 0)
return 0; return;
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()));
}
const size_t prf_sz = prf.output_length(); const size_t prf_sz = prf.output_length();
BOTAN_ASSERT_NOMSG(prf_sz > 0);
secure_vector<uint8_t> U(prf_sz); 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; uint32_t counter = 1;
while(out_len) while(out_len)
{ {
@@ -55,64 +130,93 @@ pbkdf2(MessageAuthenticationCode& prf,
xor_buf(out, U.data(), prf_output); xor_buf(out, U.data(), prf_output);
if(iterations == 0) for(size_t i = 1; i != iterations; ++i)
{ {
/* prf.update(U);
If no iterations set, run the first block to calibrate based prf.final(U.data());
on how long hashing takes on whatever machine we're running on. xor_buf(out, U.data(), prf_output);
*/
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);
}
} }
out_len -= prf_output; out_len -= prf_output;
out += prf_output; out += prf_output;
} }
return iterations;
} }
// PBKDF interface
size_t size_t
PKCS5_PBKDF2::pbkdf(uint8_t key[], size_t key_len, 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, const uint8_t salt[], size_t salt_len,
size_t iterations, size_t iterations,
std::chrono::milliseconds msec) const 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 * PBKDF2
* (C) 1999-2007,2012 Jack Lloyd * (C) 1999-2007,2012 Jack Lloyd
* (C) 2018 Ribose Inc
* *
* Botan is released under the Simplified BSD License (see license.txt) * Botan is released under the Simplified BSD License (see license.txt)
*/ */
@@ -9,6 +10,7 @@
#define BOTAN_PBKDF2_H_ #define BOTAN_PBKDF2_H_
#include <botan/pbkdf.h> #include <botan/pbkdf.h>
#include <botan/pwdhash.h>
#include <botan/mac.h> #include <botan/mac.h>
namespace Botan { namespace Botan {
@@ -22,20 +24,76 @@ BOTAN_PUBLIC_API(2,0) size_t pbkdf2(MessageAuthenticationCode& prf,
std::chrono::milliseconds msec); 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 class BOTAN_PUBLIC_API(2,0) PKCS5_PBKDF2 final : public PBKDF
{ {
public: public:
std::string name() const override std::string name() const override;
{
return "PBKDF2(" + m_mac->name() + ")";
}
PBKDF* clone() const override PBKDF* clone() const override;
{
return new PKCS5_PBKDF2(m_mac->clone());
}
size_t pbkdf(uint8_t output_buf[], size_t output_len, size_t pbkdf(uint8_t output_buf[], size_t output_len,
const std::string& passphrase, 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 defined(BOTAN_HAS_EMSA_PKCS1)
if(req.algo_name() == "EMSA_PKCS1" || if(req.algo_name() == "EMSA_PKCS1" ||
req.algo_name() == "EMSA-PKCS1-v1_5" || req.algo_name() == "PKCS1v15" ||
req.algo_name() == "EMSA3") req.algo_name() == "EMSA-PKCS1-v1_5" ||
req.algo_name() == "EMSA3")
{ {
if(req.arg_count() == 2 && req.arg(0) == "Raw") if(req.arg_count() == 2 && req.arg(0) == "Raw")
{ {
@@ -80,25 +81,45 @@ EMSA* get_emsa(const std::string& algo_spec)
#endif #endif
#if defined(BOTAN_HAS_EMSA_PSSR) #if defined(BOTAN_HAS_EMSA_PSSR)
if(req.algo_name() == "PSSR" || if(req.algo_name() == "PSS_Raw" ||
req.algo_name() == "EMSA-PSS" ||
req.algo_name() == "PSS-MGF1" ||
req.algo_name() == "EMSA4" ||
req.algo_name() == "PSSR_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))) if(auto h = HashFunction::create(req.arg(0)))
{ {
const size_t salt_size = req.arg_as_integer(2, h->output_length()); if(req.arg_count() == 3)
{
if(req.algo_name() == "PSSR_Raw") const size_t salt_size = req.arg_as_integer(2, 0);
return new PSSR_Raw(h.release(), salt_size); return new PSSR_Raw(h.release(), salt_size);
}
else 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); 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, bool pss_verify(HashFunction& hash,
const secure_vector<uint8_t>& const_coded, const secure_vector<uint8_t>& pss_repr,
const secure_vector<uint8_t>& raw, const secure_vector<uint8_t>& message_hash,
size_t key_bits) size_t key_bits,
size_t* out_salt_size)
{ {
const size_t HASH_SIZE = hash.output_length(); const size_t HASH_SIZE = hash.output_length();
const size_t KEY_BYTES = (key_bits + 7) / 8; 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) if(key_bits < 8*HASH_SIZE + 9)
return false; return false;
if(raw.size() != HASH_SIZE) if(message_hash.size() != HASH_SIZE)
return false; return false;
if(const_coded.size() > KEY_BYTES || const_coded.size() <= 1) if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
return false; return false;
if(const_coded[const_coded.size()-1] != 0xBC) if(pss_repr[pss_repr.size()-1] != 0xBC)
return false; return false;
secure_vector<uint8_t> coded = const_coded; secure_vector<uint8_t> coded = pss_repr;
if(coded.size() < KEY_BYTES) if(coded.size() < KEY_BYTES)
{ {
secure_vector<uint8_t> temp(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) for(size_t j = 0; j != 8; ++j)
hash.update(0); hash.update(0);
hash.update(raw); hash.update(message_hash);
hash.update(&DB[salt_offset], salt_size); 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) : 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) : 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, size_t output_bits,
RandomNumberGenerator& rng) 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); 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, const secure_vector<uint8_t>& raw,
size_t key_bits) 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 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, 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(SEQUENCE)
.start_cons(ASN1_Tag(0), CONTEXT_SPECIFIC).encode(hash_id).end_cons() .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(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 .start_cons(ASN1_Tag(3), CONTEXT_SPECIFIC).encode(size_t(1)).end_cons() // trailer field
.end_cons(); .end_cons();
@@ -201,12 +222,16 @@ AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
} }
PSSR_Raw::PSSR_Raw(HashFunction* h) : 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) : 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, size_t output_bits,
RandomNumberGenerator& rng) 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); 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, const secure_vector<uint8_t>& raw,
size_t key_bits) 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 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); 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; std::string name() const override;
@@ -51,7 +51,8 @@ class BOTAN_PUBLIC_API(2,0) PSSR final : public EMSA
size_t key_bits) override; size_t key_bits) override;
std::unique_ptr<HashFunction> m_hash; 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); 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; std::string name() const override;
private: private:
@@ -90,8 +91,9 @@ class BOTAN_PUBLIC_API(2,3) PSSR_Raw final : public EMSA
size_t key_bits) override; size_t key_bits) override;
std::unique_ptr<HashFunction> m_hash; std::unique_ptr<HashFunction> m_hash;
size_t m_SALT_SIZE;
secure_vector<uint8_t> m_msg; 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 PK_PADDING -> 20131128
</defines> </defines>
load_on auto
<requires> <requires>
asn1 asn1
rng rng

View File

@@ -17,13 +17,14 @@ void mgf1_mask(HashFunction& hash,
{ {
uint32_t counter = 0; uint32_t counter = 0;
secure_vector<uint8_t> buffer(hash.output_length());
while(out_len) while(out_len)
{ {
hash.update(in, in_len); hash.update(in, in_len);
hash.update_be(counter); 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); xor_buf(out, buffer.data(), xored);
out += xored; out += xored;
out_len -= 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)); }) [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; secure_vector<uint8_t> raw_agree(const uint8_t w[], size_t w_len) override;
private: private:
const BigInt& m_p; 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 p_bits() const { return m_p_bits; }
size_t q_bits() const { return m_q_bits; } size_t q_bits() const { return m_q_bits; }
size_t p_bytes() const { return (m_p_bits + 7) / 8; } 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; } size_t estimated_strength() const { return m_estimated_strength; }
@@ -448,6 +449,12 @@ size_t DL_Group::q_bits() const
return data().q_bits(); 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 size_t DL_Group::estimated_strength() const
{ {
return data().estimated_strength(); return data().estimated_strength();

View File

@@ -268,6 +268,13 @@ class BOTAN_PUBLIC_API(2,0) DL_Group final
*/ */
size_t q_bits() const; 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 * 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); 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, secure_vector<uint8_t> raw_sign(const uint8_t msg[], size_t msg_len,
RandomNumberGenerator& rng) override; 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; } bool with_recovery() const override { return false; }

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